Enable SSL for managed socket on windows mobile

I recently had to implement an application on windows mobile that would talk to a service via an SSL socket. This wasn’t just doing https requests so HttpWebRequest was not an option. And unfortunately the compact framework doesn’t include the SslStream class (which would have made my life easier).

I found windows mobile sockets support SSL through winsock so I decided to explore this route. Since my application was mostly managed it took a little interop dancing but I finally got it to work. What I came up with is a helper class that can take an existing socket and will enable SSL on it. For example:


var socket = new Socket(ipaddr, SocketType.Stream, ProtocolType.IP);

using (var sslHelper = new SslHelper(socket, host))



     //at this point the SSL handshake has occurred and you can

    //send and receive normally



Below is the code for this class. This is not meant to be production ready but can serve as an illustration on how to hook things up. In my case this was used as part of a proof of concept prototype.

It took me some time to figure out how all the pieces work together since the documentation is a little scattered but hopefully if you have to do something similar it can save you some time.

Another option might be to use SSPI, although I haven’t looked into that yet.


using System;

using System.Diagnostics;

using System.Net.Sockets;

using System.Runtime.InteropServices;

using System.Security.Cryptography;

using System.Security.Cryptography.X509Certificates;

using System.Text;

using System.Globalization;


namespace SslTest


    class SslHelper : IDisposable


        private const ushort SO_SECURE = 0x2001;

        private const ushort SO_SEC_SSL = 0x2004;

        private const int _SO_SSL_FLAGS = 0x02;

        private const int _SO_SSL_VALIDATE_CERT_HOOK = 0x08;

        private const int SO_SSL_FAMILY = 0x00730000;

        private const long _SO_SSL = ((2L << 27) | SO_SSL_FAMILY);

        private const uint IOC_IN = 0x80000000;


        private const long SO_SSL_SET_FLAGS = (IOC_IN | _SO_SSL | _SO_SSL_FLAGS);


        private const int SSL_CERT_X59            = 1;

        private const int SSL_ERR_OKAY            = 0;

        private const int SSL_ERR_FAILED          = 2;

        private const int SSL_ERR_BAD_LEN         = 3;

        private const int SSL_ERR_BAD_TYPE        = 4;

        private const int SSL_ERR_BAD_DATA        = 5;

        private const int SSL_ERR_NO_CERT         = 6;

        private const int SSL_ERR_BAD_SIG         = 7;

        private const int SSL_ERR_CERT_EXPIRED    = 8;

        private const int SSL_ERR_CERT_REVOKED    = 9;

        private const int SSL_ERR_CERT_UNKNOWN    = 10;

        private const int SSL_ERR_SIGNATURE       = 11;

        private const int SSL_CERT_FLAG_ISSUER_UNKNOWN = 0x0001;



        public delegate int SSLVALIDATECERTFUNC(uint dwType, IntPtr pvArg, uint dwChainLen, IntPtr pCertChain, uint dwFlags);       

        private IntPtr ptrHost;

        private IntPtr hookFunc;


        public SslHelper(Socket socket, string host)


            //The managed SocketOptionName enum doesn't have SO_SECURE so here we cast the integer value

            socket.SetSocketOption(SocketOptionLevel.Socket, (SocketOptionName)SO_SECURE, SO_SEC_SSL);


            //We need to pass a function pointer and a pointer to a string containing the host

            //to unmanaged code

            hookFunc = Marshal.GetFunctionPointerForDelegate(new SSLVALIDATECERTFUNC(ValidateCert));


            //Allocate the buffer for the string

            ptrHost = Marshal.AllocHGlobal(host.Length + 1);

            WriteASCIIString(ptrHost, host);


            //Now put both pointers into a byte[]

            var inBuffer = new byte[8];

            var hookFuncBytes = BitConverter.GetBytes(hookFunc.ToInt32());

            var hostPtrBytes = BitConverter.GetBytes(ptrHost.ToInt32());

            Array.Copy(hookFuncBytes, inBuffer, hookFuncBytes.Length);

            Array.Copy(hostPtrBytes, 0, inBuffer, hookFuncBytes.Length, hostPtrBytes.Length);




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




        private static void WriteASCIIString(IntPtr basePtr, string s)


            byte[] bytes = Encoding.ASCII.GetBytes(s);

            for (int i = 0; i < bytes.Length; i++)

                Marshal.WriteByte(basePtr, i, bytes[i]);


            //null terminate the string

            Marshal.WriteByte(basePtr, bytes.Length, 0);



        #region IDisposable Members







        public void Dispose()






        private void ReleaseHostPointer()


            if (ptrHost != IntPtr.Zero)



                ptrHost = IntPtr.Zero;






        private int ValidateCert(uint dwType, IntPtr pvArg, uint dwChainLen, IntPtr pCertChain, uint dwFlags)


            //According to http://msdn.microsoft.com/en-us/library/ms940451.aspx:


            //- dwChainLen is always 1

            //- Windows CE performs the cert chain validation

            //- pvArg is the context data we passed into the SO_SSL_SET_VALIDATE_CERT_HOOK call so in our

            //- case is the host name


            //So here we are responsible for validating the dates on the certificate and the CN



            if (dwType != SSL_CERT_X59)

                return SSL_ERR_BAD_TYPE;


            //When in debug mode let self-signed certificates through ...

