2

I'm teaching a class where I'd like to show students how open a socket in C++ and read both http: and https: webpages under both Linux and Windows. The Linux version version was a breeze with OpenSSL. But under Windows using Microsoft's WSA socket library, I've only been able to read non-ssl pages. I cannot figure out how to get their WSASetSocketSecurity() function to work.

With the WSASetSocketSecurity call in the following code fragment commented out, I'm able to read http: (port 80) pages. I'm able to connect() to https: (port 443) hosts but attempts to send an HTML GET request and then recv() the page fail as expected with either nothing returned or a 400 bad request page from some servers because I haven't negotiated encryption.

Uncommenting the WSASetSocketSecurity call to guarantee encryption, the connect call always fails with WSAGetLastError = 10060 (Connection timed out) on both http: and https: pages.

Calling WSASetSocketSecurity but specifying allow insecure connections allows me to read http: pages but fails with https: pages in the same way as if WSASetSocketSecurity had not been called at all.

Fundamentally, I'm not able to turn on encryption and then connect and I don't know why.

I have tried experiments replacing the socket, connect and other calls with WSAxxx() versions, imagining there might be distinction similar to the way you have to do an SSL_connect call after the connect in Linux but that makes no difference. The only thing I can think of that I have not yet tried is authenticating the host using WSASetSocketPeerTargetName(), but it doesn't seem to me I should need to do that if all I want is an SSL link.

What am I missing here? Has anyone made this work?

   // Initialize the socket library.
   // wVersionRequested = 2.2 (current latest)

   WSADATA wsaData;
   int wsaStartupResult = WSAStartup( MAKEWORD( 2, 2 ), &wsaData );
   assert( wsaStartupResult == 0 );

   // Get the host address.

   ADDRINFOA *addressInfo;
   int addrInfoResult = getaddrinfo( url.Host, url.Service,
         nullptr, &addressInfo );
   assert( addrInfoResult == 0 );

   sockaddr *socketAddress = addressInfo->ai_addr;
   size_t socketAddressLength = addressInfo->ai_addrlen;
   PrintAddress( socketAddress, socketAddressLength );

   // Create a TCP/IP socket.

   SOCKET s = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
   assert( s != INVALID_SOCKET );

   // Turn on SSL.

   SOCKET_SECURITY_SETTINGS security =
      {
      SOCKET_SECURITY_PROTOCOL_DEFAULT,
      SOCKET_SETTINGS_GUARANTEE_ENCRYPTION
      // SOCKET_SETTINGS_ALLOW_INSECURE
      };
/*
   int setSecurityResult = WSASetSocketSecurity( s,
         &security, sizeof( security ), nullptr, nullptr );
   assert( setSecurityResult == 0 );
*/

   // Connect to the host.

   int connectResult = connect( s, socketAddress, socketAddressLength );

   if ( connectResult != 0 )
      cerr << "Connect failed, WSAGetLastError = " << WSAGetLastError( ) << endl;
   assert( connectResult == 0 );

   // Send a GET message for the desired page.

   string getMessage = "GET ";
   getMessage += url.CompleteUrl;
   getMessage += " HTTP/1.1\r\nHost: ";
   getMessage += url.Host;
   getMessage += "\r\nConnection: close\r\n\r\n";

   cout << getMessage << endl;
   send( s, getMessage.c_str( ), getMessage.length( ), 0 );

   // Read from the socket until there's no more data.

   HANDLE Stdout = GetStdHandle( STD_OUTPUT_HANDLE );
   char buffer[ 10240 ];
   int bytes;
   DWORD length;

   while ( ( bytes = recv( s, buffer, sizeof( buffer ), 0 ) ) > 0 )
      WriteFile( Stdout, buffer, bytes, &length, nullptr );

   freeaddrinfo( addressInfo );
   closesocket( s );
   WSACleanup( );          
Nicole Hamilton
  • 284
  • 1
  • 15
  • 1
    My advice would be to install and use OpenSSL for Windows, just like you do for Linux. Microsoft's implementation is called schannel, but quite frankly it's rather a pain to use, and the documentation could use some serious help as well. If you insist on getting into the gory details, there's an [article (with code) on CodeProject that shows both a client and a server](https://www.codeproject.com/Articles/1000189/A-Working-TCP-Client-and-Server-With-SSL). Quite a bit beyond what will fit in an answer here though. – Jerry Coffin Feb 17 '18 at 16:26
  • @JerryCoffin Thank you, Jerry, that was very helpful. I'm genuinely surprised and appalled that the Microsoft hasn't provided a simple way to get an SSL similar to what OpenSSL provides. – Nicole Hamilton Feb 18 '18 at 14:08

1 Answers1

4

Your assumption that socket security turns on SSL / TLS is wrong. It is actually for enforcing use of IPsec protocol. See Winsock Secure Socket Extensions. If you need SSL/TLS then you should use Secure Channel (built-in Windows SSL/TLS library), OpenSSL or other dedicated library working on top of sockets.

user7860670
  • 35,849
  • 4
  • 58
  • 84
  • Okay, I know I'm doing something wrong. I've tried SOCKET_SECURITY_PROTOCOL_IPSEC without success. What exactly am I doing wrong and what change is needed to fix it? – Nicole Hamilton Feb 17 '18 at 16:16
  • Okay, but that's just a link to a general information page about Microsoft's secure channel. It's not even a link to function call or set of calls I would need to use. Yes, I understand I could use OpenSSL; that's what I did with my LinuxVersion. But I'm trying to make this work on Windows using native Windows functions just to demonstrate how the two OS's compare. – Nicole Hamilton Feb 17 '18 at 16:25
  • @NicoleHamilton That MSDN section links to [CryptoAPI reference](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380256(v=vs.85).aspx). There are some examples of using it, see [Window C/C++ Crypto API Examples and tips](https://stackoverflow.com/questions/4796590/window-c-c-crypto-api-examples-and-tips). – user7860670 Feb 17 '18 at 16:45
  • SChannel relies on SSPI. See [Using SSPI](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380535(v=vs.85).aspx) and [Creating a Secure Connection Using Schannel](https://msdn.microsoft.com/en-us/library/windows/desktop/aa374782(v=vs.85).aspx) on MSDN. – Remy Lebeau Feb 17 '18 at 18:19
  • Okay, I now understand your point. Thank you. That was very helpful. – Nicole Hamilton Feb 18 '18 at 14:06