views:

18

answers:

1

I have a simple SMTP client, to which I am attempting to add TLS support. I am unsure as to what occurs after the client issues the 'STARTTLS' command. Most sources (including the RFC itself) describe it as the negotiation of a TLS session, but this is not particularly clear.

How does one go about doing this? My client is written in Objective C and uses Cocoa's stream objects (a wrapper for sockets). Cocoa streams have the ability to designate TLS as the the socket security level system with NSStream's setProperty function.

It seems, however, that this must be done before the connection is opened. If this is the case, then is the client expected to disconnect after receiving code 220 from the server (in response to STARTTLS) and then reconnect while specifying TLS?

Or rather, is this just a limitation of NSStream? Do plain sockets re-negotiate TLS or SSL without being closed?

Furthermore, once STARTTLS has been issued and the subsequent negotiating completed, is any other encoding/decoding expected on the part of the client?

Apologies if these are simple questions. I've had difficulty finding proper examples.

Cheers!

A: 

After the client sends the STARTTLS command and the server replies with a success code, the client then has to initiate its SSL/TLS handshake at that time on the same socket. DO NOT disconnect the socket before initiating the SSL/TLS handshake. That will start a new SMTP session, and you will have to issue the STARTTLS command all over again.

Once the SSL/TLS handshake is succesfully completed, no additional work is needed, just send your remaining SMTP commands normally, and they will be encrypted back and forth. Some clients issue a new HELO/EHLO command after establishing TLS, in case the server's capabilities are different once in the encrypted mode.

Unfortunately, from what I can see, NSStream does not support initiating SSL/TLS after the stream is open. This is a limitation of NSStream, and is documented by Apple:

For SSL security, NSStream defines various security-level properties (for example, NSStreamSocketSecurityLevelSSLv2). You set these properties by sending setProperty:forKey: to the stream object using the key NSStreamSocketSecurityLevelKey, as in this sample message:

[iStream setProperty:NSStreamSocketSecurityLevelTLSv1 forKey:NSStreamSocketSecurityLevelKey];

You must set the property before you open the stream.

I do not know if this is possible in Objective C/Cocoa, but you might have to write your own stream class that you attach to your main SMTP stream. Then you could initiate SSL/TLS when you are ready to, and have it delegate to your main stream for its input/output. Or else find a third-party SMTP class that handles these details for you.

Remy Lebeau - TeamB
Thanks for your response.I did a little more investigation after posting the initial question and eventually came to the same conclusion.The solution was to write a simple objective-C wrapper for OpenSSL sockets and use that instead of NSStream.