SSL is a complicated binary protocol. Unless you are a crypto expert, you shouldn't send raw SSL traffic directly. Thankfully, several commercial and open source libraries exist to make it easier to program SSL clients and servers.

OpenSSL

OpenSSL is the most popular open source implementation of SSL and TLS. The OpenSSL Project is a collaborative volunteer effort to develop a robust, commercial-grade, full-featured toolkit implementing the SSL and TLS protocols, as well as a full-strength, general-purpose cryptography library. You can get information about OpenSSL, and download the software, from http://www.openssl.org.

You might also hear of SSLeay (pronounced S-S-L-e-a-y). OpenSSL is the successor to the SSLeay library, and it has a very similar interface. SSLeay was originally developed by Eric A. Young (the "eay" of SSLeay).

A Simple HTTPS Client

In this section, we'll use the OpenSSL package to write an extremely primitive HTTPS client. This client establishes an SSL connection with a server, prints out some identification information from the site server, sends an HTTP GET request across the secure channel, receives an HTTP response, and prints the response.

The C program shown below is an OpenSSL implementation of the trivial HTTPS client. To keep the program simple, error-handling and certificate-processing logic has not been included.

Because error handling has been removed from this example program, you should use it only for explanatory value. The software will crash or otherwise misbehave in normal error conditions.

/**********************************************************************
 * https_client.c --- very simple HTTPS client with no error checking
 * usage: https_client servername
 **********************************************************************/
#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h> 
void main(int argc, char **argv)
{
 SSL *ssl;
 SSL_CTX *ctx;
 SSL_METHOD *client_method;
 X509 *server_cert;
 int sd,err;
 char *str,*hostname,outbuf[4096],inbuf[4096],host_header[512];
 struct hostent *host_entry;
 struct sockaddr_in server_socket_address;
 struct in_addr ip;
 /*========================================*/
 /* (1) initialize SSL library */
 /*========================================*/
 SSLeay_add_ssl_algorithms( );
 client_method = SSLv2_client_method( );
 SSL_load_error_strings( );
 ctx = SSL_CTX_new(client_method);
 printf("(1) SSL context initialized\n\n");
 /*=============================================*/
 /* (2) convert server hostname into IP address */
 /*=============================================*/
 hostname = argv[1];
 host_entry = gethostbyname(hostname);
 bcopy(host_entry->h_addr, &(ip.s_addr), host_entry->h_length);
 printf("(2) '%s' has IP address '%s'\n\n", hostname, inet_ntoa(ip));
 /*=================================================*/
 /* (3) open a TCP connection to port 443 on server */ 
 /*=================================================*/
 sd = socket (AF_INET, SOCK_STREAM, 0);
 memset(&server_socket_address, '\0', sizeof(server_socket_address));
 server_socket_address.sin_family = AF_INET;
 server_socket_address.sin_port = htons(443);
 memcpy(&(server_socket_address.sin_addr.s_addr),
 host_entry->h_addr, host_entry->h_length);
 
 err = connect(sd, (struct sockaddr*) &server_socket_address,
 sizeof(server_socket_address));
 if (err < 0) { perror("can't connect to server port"); exit(1); }
 printf("(3) TCP connection open to host '%s', port %d\n\n",
 hostname, server_socket_address.sin_port);
 /*========================================================*/
 /* (4) initiate the SSL handshake over the TCP connection */
 /*========================================================*/
 ssl = SSL_new(ctx); /* create SSL stack endpoint */
 SSL_set_fd(ssl, sd); /* attach SSL stack to socket */
 err = SSL_connect(ssl); /* initiate SSL handshake */
 printf("(4) SSL endpoint created & handshake completed\n\n");
 
 /*============================================*/
 /* (5) print out the negotiated cipher chosen */
 /*============================================*/
 
 printf("(5) SSL connected with cipher: %s\n\n", SSL_get_cipher(ssl));
 
 /*========================================*/
 /* (6) print out the server's certificate */
 /*========================================*/
 server_cert = SSL_get_peer_certificate(ssl);
 printf("(6) server's certificate was received:\n\n");
 
 str = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
 printf(" subject: %s\n", str);
 str = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
 printf(" issuer: %s\n\n", str);
 /* certificate verification would happen here */
 X509_free(server_cert);
 /*********************************************************/
 /* (7) handshake complete --- send HTTP request over SSL */
 /*********************************************************/
 
 sprintf(host_header,"Host: %s:443\r\n",hostname);
 strcpy(outbuf,"GET / HTTP/1.0\r\n");
 strcat(outbuf,host_header);
 strcat(outbuf,"Connection: close\r\n");
 strcat(outbuf,"\r\n");
 err = SSL_write(ssl, outbuf, strlen(outbuf));
 shutdown (sd, 1); /* send EOF to server */ 
 
 printf("(7) sent HTTP request over encrypted channel:\n\n%s\n",outbuf);
 /**************************************************/
 /* (8) read back HTTP response from the SSL stack */
 /**************************************************/
 
 err = SSL_read(ssl, inbuf, sizeof(inbuf) - 1);
 inbuf[err] = '\0';
 printf ("(8) got back %d bytes of HTTP response:\n\n%s\n",err,inbuf);
 /************************************************/
 /* (9) all done, so close connection & clean up */
 /************************************************/
 SSL_shutdown(ssl);
 close (sd);
 SSL_free (ssl);
 SSL_CTX_free (ctx);
 printf("(9) all done, cleaned up and closed connection\n\n");
}