#if !DEBUG

            if ((dwFlags & SSL_CERT_FLAG_ISSUER_UNKNOWN) != 0)

                return SSL_ERR_CERT_UNKNOWN;



            Debug.Assert(dwChainLen == 1);


            //Note about the note: an unmanaged long is 32 bits, unlike a managed long which is 64. I was missing

            //this fact when I wrote the comment. So the docs are accurate.

            //NOTE: The documentation says pCertChain is a pointer to a LPBLOB struct:


            // {ulong size, byte* data}


            //in reality the size is a 32 bit integer (not 64).

            int certSize = Marshal.ReadInt32(pCertChain);

            IntPtr pData = Marshal.ReadIntPtr(new IntPtr(pCertChain.ToInt32() + sizeof(int)));


            byte[] certData = new byte[certSize];


            for (int i = 0; i < certSize; i++)

                certData[i] = Marshal.ReadByte(pData, (int)i);


            X509Certificate2 cert;



                cert = new X509Certificate2(certData);


            catch (ArgumentException) { return SSL_ERR_BAD_DATA; }

            catch (CryptographicException) { return SSL_ERR_BAD_DATA; }


            //Validate the expiration date

            if (DateTime.Now > DateTime.Parse(cert.GetExpirationDateString(), CultureInfo.CurrentCulture))

                return SSL_ERR_CERT_EXPIRED;


            //Validate the effective date

            if (DateTime.Now < DateTime.Parse(cert.GetEffectiveDateString(), CultureInfo.CurrentCulture))

                return SSL_ERR_FAILED;


            string certName = cert.GetName();



            //Validate the CN

            string host = ReadAnsiString(pvArg);

            if (!certName.Contains("CN=" + host))

                return SSL_ERR_FAILED;


            return SSL_ERR_OKAY;



        private static string ReadAnsiString(IntPtr pvArg)


            byte[] buffer = new byte[1024];

            int j = 0;



                buffer[j] = Marshal.ReadByte(pvArg, j);


            } while (buffer[j - 1] != 0);

            string host = Encoding.ASCII.GetString(buffer, 0, j - 1);

            return host;




