Implementing renegotiations IO on SSL Connections

139 This function does not actually perform the new handshake when called; however, it sets a flag that causes a renegotiation request to be sent to the peer. The request is sent out on the next call to an IO function on the SSL connection. An important point to consider is that the peer has the option of not renegotiating the connection. If the peer chooses not to respond to the request and to continue transferring data instead, no renegotiation will occur; unless the requestor checks for negotiation success, it may not have happened. This is especially important when making applications that will connect with other non-OpenSSL SSL implementations. A renegotiation can also be done explicitly. In other words, we will send a request and not send or receive application data until the new handshake has completed successfully. While this will sometimes be the appropriate way to refresh session keys for long-term connections, it serves another important purpose. It allows us to upgrade client authentication from the server side. For instance, our example server above requires a valid client certificate to be presented in order for the initial connection to take place. This is overly restrictive since at connection time, we do not know the clients intentions. As an example, consider a simple protocol that allows clients to connect via SSL and send commands to the server. A subset of these commands will be reserved for administrators. Our goal is to allow anyone to connect to the server to run the general commands and allow only administrators to run reserved commands. If we require all users to present a certificate at connection time, we must issue a certificate to every possible client and special certificates to administrators. This can become cumbersome rather quickly. Alternatively, we can run two servers, one for normal users and another for administrators. This is also a suboptimal solution since it requires extra consumption of resources. We can use renegotiations to make our job simpler. First, we will allow anyone to connect without a certificate. When a client connects, it sends its command. If its a reserved command, we require a renegotiation with the more stringent requirements on the client in place. If the client renegotiates successfully, we can accept the command, or otherwise discard it. Thus, we need to issue certificates only to administrators. This option is clearly better than the previous two since it allows us to determine what the client is attempting before putting stronger authentication requirements in place.

5.2.3.1 Implementing renegotiations

As weve said before, to do a passive renegotiation i.e., one in which the handshake occurs during application IO we need to call only SSL_renegotiate . In general, applications can get away with having the handshake occur during application IO, but making sure that it did indeed happen is important. Unfortunately, this isnt easy to do with OpenSSL Version 0.9.6. In fact, many aspects of renegotiations dont work cleanly in this version. However, the forthcoming Version 0.9.7 promises to improve this considerably. These changes are described in the next section. With Version 0.9.6, we should always use explicit renegotiation since there is no way to determine if a renegotiation request was ignored by the peer. This is the same problem we find in renegotiating client credentials; we will focus on determining if a request was ignored, since it is far more common. Renegotiating for session key refreshment is a subset of this problem. Example 5-17 shows an incomplete code fragment to force a renegotiation from a server. Example 5-17. Code fragment to force a renegotiation from a server assume ssl is connected and error free up to here set_blockingssl; this is unnecessary if it is already blocking SSL_renegotiatessl; SSL_do_handshakessl; if ssl-state = SSL_ST_OK TE AM FL Y Team-Fly ® 140 int_errorFailed to send renegotiation request; ssl-state |= SSL_ST_ACCEPT; SSL_do_handshakessl; if ssl-state = SSL_ST_OK int_errorFailed to complete renegotiation; our renegotiation is complete This example uses some functions weve seen before. To avoid extra complication, we ensure the SSL object is blocking so we dont need to retry failed IO calls. The call to SSL_renegotiate sends out the request to the peer. The function SSL_do_handshake is a generic routine that calls the accept function for server objects or the connect function for client objects. This first call to SSL_do_handshake sends out our request and returns. After doing this, we need to check that the SSL connection hasnt received any errors. We do this by making sure its state is SSL_ST_OK . At this point, if we call the handshake function again, it will just return if the peer chose not to renegotiate. This occurs because the SSLTLS protocols allow requests to be ignored. Since we have a reason for renegotiating, and we need it to complete before continuing, we must manually set the SSL_ST_ACCEPT state of the server object. This will cause the subsequent call to SSL_do_handshake , which will force a handshake to occur before continuing. Obviously, this method of renegotiation isnt very clean because it requires us to set internal variables of the SSL object manually. Unfortunately, it is the only way to accomplish a forced renegotiation. This code fragment is not complete, though. Consider session caching, which allows a client to skip the handshake by resuming a previously created session. This can be extremely bad when our purpose is to collect stronger client credentials since the client has already obtained a valid session with weak credentials. When we attempt to renegotiate a connection from a server that does session caching, we must take extra precautions that the client doesnt simply present the previously negotiated session and bypass the handshake. To make this discrepancy between the sessions, we need to change the session ID context. Recall that the session ID contexts function is to discern sessions established with clients for different purposes. To change its value, we use the function SSL_set_session_id_context . It behaves exactly as the SSL_CTX version discussed above, except that it operates on SSL objects. The change to the session ID context must be made before the renegotiation is started. We havent discussed the minor detail of setting stronger requirements for verification of the client during renegotiation. To do this, we use the function SSL_set_verify and pass it our new verify flags. Example 5-18 shows the code fragment that must be built around the fragment shown in Example 5-17 in order for the renegotiation to be effective. This fragment is for a caching server that wishes to upgrade client authentication; if our server isnt caching, we can omit the calls to set the session ID context. Example 5-18. Code to cause forced renegotiation in order to request stronger client authentication and distinguish the sessions assume ctx is an SSL_CTX object that is setup to not have any verify options. int normal_user = 1; int admin_user = 2; SSL_CTX_set_session_id_contextctx, normal_user, sizeofint; perform rest of ctx setup, create an ssl object, and connect it normal SSL IO operations and application code go here if we want to upgrade client privilege, we enter the following code block SSL_set_verifyssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback; SSL_set_session_id_contextssl, admin_user, sizeofint; 141 code fragment from Example 5-18 goes here. the new session is made post_connection_checkssl, host; if everything is error-free, we have properly authenticated the client The code in Example 5-18 realizes the solution to the problem we laid out earlier for upgrading client authentication. By changing the session context ID to admin_user , we allow clients previously verified as admin users to resume connections, but no others. This is effective at keeping resumed sessions from being mistaken as privileged sessions. In addition, we set the verify options for the SSL object explicitly, forcing the renegotiation to demand a client certificate or fail. After renegotiation is complete, we call the post-connection check function. In some cases, we may want to tailor the post-connection function to meet application-specific needs.

5.2.3.2 Renegotiations in 0.9.7