Using Secure WinSock

WinSock 2.0 extends the Windows Socket interface to allow the underlying transport provider to expose security features that may be built into the provider. It is conceivable that a TCP/IP provider could use SSPI to encapsulate security functionality such that it can be invoked by a WinSock application. This will be very similar to how RPC encapsulates this functionality and all the application needs to do is to request it! Note that such a provider does not currently exist for Windows NT 4.0. Microsoft is implementing a WinSock 2.0 provider for SSL 3.0 which will be available soon. A general purpose SSPI-TCP/IP transport provider is not currently implemented, but Microsoft will make one available in a future release.

Using the TCP/IP and SSL security provider as an example, all that an application needs to do to use SSPI services is the following:

The following example is taken from the Microsoft Internet Security Schannel examples. The example below shows how to use SSL 3.0 and a TCP/IP provider from WinSock 2.0.


//
// Initialize the WinSock 2 subsystem.
//

err = WSAStartup(MAKEWORD(2,2), &WsaData);
if(err != 0)
{
 printf("**** Error initializing WinSock!\n");
 return;
}

//
// Choose a WinSock 2 provider that supports both TCP/IP and the
// chosen security scheme.
//
cProtocols = WSAEnumProtocols(NULL,
        NULL,
        &cbProtocolBuffer);
if(cProtocols == SOCKET_ERROR && WSAGetLastError() != WSAENOBUFS)
{
 printf("**** Error %d during WSAEnumProtocols\n", WSAGetLastError());
 return;
}

// Allocate memory
pProtocolBuffer = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cbProtocolBuffer);
if(pProtocolBuffer == NULL) return FALSE;

// Read array of WSAPROTOCOL_INFO structures.
cProtocols = WSAEnumProtocols(NULL,
        pProtocolBuffer,
        &cbProtocolBuffer);
if(cProtocols == SOCKET_ERROR)
{
 LocalFree(pProtocolBuffer);
 return;
}
// Search for SSL protocol
for(i = 0, fFound = FALSE ; i < cProtocols ; i++)
{
 if(pProtocolBuffer[i].iProtocol == IPPROTO_TCP &&
  pProtocolBuffer[i].iSecurityScheme == SECURITY_PROTOCOL_SSL)
 {
  *pProtocolInfo = pProtocolBuffer[i];
  fFound = TRUE;
  break;
 }
}
if(!fFound)
{
 LocalFree(pProtocolBuffer);
 return;
}

// Free memory
LocalFree(pProtocolBuffer);

Once we have selected the WinSock provider of choice, we can go ahead and create a socket and initialize security on it.


//
 // Create socket
 //

 Socket = WSASocket(FROM_PROTOCOL_INFO,  // address family
      FROM_PROTOCOL_INFO,  // type
      FROM_PROTOCOL_INFO,  // protocol
      pProtocolInfo,   // protocol info
      0,      // group
      0);      // flags
 if(Socket == INVALID_SOCKET)
 {
  printf("**** Error creating socket!\n");
  return FALSE;
 }
 else
 {
  *pSocket = Socket;
 }

 //
 // Set the socket's SSL flags.
 //

 {
  DWORD dwFlags;

  dwFlags = SSL_FLAG_ENABLE;

  err = WSAIoctl(Socket,
      SO_SSL_SET_FLAGS,
      (LPVOID)&dwFlags,
      sizeof(dwFlags),
      NULL,     // output buffer
      0,      // output buffer size
      NULL,     // # bytes returned
      NULL,     // overlapped structure
      NULL);     // completion routine
  if(err == SOCKET_ERROR)
  {
   printf("**** Error setting SSL flags!\n");
   return FALSE;
  }
 }

//
// Set the socket's SSL client parameters.
//

{
 SSLCLIENTOPTS SslClientOpts;
 DWORD cbBytesRead;

 // Read the default client parameters.
 err = WSAIoctl(Socket,     // socket
     SO_SSL_GET_CLIENT_OPTS, // dwIoControlCode
     NULL,     // lpvInBuffer
     0,      // cbInBuffer
     (LPVOID)&SslClientOpts, // lpvOutBuffer
     sizeof(SslClientOpts), // cbOutBuffer
     &cbBytesRead,   // lpcbBytesReturned
     NULL,     // lpOverlapped
     NULL);     // lpCompletionRoutine
 if(err == SOCKET_ERROR)
 {
  printf("**** Error reading default client options!\n");
  return FALSE;
 }

 // Set the session cache timeout period to 10 minutes. Leave
 // everything else at the default value.
 SslClientOpts.CacheTimeout = 600;

 // Set the client parameters.
 err = WSAIoctl(Socket,     // socket
     SO_SSL_SET_CLIENT_OPTS, // dwIoControlCode
     (LPVOID)&SslClientOpts, // lpvInBuffer
     sizeof(SslClientOpts), // cbInBuffer
     NULL,     // lpvOutBuffer
     0,      // cbOutBuffer
     NULL,     // lpcbBytesReturned
     NULL,     // lpOverlapped
     NULL);     // lpCompletionRoutine
 if(err == SOCKET_ERROR)
 {
  printf("**** Error setting client options!\n");
  return FALSE;
 }
}

//
// We could additionally set up authentication call back functions, etc.
// using WSAIoctl API, depending on what else may be involved in setting
// up a secure socket.
//

Note: The code above is for demonstration purposes only, no such WinSock provider is currently available from Microsoft.

Once the socket is set up, the application can use WSAConnect API to connect to the server and the underlying provider will use the socket security settings to authenticate the connection using an appropriate security package, and so forth. From then on, all the communication can occur transparent of any message signing and sealing that may be done by the provider via SSPI.