Our example extended Step 1: SSL Version Selection and Certificate Preparation

101 needs to copy the data from the fourth parameter to the first. This method is viable for applications that need to decrypt keys during normal operation in which constant user prompting is a nuisance. An unlimited number of PEM-encoded items can be stored in a file, but only one DER item may be stored in a file. Also, different types of PEM items may be stored within a single file. As a result, if the private key is kept in PEM encoding, it can be appended to the certificate chain file, and the same filename can be used for the calls to SSL_CTX_use_certificate_chain_file and SSL_CTX_use_PrivateKey_file . This trick is used in Example 5-5 . PEM and DER encodings are discussed in Chapter 8 . At this stage, we will limit our discussion to the process of providing certificate information to the peer, rather than discussing the processes of validation. The validation problem will be discussed in Step 2.

5.1.2.3 Our example extended

Using the same example applications that weve already provided, lets modify them with what weve learned about making SSL connections. Keep in mind that this example is not yet secure. It does not validate anything about the peer to which it connects; it merely provides the authentication information. The new version of our client in client1.c is shown in Example 5-5 . The bold lines are those that we have added or changed. Example 5-5. client1.c 1 include common.h 2 3 define CERTFILE client.pem 4 SSL_CTX setup_client_ctxvoid 5 { 6 SSL_CTX ctx; 7 8 ctx = SSL_CTX_newSSLv23_method; 9 if SSL_CTX_use_certificate_chain_filectx, CERTFILE = 1 10 int_errorError loading certificate from file; 11 if SSL_CTX_use_PrivateKey_filectx, CERTFILE, SSL_FILETYPE_PEM = 1 12 int_errorError loading private key from file; 13 return ctx; 14 } 15 16 int do_client_loopSSL ssl 17 { 18 int err, nwritten; 19 char buf[80]; 20 21 for ;; 22 { 23 if fgetsbuf, sizeofbuf, stdin 24 break; 25 for nwritten = 0; nwritten sizeofbuf; nwritten += err 26 { 27 err = SSL_writessl, buf + nwritten, strlenbuf - nwritten; 28 if err = 0 102 29 return 0; 30 } 31 } 32 return 1; 33 } 34 35 int mainint argc, char argv[] 36 { 37 BIO conn; 38 SSL ssl; 39 SSL_CTX ctx; 40 41 init_OpenSSL; 42 seed_prng; 43 44 ctx = setup_client_ctx; 45 46 conn = BIO_new_connectSERVER : PORT; 47 if conn 48 int_errorError creating connection BIO; 49 50 if BIO_do_connectconn = 0 51 int_errorError connecting to remote machine; 52 53 if ssl = SSL_newctx 54 int_errorError creating an SSL context; 55 SSL_set_biossl, conn, conn; 56 if SSL_connectssl = 0 57 int_errorError connecting SSL object; 58 59 fprintfstderr, SSL Connection opened\n; 60 if do_client_loopssl 61 SSL_shutdownssl; 62 else 63 SSL_clearssl; 64 fprintfstderr, SSL Connection closed\n; 65 66 SSL_freessl; 67 SSL_CTX_freectx; 68 return 0; 69 } In this example, we make a call to the function seed_prng . As its name suggests, this function seeds the OpenSSL PRNG. Its implementation is left out; see Chapter 4 for details on an appropriate implementation. It is very important to maintaining the security of SSL for the PRNG to be properly seeded, so this function should never be left out in real-world applications. The function setup_client_ctx performs the actions as discussed earlier to provide certificate data to the server properly. In this setup process, we leave out any calls to SSL_CTX_set_default_passwd_cb since the default OpenSSL passphrase callback is acceptable for our purposes. The only other point of interest is the error checking performed. This example prints errors and exits if anything goes wrong; a more robust error handling technique was left out for clarity. The sidebar contains more information about the contents of the file client.pem . Generating the Files Needed by the Examples Our example programs refer to several filenames that contain PEM-encoded certificates 103 and keys. In this sidebar, well describe the process of creating each of them. There are two certificates used, the files server.pem and client.pem. In addition, we have a trusted root certificate in the file root.pem. As the example develops, we will also require two other files that will contain DH parameters dh512.pem and dh1024.pem. All of the files were generated using the command-line tool described in Chapter 2 . Before moving into the details of the commands themselves, we should first describe our certificate hierarchy. As weve stated, there is just one trusted certificate: the root CAs. This certificate is self-signed, as are all root CA certificates. This root CA represents the CA for a company. The qualifications for peer certificate validation for both our example client and server will be simply to verify that the other has been signed by the root CA. To demonstrate how a chain can grow and still be verifiable, we will create a server CA. This CA will be signed by the root CA and it, in turn, will be used to sign all server identity certificates. The client certificates, on the other hand, will be signed directly by the root CA. Nothing prevents us from making the hierarchy arbitrarily complex, but weve left just one intermediate CA to demonstrate how to do it. Creating more intermediates would follow the same pattern, as well see. The first command shown in each example below generates a certificate signing request. In creating the request, the command-line utility will prompt the user for the contents of the data fields that will be put in the request. The values we typed in are printed when the last command in each example runs. The values that arent seen are those of the subjectAltName field. We embed the server and client fully qualified domain name FQDN in the respective certificates commonName field, and also in the dNSName field of the subjectAltName . The latter is done by changing the configuration file to include subjectAltName = DNS:FQDN under the certificate extensions section the usr_cert section; the configuration file is the default aside from this change. To create the root CA: openssl req -newkey rsa:1024 -sha1 -keyout rootkey.pem -out rootreq.pem openssl x509 -req -in rootreq.pem -sha1 -extfile myopenssl.cnf \ -extensions v3_ca -signkey rootkey.pem -out rootcert.pem cat rootcert.pem rootkey.pem root.pem openssl x509 -subject -issuer -noout -in root.pem subject= C=USST=VAL=FairfaxO=Zork.orgCN=Root CA issuer= C=USST=VAL=FairfaxO=Zork.orgCN=Root CA To create the server CA and sign it with the root CA: openssl req -newkey rsa:1024 -sha1 -keyout serverCAkey.pem - out \ serverCAreq.pem openssl x509 -req -in serverCAreq.pem -sha1 -extfile \ myopenssl.cnf -extensions v3_ca -CA root.pem -CAkey root.pem \ -CAcreateserial -out serverCAcert.pem cat serverCAcert.pem serverCAkey.pem rootcert.pem serverCA.pem openssl x509 -subject -issuer -noout -in serverCA.pem subject= C=USST=VAL=FairfaxO=Zork.orgOU=Server DivisionCN=Server CA issuer= C=USST=VAL=FairfaxO=Zork.orgCN=Root CA 104 To create the servers certificate and sign it with the Server CA: openssl req -newkey rsa:1024 -sha1 -keyout serverkey.pem - out \ serverreq.pem openssl x509 -req -in serverreq.pem -sha1 -extfile myopenssl.cnf \ -extensions usr_cert -CA serverCA.pem -CAkey serverCA.pem \ -CAcreateserial -out servercert.pem cat servercert.pem serverkey.pem serverCAcert.pem rootcert.pem \ server.pem openssl x509 -subject -issuer -noout -in server.pem subject= C=USST=VAL=FairfaxO=Zork.orgCN=splat.zork.org issuer= C=USST=VAL=FairfaxO=Zork.orgOU=Server DivisionCN=Server CA To create the client certificate and sign it with the Root CA openssl req -newkey rsa:1024 -sha1 -keyout clientkey.pem - out \ clientreq.pem openssl x509 -req -in clientreq.pem -sha1 -extfile myopenssl.cnf \ -extensions usr_cert -CA root.pem -CAkey root.pem \ -CAcreateserial -out clientcert.pem cat clientcert.pem clientkey.pem rootcert.pem client.pem openssl x509 -subject -issuer -noout -in client.pem subject= C=USST=VAL=FairfaxO=Zork.orgCN=shell.zork.org issuer= C=USST=VAL=FairfaxO=Zork.orgCN=Root CA To create dh512.pem and dh1024.pem: openssl dhparam -check -text -5 512 -out dh512.pem openssl dhparam -check -text -5 1024 -out dh1024.pem Lines 54-58 create the SSL object and connect it. There are some functions used here that we have not yet discussed. The call to SSL_new creates our SSL object and copies the settings weve already placed in the SSL_CTX to the newly created object. At this point, the SSL object is still in a generic state. In other words, it could play the role of the server or the client in an SSL handshake. Another factor left unspecified is the path of communications for the SSL object. Since SSL objects are flexible in the sense that they can perform SSL functions on top of many different types of IO methods, we must specify a BIO for our object to use. Line 56 does this through a call to SSL_set_bio . This function is passed our connection BIO twice since SSL objects are robust enough to operate on two one-way IO types instead of requiring a single full-duplex IO method. Basically, we must specify the BIO to use for writing separately from the BIO used for reading. In this case, they are the same object, since sockets allow two-way communication. The last unfamiliar function used here is SSL_connect . This function causes the SSL object to initiate the protocol using the underlying IO. In other words, it begins the SSL handshake with the application on the other end of the underlying BIO . This function will return an error for problems such as incompatible protocol versions. 105 The do_client_loop function is almost identical to that of our non-SSL client. Weve simply changed the parameter to an SSL object instead of a BIO , and the BIO_write becomes an SSL_write . In addition, weve added a return value to this function. If no errors occur, we can call SSL_shutdown to stop the SSL connection; otherwise, we call SSL_clear . This is done to force OpenSSL to remove any session with errors from the session cache. We will look at session caching in more detail later in this chapter, but for now, it is worth noting that session caching is effectively disabled in the examples weve provided so far. The last point to make about this example is that we removed the call to BIO_free . This is done because SSL_free automatically frees the SSL objects underlying BIO s for us. Example 5-6 has the contents of server1.c, the file containing the implementation of our SSL- enabled server. Again, it isnt yet secure since it validates nothing about the peer; it simply provides its certificate information to the client. Example 5-6. server1.c 1 include common.h 2 3 define CERTFILE server.pem 4 SSL_CTX setup_server_ctxvoid 5 { 6 SSL_CTX ctx; 7 8 ctx = SSL_CTX_newSSLv23_method; 9 if SSL_CTX_use_certificate_chain_filectx, CERTFILE = 1 10 int_errorError loading certificate from file; 11 if SSL_CTX_use_PrivateKey_filectx, CERTFILE, SSL_FILETYPE_PEM = 1 12 int_errorError loading private key from file; 13 return ctx; 14 } 15 16 int do_server_loopSSL ssl 17 { 18 int err, nread; 19 char buf[80]; 20 21 do 22 { 23 for nread = 0; nread sizeofbuf; nread += err 24 { 25 err = SSL_readssl, buf + nread, sizeofbuf - nread; 26 if err = 0 27 break; 28 } 29 fwritebuf, 1, nread, stdout; 30 } 31 while err 0; 32 return SSL_get_shutdownssl SSL_RECEIVED_SHUTDOWN ? 1 : 0; 33 } 34 35 void THREAD_CC server_threadvoid arg 36 { 37 SSL ssl = SSL arg; 38 39 ifndef WIN32 106 40 pthread_detachpthread_self; 41 endif 42 if SSL_acceptssl = 0 43 int_errorError accepting SSL connection; 44 fprintfstderr, SSL Connection opened\n; 45 if do_server_loopssl 46 SSL_shutdownssl; 47 else 48 SSL_clearssl; 49 fprintfstderr, SSL Connection closed\n; 50 SSL_freessl; 51 52 ERR_remove_state0; 53 54 ifdef WIN32 55 _endthread; 56 endif 57 } 58 59 int mainint argc, char argv[] 60 { 61 BIO acc, client; 62 SSL ssl; 63 SSL_CTX ctx; 64 THREAD_TYPE tid; 65 66 init_OpenSSL; 67 seed_prng; 68 69 ctx = setup_server_ctx; 70 71 acc = BIO_new_acceptPORT; 72 if acc 73 int_errorError creating server socket; 74 75 if BIO_do_acceptacc = 0 76 int_errorError binding server socket; 77 78 for ;; 79 { 80 if BIO_do_acceptacc = 0 81 int_errorError accepting connection; 82 83 client = BIO_popacc; 84 if ssl = SSL_newctx 85 int_errorError creating SSL context; 86 87 SSL_set_biossl, client, client; 88 THREAD_CREATEtid, server_thread, ssl; 89 } 90 91 SSL_CTX_freectx; 92 BIO_freeacc; 93 return 0; 94 } After looking at the new client program, the modifications to the server should be clear. Since this is the server side of the SSL negotiation, a different function call is made: SSL_accept . The SSL_accept function initiates communication on the underlying IO layer to perform the SSL handshake. 107 In the do_server_loop function, we use a call to SSL_get_shutdown to check into the error status of the SSL object. This essentially allows us to differentiate normal client terminations from actual errors. If the SSL_RECEIVED_SHUTDOWN flag is set, we know the session hasnt had an error and its safe to cache. In other words, we can call SSL_shutdown rather than simply clear the connection. The remainder of the modifications to the server program parallel those made to the client. In summary, weve taken our applications and built them to the point of creating the objects necessary for SSL connections. Each application does provide its certificate data to the peers to which it connects, but they do not verify the certificates they receive. We will build further in the next step and learn how to validate peer certificates.

5.1.3 Step 2: Peer Authentication