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
Certificate verification entails checking the cryptographic signatures on a certificate to be sure an entity we trust has signed that certificate. It also involves checking the certificates
notBefore
109
and
notAfter
dates, trust settings, purpose, and revocation status. Verification of a certificate takes place during the SSL handshake during the call to
SSL_connect
or
SSL_accept
, depending on whether the SSL object is a client or a server.
Once weve properly loaded trusted certificates into the
SSL_CTX
object, OpenSSL has a built-in function to verify the peers certificate chain automatically. The routine used to verify the
certificate chain could be changed from the default via a call to
SSL_CTX_set_cert_verify_callback
, but under almost all circumstances, this is undesirable since the default routine for signature verification is amply complete and robust.
Instead, the developer can specify a different callback that filters the return status of the default verification and returns the new verification status. The function to perform this task is
SSL_CTX_set_verify
. Aside from assigning a filter verify callback, this functions primary purpose is to assign the type
of verification our
SSL_CTX
objects connections will perform. More accurately, we can use it to control how certificates and requests are handled during a handshake. The second argument to this
function is a set of flags that determine this. Four flags are defined with names that can be combined with a logical OR operation. Depending on whether the context is being used in client
mode or server mode, these flags can have different meanings.
SSL_VERIFY_NONE When the context is being used in server mode, no request for a certificate will be sent to
the client, and the client should not send a certificate. When the context is being used in client mode, any certificate received from the server will be verified, but failure will not
terminate the handshake. Do not combine this flag with any others; the others will take precedence over this one. This flag should only be used by itself.
SSL_VERIFY_PEER When the context is being used in server mode, a request for a certificate will be sent to
the client. The client may opt to ignore the request, but if a certificate is sent back, it will be verified. If the verification fails, the handshake will be terminated immediately.
When the context is being used in client mode, if the server sends a certificate, it will be verified. If the verification fails, the handshake will be terminated immediately. The only
time that a server would not send a certificate is when an anonymous cipher is in use. Anonymous ciphers are disabled by default. Any other flags combined with this one in
client mode are ignored.
SSL_VERIFY_FAIL_IF_NO_PEER_CERT If the context is not being used in server mode or if
SSL_VERIFY_PEER
is not set, this flag is ignored. Use of this flag will cause the handshake to terminate immediately if no
certificate is provided by the client. SSL_VERIFY_CLIENT_ONCE
If the context is not being used in server mode or if
SSL_VERIFY_PEER
is not set, this flag is ignored. Use of this flag will prevent the server from requesting a certificate from
the client in the case of a renegotiation. A certificate will still be requested during the initial handshake.
The third argument to
SSL_CTX_set_verify
is a pointer to the verification filter callback. Since the internal verification routine is called for each level of the peer certificate chain, our filter
TE AM
FL Y
Team-Fly
®
110
routine will be called just after each step. This functions first argument is nonzero if the verification succeeded, and zero otherwise. The second argument is an
X509_STORE_CTX
object. This type of object contains the information necessary to verify a certificate. The object holds the
current certificate being verified and the verification result. The return value from the function should be either zero or nonzero to indicate whether the certificate should be considered valid or
not.
As in most of the callbacks used with OpenSSL, there is a default supplied that simply returns the value of the first argument. When implementing our own version of this function, we need to
maintain this behavior. If we return nonzero when the first parameter is actually zero, an unverified client certificate will be accepted as a verified one. Likewise, the reverse would cause a
valid certificate to fail verification. At this point, it may seem as if there is no real purpose to implementing our own version, but this isnt accurate. The reason we should supply our own is so
that more detailed information about the results of verification can be obtained, especially when verification fails. For instance, if a peer presents an expired certificate and we do not implement a
verify callback to check status, then we find out only that the call to
SSL_connect
or
SSL_accept
failed because of handshake failure. Example 5-7
shows an implementation for this callback that we will use in our example applications. To use it in our examples, it should be
implemented in common.c and prototyped in common.h.
Example 5-7. A verify callback implemented in common.c and prototyped in common.h
int verify_callbackint ok, X509_STORE_CTX store {
char data[256]; if ok
{ X509 cert = X509_STORE_CTX_get_current_certstore;
int depth = X509_STORE_CTX_get_error_depthstore; int err = X509_STORE_CTX_get_errorstore;
fprintfstderr, -Error with certificate at depth: i\n, depth;
X509_NAME_onelineX509_get_issuer_namecert, data, 256; fprintfstderr, issuer = s\n, data;
X509_NAME_onelineX509_get_subject_namecert, data, 256; fprintfstderr, subject = s\n, data;
fprintfstderr, err i:s\n, err, X509_verify_cert_error_stringerr;
} return ok;
}
This callback employs several functions from the
X509
family of functions to report the detailed error information.
The call to
SSL_CTX_set_verify
is done before any
SSL
objects are created from the context. We should also make a call to
SSL_CTX_set_verify_depth
. This function sets the maximum allowable depth for peer certificates. In other words, it limits the number of certificates that we are
willing to verify in order to ensure the chain is trusted. For example, if the depth was set to four and six certificates are present in the chain to reach the trusted certificate, the verification would
fail because the required depth would be too great. For nearly all applications, the default depth of nine is more than high enough to ensure that the peer certificate will not fail due to too large of a
certificate chain. On the other hand, if we know that our application will be used only with peers
111
presenting certificates of some smaller chain length, it is a good idea to set the value to exclude certificates composed of longer chains from being verified successfully. Setting the depth to zero
allows chains of unlimited length to be used.
There is a known security vulnerability in
SSL_CTX_set_verify_depth
in versions of OpenSSL prior to 0.9.6. The problem stemmed from the fact that the internal verification routine
did not properly check extensions on peer certificate chains; it approved certificate chains that contained non-CA certificates as long as they led to
a trusted root CA. Thus, using any verification depth greater than one left the application susceptible to attack from anyone signed by the trusted
root CA. Since this problem has been fixed in newer versions of OpenSSL by checking the X509v3 fields regarding CA authorization, this
vulnerability should be of only academic interest.
5.1.3.4 Incorporating certificate revocation lists