Re: sslio as a STARTTLS wrapper (was Re: sslio error description incomplete/wrong)

Scott Gifford <[email protected]>
Newsgroups gmane.comp.misc.pape.general
Message-ID <[email protected]>
Charlie Brady <[email protected]> writes:

> On Thu, 6 Jan 2005, Scott Gifford wrote:
>
>> Charlie Brady <[email protected]> writes:

[...]

> It's my impression that SIGCONT is the only signal we can send
> across uid boundaries (presuming that both smtpd and sslio have
> changed uid), and then only if the processes are in the same session
> (as I think they would be here). I can't think of how we'd send two
> different messages ("take over", "die") with that one signal.

Ah, you're right, a quick test confirms that.  Using SIGCONT seems
quite kludgey, though I can't think of any other reason than
aesthetics not to use it.  Well, maybe portability.

> But a single byte message over a pipe should do.

Yeah, that's probably the best way to go.  It seems a little annoying
to do it this way, but that's OK.  The file descriptor number should
probably be passed in via an environment variable, so we don't get
tied to a particular number being available or conflict with other
similar programs.

>> One concern that one of stunnel's authors (Brian Hatch?) had was that
>> starting up a brand new SSL-handling program wasted processing power,
>> since a lot of SSL's work is initialization.  If we used a
>> tcpserver/tcpsvd replacement that natively understood SSL, it would
>> help with that concern.  The operation would essentially be:
>> 
>>     /* Running as root */
>>     initialize_ssl();
>>     while(accept())
>>       fork()
>>         child:
>>           fork()
>>             parent:
>>               chroot("/nothing");
>>               setgid("nobody");
>>               setuid("nobody");
>>               be_ssl_tunnel();
>>             child:
>>               setgid(g_option);
>>               setuid(u_option);
>>               exec(rest_of_args);
>> 
>> The child would use IPC to ask the parent to begin SSL, as in your
>> proposal.
>
> More as in your proposal than mine, since this would require fd passing.

No; the parent and child processes would share the socket file
descriptor, as they would with sslio.

[...]

>> Another option I've considered is a standalone SSL daemon.
>
> There is William Baxter's ucspi-ssl, but that comes without any license, 
> doesn't support privilege separation.

Right; it would be equivalent to adding privilege separation to
ucspi-ssl, adding tcpserver functionality to sslio, or adding SSL
functionality to ipsvd.  All of these programs have two of the things
that would be ideal.  :)

>> An application that wanted TLS would connect to this daemon via a UNIX
>> socket and send the network file descriptors, then receive back the
>> decrypted ends of an SSL connection:
>> 
>>   smtpd:
>>     case STARTTLS:
>>       s = socket(...)
>>       connect(s, AF_UNIX, getenv(TLS_SOCKET),...)
>>       sendfd(s,STDIN_FILENO);
>>       sendfd(s,STDOUT_FILENO);
>>       newfd = recvfd(s);
>>       dup2(newfd, STDIN_FILENO);
>>       newfd = recvfd(s);
>>       dup2(newfd, STDIN_FILENO);
>> 
>> This lets a single SSL daemon handle multiple services, which saves
>> resources.  It's also the coolest of the solutions I've considered.
>
> Fd sending is unfamiliar territory for me (and most software it seems). 
> The UNIX socket would be protected by file access permissions, right?

Right.  It's straightforward to do; AFAIK, everybody copies and pastes
the code from a Stevens book.  :)

>> A third option I've used for a similar problem is to start up the TLS
>> proxy without executing the SMTP server.  As soon as we receive any
>> command besides STARTTLS, we exec the SMTP server and send the first
>> command on FD 3 then close it; the SMTP server reads from FD 3 until
>> EOF, then switches to STDIN.  If we receive STARTTLS, we start up an
>> encryption tunnel and then exec the SMTP server with the decrypted
>> ends of this.  This only works if STARTTLS is the first command, but
>> in practice it always is.  The advantage is that you don't have an SSL
>> server sitting around waiting for a signal; it just exits if it
>> doesn't see STARTTLS right away.
>
> This approach would mean that you need to have a TLS proxy which includes 
> code which is a subset of any of the protocols which you want it to deal 
> with (SMTP, IMAP, POP, etc). That's what stunnel currently does, and it's 
> complexity I want to avoid.

The big advantage of it is that by teaching the SMTP server one thing,
you can add multiple layers of wrappers on top if it.  I've used this
to add both TLS and SMTP AUTH support to qmail-smtpd in a
straightforward way.  You could avoid teaching stunnel about all of
these protocols by implementing small shim program to implement
protocols, which interacted with stunnel.

>> My favorite of these is the tcpserver replacement that forks off an
>> SSL handler, which is activated by a signal.  This has a very clean
>> interface, and the persistent daemon design may be more efficient with
>> SSL handling than a new copy of sslio every time (though I'll admit I
>> don't exactly understand all of SSL's performance characteristics).
>
> Nor is performance necessarily a big issue in most deployments.

That's my experience, though I've mostly done this for small
installations.

Some quick measurements show that stunnel under tcpserver is about 50%
slower than tcpserver+stunnel (user+system for 100 connections is 2.96
vs. 1.935); it's likely that other arrangements will have similar
overhead.  So it's not gigantic, but it's certainly non-negligible.
On a system with many thousand clients it would certainly make a big
difference.

> I can understand you wanting to avoid the SSL startup costs with each
> connection, but I don't have a picture of how signals and privilege 
> separation would work here.

PrivSep would work the same as for sslio; it would just be a matter of
where it's happening.  Signaling wouldn't be any different from with
sslio, either; kill() would work, or a single character on a pipe, or
anything else.

> I've also been trying to avoid mixing SSL code with existing stable
> well-tested applications. Avoiding any change to tcpserver/tcpsvd would be
> preferable (and in the case of tcpserver, required, if being able to
> distribute binaries matters).

I agree this is preferable, but there's a trade-off with performance.
If performance is no better, the advantage over stunnel is minimal
IMHO.

> One more feature which is missing in all these proxy configurations is any 
> mechanism to provide feedback to the mail daemon as to what SSL parameters 
> was negotiated. In the fork/exec model which sslio has, this is 
> necessary/deliberate, since the fork/exec occurs before any data is read 
> from the network, so, e.g., an environment variable can't be set up for 
> the the mail daemon describing the SSL negotiation outcome. This prevents, 
> for instance, the mail daemon from adding a descriptive Received header. 

With your pipe/socket idea, it would be straightforward to send this
information back down the pipe, although it would require a more
complex protocol.  SSL may allow renegotiation of parameters, which
would be more challenging.

Another idea is to have the server exit with a particular exit code
when SSL was requested; the wrapper would detect this, enable SSL,
then re-exec the server with the connection, and any SSL settings in
environment variables.  This is also very simple to implement, and
enforces the requirement for SMTP that all state is reset after
STARTTLS.  I'm not sure whether other protocols require this.

>> I could probably find some time to help with a project like that,
>> or at least to test it since the coding should be fairly minimal.
>
> Thanks. Have you used Gerrit's ipsvd or Bruce's mailfront?

I've used mailfront; I've never needed the features of ipsvd, so
haven't used it.

I'm still in a bit of a brainstorming mood on this, so excuse me if
this message is a bit scattered.  :)

----ScottG.

P.S.  I can't believe we go through all this crap just to run SMTP+SSL
on port 25 instead of 465.  :)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.