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