[ Team LiB ] |
10.7 Verifying an SSL Peer's Certificate10.7.1 ProblemYou are using OpenSSL to support SSL-enabled communication between a client and a server. You want to instruct OpenSSL to verify the certificate received from the peer. 10.7.2 SolutionEvery SSL connection has an SSL object, which in turn has an SSL_CTX object, and that object, in turn, has an X509_STORE object. OpenSSL uses the X509_STORE object as a container for any certificates and CRLs required to verify another certificate. OpenSSL creates an X509_STORE_CTX object and calls X509_verify_cert( ) for you, but not by default. OpenSSL's default behavior is to not verify peer certificates, which is the worst default behavior that any SSL implementation could possibly provide. By not verifying certificates in an SSL connection, the strength of the security provided by SSL is severely reduced, to the point where the two parties in the conversation might as well be using nothing more than a symmetric cipher with keys exchanged in the clear. Without verifying certificates, you will have security against passive eavesdroppers, but that is all. With a small amount of effort, anyone could hijack the TCP connection before the SSL session is established and act as a man-in-the-middle. 10.7.3 DiscussionTo have OpenSSL verify a peer's certificate, you must issue a call to SSL_CTX_set_verify( ). SSL_CTX_set_verify( ) accepts a bitmask of flags that tell OpenSSL how to deal with certificates. Depending on whether the SSL_CTX object is being used as a client or as a server, the meanings of the flags are somewhat different:
When the SSL_CTX object 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.
Using this knowledge of SSL_CTX_set_verify( ) and the code from Recipe 10.5, we'll build a new function, spc_create_sslctx( ), that will create an SSL_CTX object and initialize it with secure settings. In addition to calling SSL_CTX_set_verify( ), we'll disable the SSLv2 protocol, leaving only SSLv3 and TLSv1 enabled. We want to disable SSLv2 because it is well known to be insecure. It was the first publicly released version of the protocol and was not designed or adequately reviewed by security experts before its deployment. SSLv3 was designed and reviewed by security experts, and it corrects all of the known problems in SSLv2. Finally, we'll call SSL_CTX_set_cipher_list( ) to ensure that only secure ciphers will be used. Before we can build spc_create_sslctx( ), we need to extend and complete the implementation of the spc_x509store_t object introduced in Recipe 10.5. Some additional flags are necessary for spc_create_sslctx( ), so we'll define those first:
We will also need an additional set of functions to add certificate and key information into the context for presenting to a peer when it is requested. The information will be used by spc_create_sslctx( ) when creating an SSL_CTX object, but only if SPC_X509STORE_USE_CERTIFICATE is set in the spc_x509store_t's flags. void spc_x509store_setusecertfile(spc_x509store_t *spc_store, char *file) { if (spc_store->use_certfile) free(spc_store->use_certfile); spc_store->use_certfile = (file ? strdup(file) : 0); } void spc_x509store_addusecert(spc_x509store_t *spc_store, X509 *cert) { sk_X509_push(spc_store->certs, cert); } void spc_x509store_setusekeyfile(spc_x509store_t *spc_store, char *file) { if (spc_store->use_keyfile) free(spc_store->use_keyfile); spc_store->use_keyfile = (file ? strdup(file) : 0); } void spc_x509store_setusekey(spc_x509store_t *spc_store, EVP_PKEY *key) { if (spc_store->use_key) EVP_PKEY_free(key); spc_store->use_key = key; CRYPTO_add(&(key->references), 1, CRYPTO_LOCK_EVP_PKEY); } Both the certificates and the keys can be specified either as a file from which to load the information, or as preexisting OpenSSL objects of the appropriate type (X509 objects for certificates, and EVP_PKEY objects for keys). If a filename is specified, it will take precedence over a preexisting OpenSSL object. If a preexisting key object is used, it is the caller's responsibility to free it using EVP_PKEY_free( ) at any point after it is added into the spc_x509store_t object because it is reference counted, and spc_x509store_setusekey( ) increments its reference count. When specifying the certificates to be sent to a peer (whether the peer will be a server or a client), multiple certificates may be specified. The first certificate specified should always be the certificate belonging to your program. Any additional certificates should be certificates in the chain that may be needed to verify the validity of your own certificate. This is true whether the certificates are loaded from a file and specified via spc_x509store_setusecertfile( ), or are added to the spc_x509store_t one at a time using spc_x509store_addusecert( ). Note also that the certificates and the required private key may be contained within the same file. For both certificate and key files, PEM format should be used, because the alternative binary ASN.1 format (also known as DER) does not allow multiple objects to be present in the same file. At this point, spc_create_sslctx( ) has everything it needs. It takes a single argument—the spc_x509store_t object—to get its information from, and it returns a new SSL_CTX object that can be used to establish SSL-enabled connections. #include <openssl/ssl.h> #define SPC_X509STORE_USE_CERTIFICATE 0x04 #define SPC_X509STORE_SSL_VERIFY_NONE 0x10 #define SPC_X509STORE_SSL_VERIFY_PEER 0x20 #define SPC_X509STORE_SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x40 #define SPC_X509STORE_SSL_VERIFY_CLIENT_ONCE 0x80 #define SPC_X509STORE_SSL_VERIFY_MASK 0xF0 SSL_CTX *spc_create_sslctx(spc_x509store_t *spc_store) { int i, verify_flags = 0; SSL_CTX *ctx = 0; X509_STORE *store = 0; spc_x509verifycallback_t verify_callback; if (!(ctx = SSL_CTX_new(SSLv23_method( )))) goto error_exit; if (!(store = spc_create_x509store(spc_store))) goto error_exit; SSL_CTX_set_cert_store(ctx, store); store = 0; SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2); SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); if (!(verify_callback = spc_store->callback)) verify_callback = spc_verify_callback; if (!(spc_store->flags & SPC_X509STORE_SSL_VERIFY_MASK)) verify_flags = SSL_VERIFY_NONE; else { if (spc_store->flags & SPC_X509STORE_SSL_VERIFY_NONE) verify_flags |= SSL_VERIFY_NONE; if (spc_store->flags & SPC_X509STORE_SSL_VERIFY_PEER) verify_flags |= SSL_VERIFY_PEER; if (spc_store->flags & SPC_X509STORE_SSL_VERIFY_FAIL_IF_NO_PEER_CERT) verify_flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; if (spc_store->flags & SPC_X509STORE_SSL_VERIFY_CLIENT_ONCE) verify_flags |= SSL_VERIFY_CLIENT_ONCE; } SSL_CTX_set_verify(ctx, verify_flags, verify_callback); if (spc_store->flags & SPC_X509STORE_USE_CERTIFICATE) { if (spc_store->use_certfile) SSL_CTX_use_certificate_chain_file(ctx, spc_store->use_certfile); else { SSL_CTX_use_certificate(ctx, sk_X509_value(spc_store->use_certs, 0)); for (i = 1; i < sk_X509_num(spc_store->use_certs); i++) { SSL_CTX_add_extra_chain_cert(ctx, sk_X509_value(spc_store->use_certs, i)); } } if (spc_store->use_keyfile) { SSL_CTX_use_PrivateKey_file(ctx, spc_store->use_keyfile, SSL_FILETYPE_PEM); } else { if (spc_store->use_key) SSL_CTX_use_PrivateKey(ctx, spc_store->use_key); } } SSL_CTX_set_app_data(ctx, spc_store); return ctx; error_exit: if (store) X509_STORE_free(store); /* not ref counted */ if (ctx) SSL_CTX_free(ctx); /* ref counted */ return 0; } 10.7.4 See Also |
[ Team LiB ] |