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
The security of an SSL-enabled program is compromised by failure to verify peer certificates properly. In this step, well look into the various API calls that deal with trusted certificates,
certificate chain verification, CRL usage, and post-connection verification.
5.1.3.1 Background
Certificate verification can often be confusing, so well discuss the theory before delving into the details. As we already know, a certificate is a set of credentials that has been cryptographically
signed by a CA. Each certificate, including a CA certificate, contains a public key with a private key counterpart held in secret by the certificate owner. Moving forward, the process of signing a
certificate involves using the private key of a CA to sign the public key in the new certificate. Thus, it should be clear that the process of verification will involve using the public key in a CA
certificate to verify the signature on a certificate.
Aside from using a CA to create an entity certificate, a CA may also sign a certificate and give it permissions, via X.509v3 extensions, to act as a CA itself. Generally, this procedure allows for a
CA to permit another certificate to act as a CA for a specialized purpose. Through this mechanism, we become aware of certificate hierarchies, i.e., a certificate tree. Understanding this, we can see
that a single entity certificate may have a list of signing certificates leading up to the original, self- signed root certificate. This list of certificates, each signed by the next, is called a certificate chain.
Jumping back to a simple example of a root CA signing a single entity certificate, any party may verify the entity certificate by checking the signature on it, presuming it trusts the root CA. The
process of validating an entity certificate is that simple. Extending this to a certificate chain, we must validate each subsequent signature in the list until we reach a trusted CA certificate or until
we reach the end of the list. If we hit a CA we trust and the signatures are all valid, our entity certificate is verified; if we find an invalid signature or reach the end of the chain without reaching
a trusted certificate, the entity certificate is not verified.
5.1.3.2 Incorporating trusted certificates
As we previously discussed, verifying a certificates authenticity requires that the verifying agent have a list of CAs that it trusts. Therefore, we must provide our application with such a list in
order for it to verify the peer. We will start our discussion of peer verification by first concentrating on accomplishing this task.
Loading trusted CA certificates into our application is manifested as additional setup to the
SSL_CTX
object. The function
SSL_CTX_load_verify_locations
performs this task. This function will load certificates from files, directories, or both.
int SSL_CTX_load_verify_locationsSSL_CTX ctx, const char CAfile,
108
const char CApath;
ctx The SSL context object that trusted CA certificates will be loaded into.
CAfile The name of a file containing CA certificates in PEM format. More than one CA
certificate may be present in the file. CApath
The name of a directory containing CA certificates. Each file in the directory must contain only a single CA certificate, and the files must be named by the subject names
hash and an extension of .0.
We can call
SSL_CTX_load_verify_locations
with either the second or the third arguments specified as
NULL
, but not both. The behavior of this function is to perform the loading for the non-
NULL
arguments. An important difference between file and directory storage is the time when the certificates get loaded. With a flat file, the file is parsed and certificates loaded
during the call to
SSL_CTX_load_verify_locations
. However, with a directory, certificates are read only when needed, i.e., during the verification phase that occurs during the SSL
handshake. OpenSSL also has default CA certificate locations. When building the library, these paths are
hardcoded into the library based on the parameters that are used to build it. In general, there is an OpenSSL directory commonly usrlocalopenssl on Unix systems. The default certificate file is
named cert.pem, and it lives in this OpenSSL directory. Likewise, the default certificate directory is named certs, and it too lives in the OpenSSL directory. These default locations provide a
convenient place to store system-wide CA certificates that all of the OpenSSL-based applications running on the machine require. Using the default files, we will not need to keep separate copies
of common certificates for each application. The function
SSL_CTX_set_default_verify_paths
loads these default locations into our
SSL_CTX
object. For calls to this function, the same rules for determining when the CA certificates actually get loaded apply as with a call to
SSL_CTX_load_verify_locations
. When we load a certificate location into an
SSL_CTX
object, we are making the statement that we trust those certificates. It is important to
understand that if our application runs on a multiuser system, any user with permissions to write to the certificate locations that we load can
subvert the security of our application. This is especially important when electing to load the default verify locations. For instance, if our
application loads these defaults, a user with the correct permissions could slip in a new CA certificate, thus connecting our application with peers
presenting certificates signed by this rogue CA certificate.
Using these two functions, we can load trusted CA certificates into our
SSL_CTX
. Even though they are loaded, the certificates are still not used to verify the peer. We will explore the details of
enabling this in the next section.
5.1.3.3 Certificate verification