Welcome to MSDN Blogs Sign in | Join | Help

Syndication

News

Add to Technorati Favorites
Deferred TLS/SSL handshakes on windows mobile

I recently received an email and blog comment from João Almeida, who was trying to use the SslHelper class to make a secure connection to an SMTP server and was having some trouble. After doing a little research I found this is a little different from doing an HTTPS connection. The SMTP protocol requires the connection to start in plain text and the TLS handshake to happen after the STARTTLS command is issued. Here’s how a typical secure SMTP session would start (bolded text is what the SMTP client needs to send, normal text are server responses):

 

>telnet smtp.live.com 587

220 BLU0-SMTP8.blu0.hotmail.com Microsoft ESMTP MAIL Service, Version: 6.0.3790.3959 ready at  Mon, 14 Sep 2009 16:44:33 -0700
EHLO
250-BLU0-SMTP8.blu0.hotmail.com Hello [131.107.0.75]
250-TURN
250-SIZE 35840000
250-ETRN
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-8bitmime
250-BINARYMIME
250-CHUNKING
250-VRFY
250-TLS
250-STARTTLS
250 OK
STARTTLS
220 2.0.0 SMTP server ready

Up to this point everything needs to be in plain text. But once the 220 status code is received the TLS handshake needs to be started.

So how does the SslHelper code need to change to accommodate this? We need to ask winsock to do a deferred handshake as follows (please refer to the full listing of SslHelper). First, we need to bring in a couple of constants from the mobile SDK:

private const int SSL_FLAG_DEFER_HANDSHAKE = 0x0008;

private const int _SO_SSL_PERFORM_HANDSHAKE = 0x0d;

private const long SO_SSL_PERFORM_HANDSHAKE = _SO_SSL | _SO_SSL_PERFORM_HANDSHAKE;

Next, we need to tell the socket that we want it to use a deferred handshake by calling socket.IOControl with the SSL_FLAG_DEFER_HANDSHAKE. We do this in the constructor after setting the ssl cert validation hook:

socket.IOControl((int)SO_SSL_SET_VALIDATE_CERT_HOOK, inBuffer, null);

if (deferHandshake)

    socket.IOControl((int)SO_SSL_SET_FLAGS, BitConverter.GetBytes(SSL_FLAG_DEFER_HANDSHAKE), null);

Finally, we need to add a method that will let us start the handshake when we need to:

        public void DoHandshake()

        {

            socket.IOControl((int)SO_SSL_PERFORM_HANDSHAKE, BitConverter.GetBytes(ptrHost.ToInt32()), null);

        }

With this in place, here’s a quick and dirty example of how to start a TLS session with an SMTP server:

string SmtpServer = "smtp.live.com";

int port = 587;

IPHostEntry IPhst = Dns.GetHostEntry(SmtpServer);

IPEndPoint endPt = new IPEndPoint(IPhst.AddressList[0], port);

Socket s = new Socket(endPt.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

using (SslHelper helper = new SslHelper(s, SmtpServer, true))

{

    string line = null;

    s.Connect(endPt);

    StreamReader sr = new StreamReader(new NetworkStream(s), Encoding.ASCII);                   

    s.Send(Encoding.ASCII.GetBytes("EHLO\r\n"));

    while ((line = sr.ReadLine()) != "250 OK") ;

    s.Send(Encoding.ASCII.GetBytes("STARTTLS\r\n"));

    while (!(line = sr.ReadLine()).StartsWith("220")) ;

    helper.DoHandshake();

    Debug.WriteLine("success");

}

Again, thanks to João for the question and for helping me validate the approach.

Published Tuesday, September 15, 2009 9:57 AM by carlosgjs

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: Deferred TLS/SSL handshakes on windows mobile @ Tuesday, October 06, 2009 5:34 AM

Hi ,

Thanks for posting this code.

I am trying to establish FTP - SSL connection.

I am able to create a socket ,but when I am trying to create a data socket I am having problems.

Like after I create a datasocket , the ftp server just not respond or throw any exception.

I hope the problem lies some where in creating datasocket -

Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);

           IPEndPoint ep = new IPEndPoint(Dns.GetHostEntry(remoteHost).AddressList[0], port);

           if (useSSL)

           {

               var sslHelp = new CommunicationsEngine.SSLHelper(s, remoteHost,false);

               try

               {

                   s.Connect(ep);

               }

               catch (Exception exp)

               {

                   cleanup();

                   throw new IOException("Couldn't Connect SSL Data Socket " + exp.Message);

               }

               if (s.Connected)

               {

                   readReply();

               }

               if (retValue != 220)

               {

                   cleanup();

                   throw new IOException(reply.Substring(4));

               }

can you please give me your comments?

Bindu

# re: Deferred TLS/SSL handshakes on windows mobile @ Tuesday, October 06, 2009 12:57 PM

Hello Bindu,

It is hard to say what could be going wrong. What does readReply do? Does the code hang in a particular line?

I have never tried an FTPS connection but reading a little bit about this protocol seems like there are two modes, implicit and explicit (search for FTPS on wikipedia). Which one are you trying to use?

Carlos

carlosgjs

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
Page view tracker