Comments (20)
  1. John says:

    Hi, is this class able to work with TLS?

  2. Carlos [MSR] says:

    Yes. The code currently lets winsock select the protocol. To use a specific protocol, you need to follow the steps described in:


    Although from managed code you would call socket.IOControl instead of WSAIoctl.

  3. Kuki says:

    Hello. Very interesting article. But I have problem with running it. When I use mySocket.Connect(myEndpoint) application crash with message “A problem has occurred with myTestApp.exe” This is I think from WinSock.dll.

    I think it is something with calling Validate function. It is not even fired. It looks like ptr is invalid? Is it possible?

  4. Jamal says:

    Kuki, you are write. In CFW 2.0 this code is not working at all, however in CFW 3.5 it does work. Connection is establishing validating callback fired, however comes another problem: error 10036. The receiving part working without problems. I am getting the error only during sending. During about each third sending operation. Blocking property does not help. Blocking sending and receiving by SyncLock does not help either. Has somebody any clue?  

  5. jereesh says:

    Hi ,

    Will this approach work in craeting a socket enabled for SSL in windows server environment(2008)

  6. Carlos [MSR] says:

    Creating an SSL enabled socket on windows server is much easier because you have the full .NET framework at our disposal (as opposed to the compact framework on windows mobile). Look at the SslStream class in System.Net.Security.

  7. Martin says:

    Hi, thanks for the article, very interesting.

    Reading data is fine, but I have a problem where sending data is unreliable, often it will produce an exception when calling write on the networkStream “Unable to write data to the transport connection.” with the inner exception “A blocking operation is currently executing”.

    We haven’t been able to find a solution to this. Also, it didn’t work at all on .NET CF 2, which doesn’t matter to me but may be some sort of clue as to the problem.

    Any ideas?


  8. Carlos [MSR] says:

    Hello Martin,

    I haven’t tried this but it seems like you need to put your socket in non-blocking mode using socket.IOControl. You may also want to look into IOControlCode.AsyncIO if you are doing things asynchronously.

    See: http://msdn.microsoft.com/en-us/library/system.net.sockets.iocontrolcode.aspx


  9. Andreas says:


    thanks for the article – unfortunately i run into the same problem as Martin (“A blocking operation is currently executing”) – so has anyone found a solution/workaround to the problem? I tried to use IOControlCode.AsyncIO but i always got a SocketException saying “An invalid argument was supplied” 😉

    Best regards,


  10. Kuki says:

    I haven’t tested this but I think that you should do following to be able sending.

    Make sure that you are not SENDING and RECEIVIN in the same time. Thant means receive data olny after successfull send. The best way (I think) is to use lock(onstaticobjec){ receive or send function call}.

    Because Windows CE doesn’t have native support for DUPLEX sockets.

    Even if you use C++ for socket you will not be able to send and receive at the same time.

  11. Matthias Vance says:

    I am hoping you can explain a bit more on how to implement this for listening sockets.

    I really don’t want to use the SSLStream class, since that affects performance (I want to use "raw" sockets).

    Kind regards,

    Matthias Vance

  12. Matthias Vance says:

    Thank you for the interesting article! (I forgot to add this to my other comment)

  13. Daniel Ray says:


    I have tried this implementation and it seems to be working just fine as long as there is low network traffic.

    Part of my application is sending data over ssl sockets (it basicly sends message and receive response). This messages are being sent every second, sometimes faster and on this device there is also a webserver. Problem usually rises when the user tries to load the web page from this device. Almost all the time application crashes down with error that looks like this:

    Exception 'Raised Exception' (-1): Thread-Id=0430002e(pth=81bec8cc), Proc-Id=041b0022(pprc=816f751c) 'CAT12CE.exe', VM-active=041b0022(pprc=816f751c) 'CAT12CE.exe'

    PC=4005d180(coredll.dll+0x0004d180) RA=8007d4c8(kernel.dll+0x000064c8) SP=00def81c, BVA=00def8c8

    Exception 'Raised Exception' (-1): Thread-Id=0430002e(pth=81bec8cc), Proc-Id=041b0022(pprc=816f751c) 'CAT12CE.exe', VM-active=041b0022(pprc=816f751c) 'CAT12CE.exe'

    PC=40020260(coredll.dll+0x00010260) RA=8007d4c8(kernel.dll+0x000064c8) SP=00def228, BVA=00000000

    Any idea?


    Daniel Ray

  14. C.A.T. says:

    Hi, is this code useful for a secure FTP??? Im receiving the SocketException with ErrorCode 10022.

    Kind Regards

  15. C.A.T. says:

    Hi, is this code useful for a secure FTP??? Im receiving the SocketException with ErrorCode 10022 when I try to connect with Socket.Connect method.

    Kind Regards

  16. Jilani says:

    the above helper class does not supports for desktop version. can any one give the suggestion/solution for SslHelper class for desktop version.it throws exception ie " An unknown, invalid, or unsupported option or level was specified in a getsockopt or setsockopt call "  

  17. Bala says:

    How to send client certificate using ssl helper for windows mobile?

  18. How to send client certificate using sslhelper for windows mobile?

  19. Yes Mr. Bala M, I am also expecting help on the same issue.If you get any help on this, please feel free to send me the same.

  20. Himanshu says:

    Any Idea how can I select Cipher Suites/algorithm in .NET CF or C++ ? I want to select AES 256 cipher algorithm for my Secure Socket.

Comments are closed.

Skip to main content