diff options
Diffstat (limited to 'src/core/tsi/ssl_transport_security.c')
-rw-r--r-- | src/core/tsi/ssl_transport_security.c | 586 |
1 files changed, 346 insertions, 240 deletions
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c index 6156a39d09..42d25ca929 100644 --- a/src/core/tsi/ssl_transport_security.c +++ b/src/core/tsi/ssl_transport_security.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,28 +33,38 @@ #include "src/core/tsi/ssl_transport_security.h" +#include <grpc/support/port_platform.h> + #include <limits.h> #include <string.h> +/* TODO(jboeuf): refactor inet_ntop into a portability header. */ +#ifdef GPR_WINSOCK_SOCKET +#include <ws2tcpip.h> +#else +#include <arpa/inet.h> +#endif + #include <grpc/support/log.h> #include <grpc/support/sync.h> #include <grpc/support/thd.h> #include <grpc/support/useful.h> -#include "src/core/tsi/transport_security.h" #include <openssl/bio.h> -#include <openssl/crypto.h> /* For OPENSSL_free */ +#include <openssl/crypto.h> /* For OPENSSL_free */ #include <openssl/err.h> #include <openssl/ssl.h> #include <openssl/x509.h> #include <openssl/x509v3.h> +#include "src/core/tsi/ssl_types.h" +#include "src/core/tsi/transport_security.h" + /* --- Constants. ---*/ #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384 #define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024 - /* Putting a macro like this and littering the source file with #if is really bad practice. TODO(jboeuf): refactor all the #if / #endif in a separate module. */ @@ -69,16 +79,16 @@ /* --- Structure definitions. ---*/ struct tsi_ssl_handshaker_factory { - tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory* self, - const char* server_name_indication, - tsi_handshaker** handshaker); - void (*destroy)(tsi_ssl_handshaker_factory* self); + tsi_result (*create_handshaker)(tsi_ssl_handshaker_factory *self, + const char *server_name_indication, + tsi_handshaker **handshaker); + void (*destroy)(tsi_ssl_handshaker_factory *self); }; typedef struct { tsi_ssl_handshaker_factory base; - SSL_CTX* ssl_context; - unsigned char* alpn_protocol_list; + SSL_CTX *ssl_context; + unsigned char *alpn_protocol_list; size_t alpn_protocol_list_length; } tsi_ssl_client_handshaker_factory; @@ -88,27 +98,27 @@ typedef struct { /* Several contexts to support SNI. The tsi_peer array contains the subject names of the server certificates associated with the contexts at the same index. */ - SSL_CTX** ssl_contexts; - tsi_peer* ssl_context_x509_subject_names; + SSL_CTX **ssl_contexts; + tsi_peer *ssl_context_x509_subject_names; size_t ssl_context_count; - unsigned char* alpn_protocol_list; + unsigned char *alpn_protocol_list; size_t alpn_protocol_list_length; } tsi_ssl_server_handshaker_factory; typedef struct { tsi_handshaker base; - SSL* ssl; - BIO* into_ssl; - BIO* from_ssl; + SSL *ssl; + BIO *into_ssl; + BIO *from_ssl; tsi_result result; } tsi_ssl_handshaker; typedef struct { tsi_frame_protector base; - SSL* ssl; - BIO* into_ssl; - BIO* from_ssl; - unsigned char* buffer; + SSL *ssl; + BIO *into_ssl; + BIO *from_ssl; + unsigned char *buffer; size_t buffer_size; size_t buffer_offset; } tsi_ssl_frame_protector; @@ -118,7 +128,7 @@ typedef struct { static gpr_once init_openssl_once = GPR_ONCE_INIT; static gpr_mu *openssl_mutexes = NULL; -static void openssl_locking_cb(int mode, int type, const char* file, int line) { +static void openssl_locking_cb(int mode, int type, const char *file, int line) { if (mode & CRYPTO_LOCK) { gpr_mu_lock(&openssl_mutexes[type]); } else { @@ -132,10 +142,13 @@ static unsigned long openssl_thread_id_cb(void) { static void init_openssl(void) { int i; + int num_locks; SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); - openssl_mutexes = malloc(CRYPTO_num_locks() * sizeof(gpr_mu)); + num_locks = CRYPTO_num_locks(); + GPR_ASSERT(num_locks > 0); + openssl_mutexes = malloc((size_t)num_locks * sizeof(gpr_mu)); GPR_ASSERT(openssl_mutexes != NULL); for (i = 0; i < CRYPTO_num_locks(); i++) { gpr_mu_init(&openssl_mutexes[i]); @@ -146,7 +159,7 @@ static void init_openssl(void) { /* --- Ssl utils. ---*/ -static const char* ssl_error_string(int error) { +static const char *ssl_error_string(int error) { switch (error) { case SSL_ERROR_NONE: return "SSL_ERROR_NONE"; @@ -172,8 +185,8 @@ static const char* ssl_error_string(int error) { } /* TODO(jboeuf): Remove when we are past the debugging phase with this code. */ -static void ssl_log_where_info(const SSL* ssl, int where, int flag, - const char* msg) { +static void ssl_log_where_info(const SSL *ssl, int where, int flag, + const char *msg) { if ((where & flag) && tsi_tracing_enabled) { gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg, SSL_state_string_long(ssl), SSL_state_string(ssl)); @@ -181,7 +194,7 @@ static void ssl_log_where_info(const SSL* ssl, int where, int flag, } /* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */ -static void ssl_info_callback(const SSL* ssl, int where, int ret) { +static void ssl_info_callback(const SSL *ssl, int where, int ret) { if (ret == 0) { gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n"); return; @@ -193,13 +206,16 @@ static void ssl_info_callback(const SSL* ssl, int where, int ret) { } /* Returns 1 if name looks like an IP address, 0 otherwise. - This is a very rough heuristic as it does not handle IPV6 or things like: - 0300.0250.00.01, 0xC0.0Xa8.0x0.0x1, 000030052000001, 0xc0.052000001 */ + This is a very rough heuristic, and only handles IPv6 in hexadecimal form. */ static int looks_like_ip_address(const char *name) { size_t i; size_t dot_count = 0; size_t num_size = 0; for (i = 0; i < strlen(name); i++) { + if (name[i] == ':') { + /* IPv6 Address in hexadecimal form, : is not allowed in DNS names. */ + return 1; + } if (name[i] >= '0' && name[i] <= '9') { if (num_size > 3) return 0; num_size++; @@ -215,14 +231,13 @@ static int looks_like_ip_address(const char *name) { return 1; } - /* Gets the subject CN from an X509 cert. */ -static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8, - size_t* utf8_size) { +static tsi_result ssl_get_x509_common_name(X509 *cert, unsigned char **utf8, + size_t *utf8_size) { int common_name_index = -1; - X509_NAME_ENTRY* common_name_entry = NULL; - ASN1_STRING* common_name_asn1 = NULL; - X509_NAME* subject_name = X509_get_subject_name(cert); + X509_NAME_ENTRY *common_name_entry = NULL; + ASN1_STRING *common_name_asn1 = NULL; + X509_NAME *subject_name = X509_get_subject_name(cert); int utf8_returned_size = 0; if (subject_name == NULL) { gpr_log(GPR_ERROR, "Could not get subject name from certificate."); @@ -251,14 +266,14 @@ static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8, gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string."); return TSI_OUT_OF_RESOURCES; } - *utf8_size = utf8_returned_size; + *utf8_size = (size_t)utf8_returned_size; return TSI_OK; } /* Gets the subject CN of an X509 cert as a tsi_peer_property. */ static tsi_result peer_property_from_x509_common_name( - X509* cert, tsi_peer_property* property) { - unsigned char* common_name; + X509 *cert, tsi_peer_property *property) { + unsigned char *common_name; size_t common_name_size; tsi_result result = ssl_get_x509_common_name(cert, &common_name, &common_name_size); @@ -272,57 +287,105 @@ static tsi_result peer_property_from_x509_common_name( } result = tsi_construct_string_peer_property( TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY, - common_name == NULL ? "" : (const char*)common_name, common_name_size, + common_name == NULL ? "" : (const char *)common_name, common_name_size, property); OPENSSL_free(common_name); return result; } +/* Gets the X509 cert in PEM format as a tsi_peer_property. */ +static tsi_result add_pem_certificate(X509 *cert, tsi_peer_property *property) { + BIO *bio = BIO_new(BIO_s_mem()); + if (!PEM_write_bio_X509(bio, cert)) { + BIO_free(bio); + return TSI_INTERNAL_ERROR; + } + char *contents; + long len = BIO_get_mem_data(bio, &contents); + if (len <= 0) { + BIO_free(bio); + return TSI_INTERNAL_ERROR; + } + tsi_result result = tsi_construct_string_peer_property( + TSI_X509_PEM_CERT_PROPERTY, (const char *)contents, (size_t)len, + property); + BIO_free(bio); + return result; +} + /* Gets the subject SANs from an X509 cert as a tsi_peer_property. */ static tsi_result add_subject_alt_names_properties_to_peer( - tsi_peer* peer, GENERAL_NAMES* subject_alt_names, - int subject_alt_name_count) { - int i; + tsi_peer *peer, GENERAL_NAMES *subject_alt_names, + size_t subject_alt_name_count) { + size_t i; tsi_result result = TSI_OK; /* Reset for DNS entries filtering. */ peer->property_count -= subject_alt_name_count; for (i = 0; i < subject_alt_name_count; i++) { - GENERAL_NAME* subject_alt_name = - sk_GENERAL_NAME_value(subject_alt_names, i); + GENERAL_NAME *subject_alt_name = + sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i)); /* Filter out the non-dns entries names. */ if (subject_alt_name->type == GEN_DNS) { - unsigned char* dns_name = NULL; - int dns_name_size = - ASN1_STRING_to_UTF8(&dns_name, subject_alt_name->d.dNSName); - if (dns_name_size < 0) { + unsigned char *name = NULL; + int name_size; + name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName); + if (name_size < 0) { gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string."); result = TSI_INTERNAL_ERROR; break; } result = tsi_construct_string_peer_property( - TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, - (const char*)dns_name, dns_name_size, + TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char *)name, + (size_t)name_size, &peer->properties[peer->property_count++]); + OPENSSL_free(name); + } else if (subject_alt_name->type == GEN_IPADD) { + char ntop_buf[INET6_ADDRSTRLEN]; + int af; + + if (subject_alt_name->d.iPAddress->length == 4) { + af = AF_INET; + } else if (subject_alt_name->d.iPAddress->length == 16) { + af = AF_INET6; + } else { + gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP"); + result = TSI_INTERNAL_ERROR; + break; + } + const char *name = inet_ntop(af, subject_alt_name->d.iPAddress->data, + ntop_buf, INET6_ADDRSTRLEN); + if (name == NULL) { + gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet."); + result = TSI_INTERNAL_ERROR; + break; + } + + result = tsi_construct_string_peer_property_from_cstring( + TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name, &peer->properties[peer->property_count++]); - OPENSSL_free(dns_name); - if (result != TSI_OK) break; } + if (result != TSI_OK) break; } return result; } /* Gets information about the peer's X509 cert as a tsi_peer object. */ -static tsi_result peer_from_x509(X509* cert, int include_certificate_type, - tsi_peer* peer) { +static tsi_result peer_from_x509(X509 *cert, int include_certificate_type, + tsi_peer *peer) { /* TODO(jboeuf): Maybe add more properties. */ - GENERAL_NAMES* subject_alt_names = + GENERAL_NAMES *subject_alt_names = X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0); - int subject_alt_name_count = - (subject_alt_names != NULL) ? sk_GENERAL_NAME_num(subject_alt_names) : 0; - size_t property_count = (include_certificate_type ? 1 : 0) + - 1 /* common name */ + subject_alt_name_count; - tsi_result result = tsi_construct_peer(property_count, peer); + int subject_alt_name_count = (subject_alt_names != NULL) + ? (int)sk_GENERAL_NAME_num(subject_alt_names) + : 0; + size_t property_count; + tsi_result result; + GPR_ASSERT(subject_alt_name_count >= 0); + property_count = (include_certificate_type ? (size_t)1 : 0) + + 2 /* common name, certificate */ + + (size_t)subject_alt_name_count; + result = tsi_construct_peer(property_count, peer); if (result != TSI_OK) return result; do { if (include_certificate_type) { @@ -335,9 +398,13 @@ static tsi_result peer_from_x509(X509* cert, int include_certificate_type, cert, &peer->properties[include_certificate_type ? 1 : 0]); if (result != TSI_OK) break; + result = add_pem_certificate( + cert, &peer->properties[include_certificate_type ? 2 : 1]); + if (result != TSI_OK) break; + if (subject_alt_name_count != 0) { - result = add_subject_alt_names_properties_to_peer(peer, subject_alt_names, - subject_alt_name_count); + result = add_subject_alt_names_properties_to_peer( + peer, subject_alt_names, (size_t)subject_alt_name_count); if (result != TSI_OK) break; } } while (0); @@ -354,15 +421,18 @@ static void log_ssl_error_stack(void) { unsigned long err; while ((err = ERR_get_error()) != 0) { char details[256]; - ERR_error_string_n(err, details, sizeof(details)); + ERR_error_string_n((uint32_t)err, details, sizeof(details)); gpr_log(GPR_ERROR, "%s", details); } } /* Performs an SSL_read and handle errors. */ -static tsi_result do_ssl_read(SSL* ssl, unsigned char* unprotected_bytes, - size_t* unprotected_bytes_size) { - int read_from_ssl = SSL_read(ssl, unprotected_bytes, *unprotected_bytes_size); +static tsi_result do_ssl_read(SSL *ssl, unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size) { + int read_from_ssl; + GPR_ASSERT(*unprotected_bytes_size <= INT_MAX); + read_from_ssl = + SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size); if (read_from_ssl == 0) { gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly."); return TSI_INTERNAL_ERROR; @@ -389,15 +459,17 @@ static tsi_result do_ssl_read(SSL* ssl, unsigned char* unprotected_bytes, return TSI_PROTOCOL_FAILURE; } } - *unprotected_bytes_size = read_from_ssl; + *unprotected_bytes_size = (size_t)read_from_ssl; return TSI_OK; } /* Performs an SSL_write and handle errors. */ -static tsi_result do_ssl_write(SSL* ssl, unsigned char* unprotected_bytes, +static tsi_result do_ssl_write(SSL *ssl, unsigned char *unprotected_bytes, size_t unprotected_bytes_size) { - int ssl_write_result = - SSL_write(ssl, unprotected_bytes, unprotected_bytes_size); + int ssl_write_result; + GPR_ASSERT(unprotected_bytes_size <= INT_MAX); + ssl_write_result = + SSL_write(ssl, unprotected_bytes, (int)unprotected_bytes_size); if (ssl_write_result < 0) { ssl_write_result = SSL_get_error(ssl, ssl_write_result); if (ssl_write_result == SSL_ERROR_WANT_READ) { @@ -415,11 +487,13 @@ static tsi_result do_ssl_write(SSL* ssl, unsigned char* unprotected_bytes, /* Loads an in-memory PEM certificate chain into the SSL context. */ static tsi_result ssl_ctx_use_certificate_chain( - SSL_CTX* context, const unsigned char* pem_cert_chain, + SSL_CTX *context, const unsigned char *pem_cert_chain, size_t pem_cert_chain_size) { tsi_result result = TSI_OK; - X509* certificate = NULL; - BIO* pem = BIO_new_mem_buf((void*)pem_cert_chain, pem_cert_chain_size); + X509 *certificate = NULL; + BIO *pem; + GPR_ASSERT(pem_cert_chain_size <= INT_MAX); + pem = BIO_new_mem_buf((void *)pem_cert_chain, (int)pem_cert_chain_size); if (pem == NULL) return TSI_OUT_OF_RESOURCES; do { @@ -433,7 +507,7 @@ static tsi_result ssl_ctx_use_certificate_chain( break; } while (1) { - X509* certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, ""); + X509 *certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, ""); if (certificate_authority == NULL) { ERR_clear_error(); break; /* Done reading. */ @@ -445,7 +519,7 @@ static tsi_result ssl_ctx_use_certificate_chain( } /* We don't need to free certificate_authority as its ownership has been transfered to the context. That is not the case for certificate though. - */ + */ } } while (0); @@ -455,12 +529,14 @@ static tsi_result ssl_ctx_use_certificate_chain( } /* Loads an in-memory PEM private key into the SSL context. */ -static tsi_result ssl_ctx_use_private_key(SSL_CTX* context, - const unsigned char* pem_key, +static tsi_result ssl_ctx_use_private_key(SSL_CTX *context, + const unsigned char *pem_key, size_t pem_key_size) { tsi_result result = TSI_OK; - EVP_PKEY* private_key = NULL; - BIO* pem = BIO_new_mem_buf((void*)pem_key, pem_key_size); + EVP_PKEY *private_key = NULL; + BIO *pem; + GPR_ASSERT(pem_key_size <= INT_MAX); + pem = BIO_new_mem_buf((void *)pem_key, (int)pem_key_size); if (pem == NULL) return TSI_OUT_OF_RESOURCES; do { private_key = PEM_read_bio_PrivateKey(pem, NULL, NULL, ""); @@ -481,14 +557,17 @@ static tsi_result ssl_ctx_use_private_key(SSL_CTX* context, /* 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 unsigned char* pem_roots, size_t pem_roots_size, + SSL_CTX *context, const unsigned 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 = NULL; - X509_NAME* root_name = NULL; - BIO* pem = BIO_new_mem_buf((void*)pem_roots, pem_roots_size); - X509_STORE* root_store = SSL_CTX_get_cert_store(context); + X509 *root = NULL; + X509_NAME *root_name = NULL; + BIO *pem; + X509_STORE *root_store; + GPR_ASSERT(pem_roots_size <= INT_MAX); + pem = BIO_new_mem_buf((void *)pem_roots, (int)pem_roots_size); + root_store = SSL_CTX_get_cert_store(context); if (root_store == NULL) return TSI_INVALID_ARGUMENT; if (pem == NULL) return TSI_OUT_OF_RESOURCES; if (root_names != NULL) { @@ -546,9 +625,9 @@ static tsi_result ssl_ctx_load_verification_certs( /* 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( - SSL_CTX* context, const unsigned char* pem_private_key, - size_t pem_private_key_size, const unsigned char* pem_certificate_chain, - size_t pem_certificate_chain_size, const char* cipher_list) { + SSL_CTX *context, const unsigned char *pem_private_key, + size_t pem_private_key_size, const unsigned char *pem_certificate_chain, + size_t pem_certificate_chain_size, const char *cipher_list) { tsi_result result = TSI_OK; if (pem_certificate_chain != NULL) { result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain, @@ -571,7 +650,7 @@ static tsi_result populate_ssl_context( return TSI_INVALID_ARGUMENT; } { - EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); + EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) { gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key."); EC_KEY_free(ecdh); @@ -585,10 +664,12 @@ static tsi_result populate_ssl_context( /* Extracts the CN and the SANs from an X509 cert as a peer object. */ static tsi_result extract_x509_subject_names_from_pem_cert( - const unsigned char* pem_cert, size_t pem_cert_size, tsi_peer* peer) { + const unsigned char *pem_cert, size_t pem_cert_size, tsi_peer *peer) { tsi_result result = TSI_OK; - X509* cert = NULL; - BIO* pem = BIO_new_mem_buf((void*)pem_cert, pem_cert_size); + X509 *cert = NULL; + BIO *pem; + GPR_ASSERT(pem_cert_size <= INT_MAX); + pem = BIO_new_mem_buf((void *)pem_cert, (int)pem_cert_size); if (pem == NULL) return TSI_OUT_OF_RESOURCES; cert = PEM_read_bio_X509(pem, NULL, NULL, ""); @@ -605,11 +686,11 @@ static tsi_result extract_x509_subject_names_from_pem_cert( /* Builds the alpn protocol name list according to rfc 7301. */ static tsi_result build_alpn_protocol_name_list( - const unsigned char** alpn_protocols, - const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, - unsigned char** protocol_name_list, size_t* protocol_name_list_length) { + const unsigned char **alpn_protocols, + const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, + unsigned char **protocol_name_list, size_t *protocol_name_list_length) { uint16_t i; - unsigned char* current; + unsigned char *current; *protocol_name_list = NULL; *protocol_name_list_length = 0; if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT; @@ -618,7 +699,7 @@ static tsi_result build_alpn_protocol_name_list( gpr_log(GPR_ERROR, "Invalid 0-length protocol name."); return TSI_INVALID_ARGUMENT; } - *protocol_name_list_length += alpn_protocols_lengths[i] + 1; + *protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1; } *protocol_name_list = malloc(*protocol_name_list_length); if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES; @@ -630,7 +711,8 @@ static tsi_result build_alpn_protocol_name_list( } /* Safety check. */ if ((current < *protocol_name_list) || - ((gpr_uintptr)(current - *protocol_name_list) != *protocol_name_list_length)) { + ((uintptr_t)(current - *protocol_name_list) != + *protocol_name_list_length)) { return TSI_INTERNAL_ERROR; } return TSI_OK; @@ -638,28 +720,29 @@ static tsi_result build_alpn_protocol_name_list( /* --- tsi_frame_protector methods implementation. ---*/ -static tsi_result ssl_protector_protect(tsi_frame_protector* self, - const unsigned char* unprotected_bytes, - size_t* unprotected_bytes_size, - unsigned char* protected_output_frames, - size_t* protected_output_frames_size) { - tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self; +static tsi_result ssl_protector_protect(tsi_frame_protector *self, + const unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size, + unsigned char *protected_output_frames, + size_t *protected_output_frames_size) { + tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; int read_from_ssl; size_t available; tsi_result result = TSI_OK; /* First see if we have some pending data in the SSL BIO. */ - size_t pending_in_ssl = BIO_pending(impl->from_ssl); + int pending_in_ssl = (int)BIO_pending(impl->from_ssl); if (pending_in_ssl > 0) { *unprotected_bytes_size = 0; + GPR_ASSERT(*protected_output_frames_size <= INT_MAX); read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, - *protected_output_frames_size); + (int)*protected_output_frames_size); if (read_from_ssl < 0) { gpr_log(GPR_ERROR, "Could not read from BIO even though some data is pending"); return TSI_INTERNAL_ERROR; } - *protected_output_frames_size = read_from_ssl; + *protected_output_frames_size = (size_t)read_from_ssl; return TSI_OK; } @@ -679,24 +762,26 @@ static tsi_result ssl_protector_protect(tsi_frame_protector* self, result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size); if (result != TSI_OK) return result; + GPR_ASSERT(*protected_output_frames_size <= INT_MAX); read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, - *protected_output_frames_size); + (int)*protected_output_frames_size); if (read_from_ssl < 0) { gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write."); return TSI_INTERNAL_ERROR; } - *protected_output_frames_size = read_from_ssl; + *protected_output_frames_size = (size_t)read_from_ssl; *unprotected_bytes_size = available; impl->buffer_offset = 0; return TSI_OK; } static tsi_result ssl_protector_protect_flush( - tsi_frame_protector* self, unsigned char* protected_output_frames, - size_t* protected_output_frames_size, size_t* still_pending_size) { + tsi_frame_protector *self, unsigned char *protected_output_frames, + size_t *protected_output_frames_size, size_t *still_pending_size) { tsi_result result = TSI_OK; - tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self; + tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; int read_from_ssl = 0; + int pending; if (impl->buffer_offset != 0) { result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset); @@ -704,29 +789,34 @@ static tsi_result ssl_protector_protect_flush( impl->buffer_offset = 0; } - *still_pending_size = BIO_pending(impl->from_ssl); + pending = (int)BIO_pending(impl->from_ssl); + GPR_ASSERT(pending >= 0); + *still_pending_size = (size_t)pending; if (*still_pending_size == 0) return TSI_OK; + GPR_ASSERT(*protected_output_frames_size <= INT_MAX); read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames, - *protected_output_frames_size); + (int)*protected_output_frames_size); if (read_from_ssl <= 0) { gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write."); return TSI_INTERNAL_ERROR; } - *protected_output_frames_size = read_from_ssl; - *still_pending_size = BIO_pending(impl->from_ssl); + *protected_output_frames_size = (size_t)read_from_ssl; + pending = (int)BIO_pending(impl->from_ssl); + GPR_ASSERT(pending >= 0); + *still_pending_size = (size_t)pending; return TSI_OK; } static tsi_result ssl_protector_unprotect( - tsi_frame_protector* self, const unsigned char* protected_frames_bytes, - size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes, - size_t* unprotected_bytes_size) { + tsi_frame_protector *self, const unsigned char *protected_frames_bytes, + size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes, + size_t *unprotected_bytes_size) { tsi_result result = TSI_OK; int written_into_ssl = 0; size_t output_bytes_size = *unprotected_bytes_size; size_t output_bytes_offset = 0; - tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self; + tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; /* First, try to read remaining data from ssl. */ result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size); @@ -741,14 +831,15 @@ static tsi_result ssl_protector_unprotect( *unprotected_bytes_size = output_bytes_size - output_bytes_offset; /* Then, try to write some data to ssl. */ + GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX); written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes, - *protected_frames_bytes_size); + (int)*protected_frames_bytes_size); if (written_into_ssl < 0) { gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d", written_into_ssl); return TSI_INTERNAL_ERROR; } - *protected_frames_bytes_size = written_into_ssl; + *protected_frames_bytes_size = (size_t)written_into_ssl; /* Now try to read some data again. */ result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size); @@ -759,8 +850,8 @@ static tsi_result ssl_protector_unprotect( return result; } -static void ssl_protector_destroy(tsi_frame_protector* self) { - tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self; +static void ssl_protector_destroy(tsi_frame_protector *self) { + tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self; if (impl->buffer != NULL) free(impl->buffer); if (impl->ssl != NULL) SSL_free(impl->ssl); free(self); @@ -768,20 +859,22 @@ static void ssl_protector_destroy(tsi_frame_protector* self) { static const tsi_frame_protector_vtable frame_protector_vtable = { ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect, - ssl_protector_destroy, }; + ssl_protector_destroy, +}; /* --- tsi_handshaker methods implementation. ---*/ -static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self, - unsigned char* bytes, - size_t* bytes_size) { - tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; +static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self, + unsigned char *bytes, + size_t *bytes_size) { + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; int bytes_read_from_ssl = 0; if (bytes == NULL || bytes_size == NULL || *bytes_size == 0 || *bytes_size > INT_MAX) { return TSI_INVALID_ARGUMENT; } - bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, *bytes_size); + GPR_ASSERT(*bytes_size <= INT_MAX); + bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, (int)*bytes_size); if (bytes_read_from_ssl < 0) { *bytes_size = 0; if (!BIO_should_retry(impl->from_ssl)) { @@ -795,8 +888,8 @@ static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self, return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA; } -static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) { - tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; +static tsi_result ssl_handshaker_get_result(tsi_handshaker *self) { + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) && SSL_is_init_finished(impl->ssl)) { impl->result = TSI_OK; @@ -805,19 +898,21 @@ static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) { } static tsi_result ssl_handshaker_process_bytes_from_peer( - tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size) { - tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; + tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) { + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; int bytes_written_into_ssl_size = 0; if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) { return TSI_INVALID_ARGUMENT; } - bytes_written_into_ssl_size = BIO_write(impl->into_ssl, bytes, *bytes_size); + GPR_ASSERT(*bytes_size <= INT_MAX); + bytes_written_into_ssl_size = + BIO_write(impl->into_ssl, bytes, (int)*bytes_size); if (bytes_written_into_ssl_size < 0) { gpr_log(GPR_ERROR, "Could not write to memory BIO."); impl->result = TSI_INTERNAL_ERROR; return impl->result; } - *bytes_size = bytes_written_into_ssl_size; + *bytes_size = (size_t)bytes_written_into_ssl_size; if (!tsi_handshaker_is_in_progress(self)) { impl->result = TSI_OK; @@ -848,13 +943,13 @@ static tsi_result ssl_handshaker_process_bytes_from_peer( } } -static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self, - tsi_peer* peer) { +static tsi_result ssl_handshaker_extract_peer(tsi_handshaker *self, + tsi_peer *peer) { tsi_result result = TSI_OK; - const unsigned char* alpn_selected = NULL; + const unsigned char *alpn_selected = NULL; unsigned int alpn_selected_len; - tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; - X509* peer_cert = SSL_get_peer_certificate(impl->ssl); + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; + X509 *peer_cert = SSL_get_peer_certificate(impl->ssl); if (peer_cert != NULL) { result = peer_from_x509(peer_cert, 1, peer); X509_free(peer_cert); @@ -870,14 +965,14 @@ static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self, } if (alpn_selected != NULL) { size_t i; - tsi_peer_property* new_properties = + tsi_peer_property *new_properties = calloc(1, sizeof(tsi_peer_property) * (peer->property_count + 1)); if (new_properties == NULL) return TSI_OUT_OF_RESOURCES; for (i = 0; i < peer->property_count; i++) { new_properties[i] = peer->properties[i]; } result = tsi_construct_string_peer_property( - TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char*)alpn_selected, + TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char *)alpn_selected, alpn_selected_len, &new_properties[peer->property_count]); if (result != TSI_OK) { free(new_properties); @@ -891,12 +986,12 @@ static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self, } static tsi_result ssl_handshaker_create_frame_protector( - tsi_handshaker* self, size_t* max_output_protected_frame_size, - tsi_frame_protector** protector) { + tsi_handshaker *self, size_t *max_output_protected_frame_size, + tsi_frame_protector **protector) { size_t actual_max_output_protected_frame_size = TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND; - tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; - tsi_ssl_frame_protector* protector_impl = + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; + tsi_ssl_frame_protector *protector_impl = calloc(1, sizeof(tsi_ssl_frame_protector)); if (protector_impl == NULL) { return TSI_OUT_OF_RESOURCES; @@ -936,41 +1031,40 @@ static tsi_result ssl_handshaker_create_frame_protector( return TSI_OK; } -static void ssl_handshaker_destroy(tsi_handshaker* self) { - tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self; +static void ssl_handshaker_destroy(tsi_handshaker *self) { + tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self; SSL_free(impl->ssl); /* The BIO objects are owned by ssl */ free(impl); } static const tsi_handshaker_vtable handshaker_vtable = { ssl_handshaker_get_bytes_to_send_to_peer, - ssl_handshaker_process_bytes_from_peer, - ssl_handshaker_get_result, - ssl_handshaker_extract_peer, - ssl_handshaker_create_frame_protector, - ssl_handshaker_destroy, }; + ssl_handshaker_process_bytes_from_peer, ssl_handshaker_get_result, + ssl_handshaker_extract_peer, ssl_handshaker_create_frame_protector, + ssl_handshaker_destroy, +}; /* --- tsi_ssl_handshaker_factory common methods. --- */ tsi_result tsi_ssl_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory* self, const char* server_name_indication, - tsi_handshaker** handshaker) { + tsi_ssl_handshaker_factory *self, const char *server_name_indication, + tsi_handshaker **handshaker) { if (self == NULL || handshaker == NULL) return TSI_INVALID_ARGUMENT; return self->create_handshaker(self, server_name_indication, handshaker); } -void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory* self) { +void tsi_ssl_handshaker_factory_destroy(tsi_ssl_handshaker_factory *self) { if (self == NULL) return; self->destroy(self); } -static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client, - const char* server_name_indication, - tsi_handshaker** handshaker) { - SSL* ssl = SSL_new(ctx); - BIO* into_ssl = NULL; - BIO* from_ssl = NULL; - tsi_ssl_handshaker* impl = NULL; +static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client, + const char *server_name_indication, + tsi_handshaker **handshaker) { + SSL *ssl = SSL_new(ctx); + BIO *into_ssl = NULL; + BIO *from_ssl = NULL; + tsi_ssl_handshaker *impl = NULL; *handshaker = NULL; if (ctx == NULL) { gpr_log(GPR_ERROR, "SSL Context is null. Should never happen."); @@ -1029,18 +1123,18 @@ static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client, return TSI_OK; } -static int select_protocol_list(const unsigned char** out, - unsigned char* outlen, - const unsigned char* client_list, - unsigned int client_list_len, - const unsigned char* server_list, - unsigned int server_list_len) { - const unsigned char* client_current = client_list; +static int select_protocol_list(const unsigned char **out, + unsigned char *outlen, + const unsigned char *client_list, + size_t client_list_len, + const unsigned char *server_list, + size_t server_list_len) { + const unsigned char *client_current = client_list; while ((unsigned int)(client_current - client_list) < client_list_len) { unsigned char client_current_len = *(client_current++); - const unsigned char* server_current = server_list; + const unsigned char *server_current = server_list; while ((server_current >= server_list) && - (gpr_uintptr)(server_current - server_list) < server_list_len) { + (uintptr_t)(server_current - server_list) < server_list_len) { unsigned char server_current_len = *(server_current++); if ((client_current_len == server_current_len) && !memcmp(client_current, server_current, server_current_len)) { @@ -1058,29 +1152,31 @@ static int select_protocol_list(const unsigned char** out, /* --- tsi_ssl__client_handshaker_factory methods implementation. --- */ static tsi_result ssl_client_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory* self, const char* server_name_indication, - tsi_handshaker** handshaker) { - tsi_ssl_client_handshaker_factory* impl = - (tsi_ssl_client_handshaker_factory*)self; + tsi_ssl_handshaker_factory *self, const char *server_name_indication, + tsi_handshaker **handshaker) { + tsi_ssl_client_handshaker_factory *impl = + (tsi_ssl_client_handshaker_factory *)self; return create_tsi_ssl_handshaker(impl->ssl_context, 1, server_name_indication, handshaker); } static void ssl_client_handshaker_factory_destroy( - tsi_ssl_handshaker_factory* self) { - tsi_ssl_client_handshaker_factory* impl = - (tsi_ssl_client_handshaker_factory*)self; + tsi_ssl_handshaker_factory *self) { + tsi_ssl_client_handshaker_factory *impl = + (tsi_ssl_client_handshaker_factory *)self; if (impl->ssl_context != NULL) SSL_CTX_free(impl->ssl_context); if (impl->alpn_protocol_list != NULL) free(impl->alpn_protocol_list); free(impl); } -static int client_handshaker_factory_npn_callback( - SSL* ssl, unsigned char** out, unsigned char* outlen, - const unsigned char* in, unsigned int inlen, void* arg) { - tsi_ssl_client_handshaker_factory* factory = - (tsi_ssl_client_handshaker_factory*)arg; - return select_protocol_list((const unsigned char**)out, outlen, +static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg) { + tsi_ssl_client_handshaker_factory *factory = + (tsi_ssl_client_handshaker_factory *)arg; + return select_protocol_list((const unsigned char **)out, outlen, factory->alpn_protocol_list, factory->alpn_protocol_list_length, in, inlen); } @@ -1088,10 +1184,10 @@ static int client_handshaker_factory_npn_callback( /* --- tsi_ssl_server_handshaker_factory methods implementation. --- */ static tsi_result ssl_server_handshaker_factory_create_handshaker( - tsi_ssl_handshaker_factory* self, const char* server_name_indication, - tsi_handshaker** handshaker) { - tsi_ssl_server_handshaker_factory* impl = - (tsi_ssl_server_handshaker_factory*)self; + tsi_ssl_handshaker_factory *self, const char *server_name_indication, + tsi_handshaker **handshaker) { + tsi_ssl_server_handshaker_factory *impl = + (tsi_ssl_server_handshaker_factory *)self; if (impl->ssl_context_count == 0 || server_name_indication != NULL) { return TSI_INVALID_ARGUMENT; } @@ -1101,9 +1197,9 @@ static tsi_result ssl_server_handshaker_factory_create_handshaker( } static void ssl_server_handshaker_factory_destroy( - tsi_ssl_handshaker_factory* self) { - tsi_ssl_server_handshaker_factory* impl = - (tsi_ssl_server_handshaker_factory*)self; + tsi_ssl_handshaker_factory *self) { + tsi_ssl_server_handshaker_factory *impl = + (tsi_ssl_server_handshaker_factory *)self; size_t i; for (i = 0; i < impl->ssl_context_count; i++) { if (impl->ssl_contexts[i] != NULL) { @@ -1119,10 +1215,10 @@ static void ssl_server_handshaker_factory_destroy( free(impl); } -static int does_entry_match_name(const char* entry, size_t entry_length, - const char* name) { +static int does_entry_match_name(const char *entry, size_t entry_length, + const char *name) { const char *dot; - const char* name_subdomain = NULL; + const char *name_subdomain = NULL; size_t name_length = strlen(name); size_t name_subdomain_length; if (entry_length == 0) return 0; @@ -1153,7 +1249,7 @@ static int does_entry_match_name(const char* entry, size_t entry_length, if (name_subdomain_length < 2) return 0; name_subdomain++; /* Starts after the dot. */ name_subdomain_length--; - entry += 2; /* Remove *. */ + entry += 2; /* Remove *. */ entry_length -= 2; dot = strchr(name_subdomain, '.'); if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) { @@ -1167,12 +1263,12 @@ static int does_entry_match_name(const char* entry, size_t entry_length, strncmp(entry, name_subdomain, entry_length) == 0); } -static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap, - void* arg) { - tsi_ssl_server_handshaker_factory* impl = - (tsi_ssl_server_handshaker_factory*)arg; +static int ssl_server_handshaker_factory_servername_callback(SSL *ssl, int *ap, + void *arg) { + tsi_ssl_server_handshaker_factory *impl = + (tsi_ssl_server_handshaker_factory *)arg; size_t i = 0; - const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); + const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (servername == NULL || strlen(servername) == 0) { return SSL_TLSEXT_ERR_NOACK; } @@ -1190,10 +1286,10 @@ static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap, #if TSI_OPENSSL_ALPN_SUPPORT static int server_handshaker_factory_alpn_callback( - SSL* ssl, const unsigned char** out, unsigned char* outlen, - const unsigned char* in, unsigned int inlen, void* arg) { - tsi_ssl_server_handshaker_factory* factory = - (tsi_ssl_server_handshaker_factory*)arg; + SSL *ssl, const unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, void *arg) { + tsi_ssl_server_handshaker_factory *factory = + (tsi_ssl_server_handshaker_factory *)arg; return select_protocol_list(out, outlen, in, inlen, factory->alpn_protocol_list, factory->alpn_protocol_list_length); @@ -1201,25 +1297,26 @@ static int server_handshaker_factory_alpn_callback( #endif /* TSI_OPENSSL_ALPN_SUPPORT */ static int server_handshaker_factory_npn_advertised_callback( - SSL* ssl, const unsigned char** out, unsigned int* outlen, void* arg) { - tsi_ssl_server_handshaker_factory* factory = - (tsi_ssl_server_handshaker_factory*)arg; + SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) { + tsi_ssl_server_handshaker_factory *factory = + (tsi_ssl_server_handshaker_factory *)arg; *out = factory->alpn_protocol_list; - *outlen = factory->alpn_protocol_list_length; + GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX); + *outlen = (unsigned int)factory->alpn_protocol_list_length; return SSL_TLSEXT_ERR_OK; } /* --- tsi_ssl_handshaker_factory constructors. --- */ tsi_result tsi_create_ssl_client_handshaker_factory( - const unsigned char* pem_private_key, size_t pem_private_key_size, - const unsigned char* pem_cert_chain, size_t pem_cert_chain_size, - const unsigned char* pem_root_certs, size_t pem_root_certs_size, - const char* cipher_list, const unsigned char** alpn_protocols, - const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory** factory) { - SSL_CTX* ssl_context = NULL; - tsi_ssl_client_handshaker_factory* impl = NULL; + const unsigned char *pem_private_key, size_t pem_private_key_size, + const unsigned char *pem_cert_chain, size_t pem_cert_chain_size, + const unsigned char *pem_root_certs, size_t pem_root_certs_size, + const char *cipher_list, const unsigned char **alpn_protocols, + const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, + tsi_ssl_handshaker_factory **factory) { + SSL_CTX *ssl_context = NULL; + tsi_ssl_client_handshaker_factory *impl = NULL; tsi_result result = TSI_OK; gpr_once_init(&init_openssl_once, init_openssl); @@ -1263,8 +1360,10 @@ tsi_result tsi_create_ssl_client_handshaker_factory( break; } #if TSI_OPENSSL_ALPN_SUPPORT - if (SSL_CTX_set_alpn_protos(ssl_context, impl->alpn_protocol_list, - impl->alpn_protocol_list_length)) { + GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX); + if (SSL_CTX_set_alpn_protos( + ssl_context, impl->alpn_protocol_list, + (unsigned int)impl->alpn_protocol_list_length)) { gpr_log(GPR_ERROR, "Could not set alpn protocol list to context."); result = TSI_INVALID_ARGUMENT; break; @@ -1289,15 +1388,15 @@ tsi_result tsi_create_ssl_client_handshaker_factory( } tsi_result tsi_create_ssl_server_handshaker_factory( - const unsigned char** pem_private_keys, - const size_t* pem_private_keys_sizes, const unsigned char** pem_cert_chains, - const size_t* pem_cert_chains_sizes, size_t key_cert_pair_count, - const unsigned char* pem_client_root_certs, - size_t pem_client_root_certs_size, const char* cipher_list, - const unsigned char** alpn_protocols, - const unsigned char* alpn_protocols_lengths, uint16_t num_alpn_protocols, - tsi_ssl_handshaker_factory** factory) { - tsi_ssl_server_handshaker_factory* impl = NULL; + const unsigned char **pem_private_keys, + const size_t *pem_private_keys_sizes, const unsigned char **pem_cert_chains, + const size_t *pem_cert_chains_sizes, size_t key_cert_pair_count, + const unsigned char *pem_client_root_certs, + size_t pem_client_root_certs_size, int force_client_auth, + const char *cipher_list, const unsigned char **alpn_protocols, + const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols, + tsi_ssl_handshaker_factory **factory) { + tsi_ssl_server_handshaker_factory *impl = NULL; tsi_result result = TSI_OK; size_t i = 0; @@ -1315,7 +1414,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory( impl->base.create_handshaker = ssl_server_handshaker_factory_create_handshaker; impl->base.destroy = ssl_server_handshaker_factory_destroy; - impl->ssl_contexts = calloc(key_cert_pair_count, sizeof(SSL_CTX*)); + impl->ssl_contexts = calloc(key_cert_pair_count, sizeof(SSL_CTX *)); impl->ssl_context_x509_subject_names = calloc(key_cert_pair_count, sizeof(tsi_peer)); if (impl->ssl_contexts == NULL || @@ -1349,7 +1448,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory( if (result != TSI_OK) break; if (pem_client_root_certs != NULL) { - STACK_OF(X509_NAME)* root_names = NULL; + int flags = SSL_VERIFY_PEER; + STACK_OF(X509_NAME) *root_names = NULL; result = ssl_ctx_load_verification_certs( impl->ssl_contexts[i], pem_client_root_certs, pem_client_root_certs_size, &root_names); @@ -1358,7 +1458,8 @@ tsi_result tsi_create_ssl_server_handshaker_factory( break; } SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names); - SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, NULL); + if (force_client_auth) flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + SSL_CTX_set_verify(impl->ssl_contexts[i], flags, NULL); /* TODO(jboeuf): Add revocation verification. */ } @@ -1391,23 +1492,28 @@ tsi_result tsi_create_ssl_server_handshaker_factory( /* --- tsi_ssl utils. --- */ -int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) { +int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) { size_t i = 0; size_t san_count = 0; - const tsi_peer_property* cn_property = NULL; - - /* For now reject what looks like an IP address. */ - if (looks_like_ip_address(name)) return 0; + const tsi_peer_property *cn_property = NULL; + int like_ip = looks_like_ip_address(name); /* Check the SAN first. */ for (i = 0; i < peer->property_count; i++) { - const tsi_peer_property* property = &peer->properties[i]; + const tsi_peer_property *property = &peer->properties[i]; if (property->name == NULL) continue; if (strcmp(property->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) { san_count++; - if (does_entry_match_name(property->value.data, property->value.length, - name)) { + + if (!like_ip && does_entry_match_name(property->value.data, + property->value.length, name)) { + return 1; + } else if (like_ip && + strncmp(name, property->value.data, property->value.length) == + 0 && + strlen(name) == property->value.length) { + /* IP Addresses are exact matches only. */ return 1; } } else if (strcmp(property->name, @@ -1416,8 +1522,8 @@ int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) { } } - /* If there's no SAN, try the CN. */ - if (san_count == 0 && cn_property != NULL) { + /* If there's no SAN, try the CN, but only if its not like an IP Address */ + if (san_count == 0 && cn_property != NULL && !like_ip) { if (does_entry_match_name(cn_property->value.data, cn_property->value.length, name)) { return 1; |