diff options
author | jiangtaoli2016 <jiangtao@google.com> | 2018-03-23 11:28:48 -0700 |
---|---|---|
committer | jiangtaoli2016 <jiangtao@google.com> | 2018-03-23 11:28:48 -0700 |
commit | 144f5559dabd2bd646acba1426647123d31c2323 (patch) | |
tree | 1418b4a63820a9d40d82a51a6522fc770c1a27ce /src/core/tsi | |
parent | 90af9346de2e4e6f0d45b130ce0de3d08d075c3f (diff) |
cache default SSL root cert store
Diffstat (limited to 'src/core/tsi')
-rw-r--r-- | src/core/tsi/ssl_transport_security.cc | 94 | ||||
-rw-r--r-- | src/core/tsi/ssl_transport_security.h | 40 |
2 files changed, 107 insertions, 27 deletions
diff --git a/src/core/tsi/ssl_transport_security.cc b/src/core/tsi/ssl_transport_security.cc index 0fc2926cf6..0ba6587678 100644 --- a/src/core/tsi/ssl_transport_security.cc +++ b/src/core/tsi/ssl_transport_security.cc @@ -71,6 +71,10 @@ extern "C" { /* --- Structure definitions. ---*/ +struct tsi_ssl_root_certs_store { + X509_STORE* store; +}; + struct tsi_ssl_handshaker_factory { const tsi_ssl_handshaker_factory_vtable* vtable; gpr_refcount refcount; @@ -553,21 +557,18 @@ static tsi_result ssl_ctx_use_private_key(SSL_CTX* context, const char* pem_key, /* Loads in-memory PEM verification certs into the SSL context and optionally returns the verification cert names (root_names can be NULL). */ -static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context, - const char* pem_roots, - size_t pem_roots_size, - STACK_OF(X509_NAME) * - *root_names) { +static tsi_result x509_store_load_certs(X509_STORE* cert_store, + const char* pem_roots, + size_t pem_roots_size, + STACK_OF(X509_NAME) * *root_names) { tsi_result result = TSI_OK; size_t num_roots = 0; X509* root = nullptr; X509_NAME* root_name = nullptr; BIO* pem; - X509_STORE* root_store; GPR_ASSERT(pem_roots_size <= INT_MAX); pem = BIO_new_mem_buf((void*)pem_roots, static_cast<int>(pem_roots_size)); - root_store = SSL_CTX_get_cert_store(context); - if (root_store == nullptr) return TSI_INVALID_ARGUMENT; + if (cert_store == nullptr) return TSI_INVALID_ARGUMENT; if (pem == nullptr) return TSI_OUT_OF_RESOURCES; if (root_names != nullptr) { *root_names = sk_X509_NAME_new_null(); @@ -595,7 +596,7 @@ static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context, sk_X509_NAME_push(*root_names, root_name); root_name = nullptr; } - if (!X509_STORE_add_cert(root_store, root)) { + if (!X509_STORE_add_cert(cert_store, root)) { gpr_log(GPR_ERROR, "Could not add root certificate to ssl context."); result = TSI_INTERNAL_ERROR; break; @@ -621,6 +622,16 @@ static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context, return result; } +static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context, + const char* pem_roots, + size_t pem_roots_size, + STACK_OF(X509_NAME) * + *root_name) { + X509_STORE* cert_store = SSL_CTX_get_cert_store(context); + return x509_store_load_certs(cert_store, pem_roots, pem_roots_size, + root_name); +} + /* Populates the SSL context with a private key and a cert chain, and sets the cipher list and the ephemeral ECDH key. */ static tsi_result populate_ssl_context( @@ -730,6 +741,43 @@ static int NullVerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) { return 1; } +/* --- tsi_ssl_root_certs_store methods implementation. ---*/ + +tsi_ssl_root_certs_store* tsi_ssl_root_certs_store_create( + const char* pem_roots) { + if (pem_roots == nullptr) { + gpr_log(GPR_ERROR, "The root certificates are empty."); + return nullptr; + } + tsi_ssl_root_certs_store* root_store = static_cast<tsi_ssl_root_certs_store*>( + gpr_zalloc(sizeof(tsi_ssl_root_certs_store))); + if (root_store == nullptr) { + gpr_log(GPR_ERROR, "Could not allocate buffer for ssl_root_certs_store."); + return nullptr; + } + root_store->store = X509_STORE_new(); + if (root_store->store == nullptr) { + gpr_log(GPR_ERROR, "Could not allocate buffer for X509_STORE."); + gpr_free(root_store); + return nullptr; + } + tsi_result result = x509_store_load_certs(root_store->store, pem_roots, + strlen(pem_roots), nullptr); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Could not load root certificates."); + X509_STORE_free(root_store->store); + gpr_free(root_store); + return nullptr; + } + return root_store; +} + +void tsi_ssl_root_certs_store_destroy(tsi_ssl_root_certs_store* self) { + if (self == nullptr) return; + X509_STORE_free(self->store); + gpr_free(self); +} + /* --- tsi_ssl_session_cache methods implementation. ---*/ tsi_ssl_session_cache* tsi_ssl_session_cache_create_lru(size_t capacity) { @@ -1468,7 +1516,9 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options( if (factory == nullptr) return TSI_INVALID_ARGUMENT; *factory = nullptr; - if (options->pem_root_certs == nullptr) return TSI_INVALID_ARGUMENT; + if (options->pem_root_certs == nullptr && options->root_store == nullptr) { + return TSI_INVALID_ARGUMENT; + } ssl_context = SSL_CTX_new(TLSv1_2_method()); if (ssl_context == nullptr) { @@ -1480,9 +1530,7 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options( gpr_zalloc(sizeof(*impl))); tsi_ssl_handshaker_factory_init(&impl->base); impl->base.vtable = &client_handshaker_factory_vtable; - impl->ssl_context = ssl_context; - if (options->session_cache != nullptr) { // Unref is called manually on factory destruction. impl->session_cache = @@ -1498,12 +1546,22 @@ tsi_result tsi_create_ssl_client_handshaker_factory_with_options( result = populate_ssl_context(ssl_context, options->pem_key_cert_pair, options->cipher_suites); if (result != TSI_OK) break; - result = ssl_ctx_load_verification_certs( - ssl_context, options->pem_root_certs, strlen(options->pem_root_certs), - nullptr); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Cannot load server root certificates."); - break; + +#if OPENSSL_VERSION_NUMBER >= 0x10100000 + // X509_STORE_up_ref is only available since OpenSSL 1.1. + if (options->root_store != nullptr) { + X509_STORE_up_ref(options->root_store->store); + SSL_CTX_set_cert_store(ssl_context, options->root_store->store); + } +#endif + if (OPENSSL_VERSION_NUMBER < 0x10100000 || options->root_store == nullptr) { + result = ssl_ctx_load_verification_certs( + ssl_context, options->pem_root_certs, strlen(options->pem_root_certs), + nullptr); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Cannot load server root certificates."); + break; + } } if (options->num_alpn_protocols != 0) { diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h index 29d209b8f5..cabf583098 100644 --- a/src/core/tsi/ssl_transport_security.h +++ b/src/core/tsi/ssl_transport_security.h @@ -36,6 +36,20 @@ #define TSI_SSL_ALPN_SELECTED_PROTOCOL "ssl_alpn_selected_protocol" +/* --- tsi_ssl_root_certs_store object --- + + This object stores SSL root certificates. It can be shared by multiple SSL + context. */ +typedef struct tsi_ssl_root_certs_store tsi_ssl_root_certs_store; + +/* Given a NULL-terminated string containing the PEM encoding of the root + certificates, creates a tsi_ssl_root_certs_store object. */ +tsi_ssl_root_certs_store* tsi_ssl_root_certs_store_create( + const char* pem_roots); + +/* Destroys the tsi_ssl_root_certs_store object. */ +void tsi_ssl_root_certs_store_destroy(tsi_ssl_root_certs_store* self); + /* --- tsi_ssl_session_cache object --- Cache for SSL sessions for sessions resumption. */ @@ -70,13 +84,13 @@ typedef struct { const char* cert_chain; } tsi_ssl_pem_key_cert_pair; -/* Creates a client handshaker factory. +/* TO BE DEPRECATED. + Creates a client handshaker factory. - pem_key_cert_pair is a pointer to the object containing client's private key and certificate chain. This parameter can be NULL if the client does not have such a key/cert pair. - pem_roots_cert is the NULL-terminated string containing the PEM encoding of - the client root certificates. This parameter may be NULL if the server does - not want the client to be authenticated with SSL. + the server root certificates. - cipher_suites contains an optional list of the ciphers that the client supports. The format of this string is described in: https://www.openssl.org/docs/apps/ciphers.html. @@ -103,9 +117,13 @@ typedef struct { not have such a key/cert pair. */ const tsi_ssl_pem_key_cert_pair* pem_key_cert_pair; /* pem_roots_cert is the NULL-terminated string containing the PEM encoding of - the client root certificates. This parameter may be NULL if the server does - not want the client to be authenticated with SSL. */ + the client root certificates. */ const char* pem_root_certs; + /* root_store is a pointer to the ssl_root_certs_store object. If root_store + is not nullptr and SSL implementation permits, root_store will be used as + root certificates. Otherwise, pem_roots_cert will be used to load server + root certificates. */ + const tsi_ssl_root_certs_store* root_store; /* cipher_suites contains an optional list of the ciphers that the client supports. The format of this string is described in: https://www.openssl.org/docs/apps/ciphers.html. @@ -160,12 +178,14 @@ void tsi_ssl_client_handshaker_factory_unref( typedef struct tsi_ssl_server_handshaker_factory tsi_ssl_server_handshaker_factory; -/* Creates a server handshaker factory. +/* TO BE DEPRECATED. + Creates a server handshaker factory. - pem_key_cert_pairs is an array private key / certificate chains of the server. - num_key_cert_pairs is the number of items in the pem_key_cert_pairs array. - pem_root_certs is the NULL-terminated string containing the PEM encoding - of the server root certificates. + of the client root certificates. This parameter may be NULL if the server + does not want the client to be authenticated with SSL. - cipher_suites contains an optional list of the ciphers that the server supports. The format of this string is described in: https://www.openssl.org/docs/apps/ciphers.html. @@ -187,7 +207,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory( const char** alpn_protocols, uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory** factory); -/* Same as tsi_create_ssl_server_handshaker_factory method except uses +/* TO BE DEPRECATED. + Same as tsi_create_ssl_server_handshaker_factory method except uses tsi_client_certificate_request_type to support more ways to handle client certificate authentication. - client_certificate_request, if set to non-zero will force the client to @@ -208,7 +229,8 @@ typedef struct { array. */ size_t num_key_cert_pairs; /* pem_root_certs is the NULL-terminated string containing the PEM encoding - of the server root certificates. */ + of the server root certificates. This parameter may be NULL if the server + does not want the client to be authenticated with SSL. */ const char* pem_client_root_certs; /* client_certificate_request, if set to non-zero will force the client to authenticate with an SSL cert. Note that this option is ignored if |