This example compiles and runs on Sun Solaris, but it is illustrative of how SSL programs work on many OS platforms. This entire program, including all the encryption and key and certificate management, fits in a three-page C program, thanks to the powerful features provided by OpenSSL.

Let's walk through the program section by section:

·         The top of the program includes support files needed to support TCP networking and SSL.

·         Section 1 creates the local context that keeps track of the handshake parameters and other state about the SSL connection, by calling SSL_CTX_new.

·         Section 2 converts the input hostname (provided as a command-line argument) to an IP address, using the Unix gethostbyname function. Other platforms may have other ways to provide this facility.

·         Section 3 opens a TCP connection to port 443 on the server by creating a local socket, setting up the remote address information, and connecting to the remote server.

·         Once the TCP connection is established, we attach the SSL layer to the TCP connection using SSL_new and SSL_set_fd and perform the SSL handshake with the server by calling SSL_connect. When section 4 is done, we have a functioning SSL channel established, with ciphers chosen and certificates exchanged.

·         Section 5 prints out the value of the chosen bulk-encryption cipher.

·         Section 6 prints out some of the information contained in the X.509 certificate sent back from the server, including information about the certificate holder and the organization that issued the certificate. The OpenSSL library doesn't do anything special with the information in the server certificate. A real SSL application, such as a web browser, would do some sanity checks on the certificate to make sure it is signed properly and came from the right host. We discussed what browsers do with server certificates in Section 14.7.6.

·         At this point, our SSL connection is ready to use for secure data transfer. In section 7, we send the simple HTTP request "GET / HTTP/1.0" over the SSL channel using SSL_write, then close the outbound half of the connection.

·         In section 8, we read the response back from the connection using SSL_read, and print it on the screen. Because the SSL layer takes care of all the encryption and decryption, we can just write and read normal HTTP commands.

·         Finally, we clean up in section 9.

Refer to http://www.openssl.org for more information about the OpenSSL libraries.

Executing Our Simple OpenSSL Client

The following shows the output of our simple HTTP client when pointed at a secure server. In this case, we pointed the client at the home page of the Morgan Stanley Online brokerage. Online trading companies make extensive use of HTTPS.

% https_client clients1.online.msdw.com
(1) SSL context initialized
(2) 'clients1.online.msdw.com' has IP address '63.151.15.11'
(3) TCP connection open to host 'clients1.online.msdw.com', port 443
(4) SSL endpoint created & handshake completed
(5) SSL connected with cipher: DES-CBC3-MD5
(6) server's certificate was received:
 subject: /C=US/ST=Utah/L=Salt Lake City/O=Morgan Stanley/OU=Online/CN=
 clients1.online.msdw.com
 issuer: /C=US/O=RSA Data Security, Inc./OU=Secure Server Certification
 Authority
(7) sent HTTP request over encrypted channel:
GET / HTTP/1.0
Host: clients1.online.msdw.com:443
Connection: close
 
(8) got back 615 bytes of HTTP response:
 
HTTP/1.1 302 Found
Date: Sat, 09 Mar 2002 09:43:42 GMT
Server: Stronghold/3.0 Apache/1.3.14 RedHat/3013c (Unix) mod_ssl/2.7.1 OpenSSL/0.9.6
Location: https://clients.online.msdw.com/cgi-bin/ICenter/home
Connection: close
Content-Type: text/html; charset=iso-8859-1
 
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>302 Found</TITLE>
</HEAD><BODY>
<H1>Found</H1>
The document has moved <A HREF="https://clients.online.msdw.com/cgi-bin/ICenter/home">here</A>.<P>
<HR>
<ADDRESS>Stronghold/3.0 Apache/1.3.14 RedHat/3013c Server at clients1.online.msdw.com Port 443</ADDRESS>
</BODY></HTML>
 
(9) all done, cleaned up and closed connection

As soon as the first four sections are completed, the client has an open SSL connection. It can then inquire about the state of the connection and chosen parameters and can examine server certificates.

In this example, the client and server negotiated the DES-CBC3-MD5 bulk-encryption cipher. You also can see that the server site certificate belongs to the organization "Morgan Stanley" in "Salt Lake City, Utah, USA". The certificate was granted by RSA Data Security, and the hostname is "clients1.online.msdw.com," which matches our request.

Once the SSL channel is established and the client feels comfortable about the site certificate, it sends its HTTP request over the secure channel. In our example, the client sends a simple "GET / HTTP/1.0" HTTP request and receives back a 302 Redirect response, requesting that the user fetch a different URL.

 


Hypertext Transfer Protocol (HTTP)