more TLS cleanup.

- using NULL-terminated strings as opposed to const unsigned char *
with length since the credentials are in PEM format.
- aligning the structures with gRPC so that we have less convertions to
do back and forth.
pull/10627/head
Julien Boeuf 8 years ago
parent e7c31edb55
commit b71ef65cb3
  1. 2
      include/grpc/grpc_security.h
  2. 16
      src/core/lib/http/httpcli_security_connector.c
  3. 76
      src/core/lib/security/credentials/ssl/ssl_credentials.c
  4. 70
      src/core/lib/security/transport/security_connector.c
  5. 24
      src/core/lib/security/transport/security_connector.h
  6. 149
      src/core/tsi/ssl_transport_security.c
  7. 100
      src/core/tsi/ssl_transport_security.h

@ -158,7 +158,7 @@ typedef struct {
} grpc_ssl_pem_key_cert_pair;
/* Creates an SSL credentials object.
- pem_roots_cert is the NULL-terminated string containing the PEM encoding
- pem_root_certs is the NULL-terminated string containing the PEM encoding
of the server root certificates. If this parameter is NULL, the
implementation will first try to dereference the file pointed by the
GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment variable, and if that fails,

@ -106,9 +106,8 @@ static grpc_security_connector_vtable httpcli_ssl_vtable = {
httpcli_ssl_destroy, httpcli_ssl_check_peer};
static grpc_security_status httpcli_ssl_channel_security_connector_create(
grpc_exec_ctx *exec_ctx, const unsigned char *pem_root_certs,
size_t pem_root_certs_size, const char *secure_peer_name,
grpc_channel_security_connector **sc) {
grpc_exec_ctx *exec_ctx, const char *pem_root_certs,
const char *secure_peer_name, grpc_channel_security_connector **sc) {
tsi_result result = TSI_OK;
grpc_httpcli_ssl_channel_security_connector *c;
@ -126,8 +125,7 @@ static grpc_security_status httpcli_ssl_channel_security_connector_create(
c->secure_peer_name = gpr_strdup(secure_peer_name);
}
result = tsi_create_ssl_client_handshaker_factory(
NULL, 0, NULL, 0, pem_root_certs, pem_root_certs_size, NULL, NULL, NULL,
0, &c->handshaker_factory);
NULL, pem_root_certs, NULL, NULL, 0, &c->handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
@ -173,10 +171,9 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
void (*on_done)(grpc_exec_ctx *exec_ctx, void *arg,
grpc_endpoint *endpoint)) {
grpc_channel_security_connector *sc = NULL;
const unsigned char *pem_root_certs = NULL;
on_done_closure *c = gpr_malloc(sizeof(*c));
size_t pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
if (pem_root_certs == NULL || pem_root_certs_size == 0) {
const char *pem_root_certs = grpc_get_default_ssl_roots();
if (pem_root_certs == NULL) {
gpr_log(GPR_ERROR, "Could not get default pem root certs.");
on_done(exec_ctx, arg, NULL);
gpr_free(c);
@ -186,8 +183,7 @@ static void ssl_handshake(grpc_exec_ctx *exec_ctx, void *arg,
c->arg = arg;
c->handshake_mgr = grpc_handshake_manager_create();
GPR_ASSERT(httpcli_ssl_channel_security_connector_create(
exec_ctx, pem_root_certs, pem_root_certs_size, host, &sc) ==
GRPC_SECURITY_OK);
exec_ctx, pem_root_certs, host, &sc) == GRPC_SECURITY_OK);
grpc_channel_security_connector_add_handshakers(exec_ctx, sc,
c->handshake_mgr);
grpc_handshake_manager_do_handshake(

@ -40,28 +40,24 @@
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
//
// Utils
// SSL Channel Credentials.
//
static void ssl_copy_key_material(const char *input, unsigned char **output,
size_t *output_size) {
*output_size = strlen(input);
*output = gpr_malloc(*output_size);
memcpy(*output, input, *output_size);
static void ssl_config_pem_key_cert_pair_destroy(
tsi_ssl_pem_key_cert_pair *kp) {
if (kp == NULL) return;
gpr_free((void *)kp->private_key);
gpr_free((void *)kp->cert_chain);
}
//
// SSL Channel Credentials.
//
static void ssl_destruct(grpc_exec_ctx *exec_ctx,
grpc_channel_credentials *creds) {
grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
if (c->config.pem_cert_chain != NULL) gpr_free(c->config.pem_cert_chain);
gpr_free(c->config.pem_root_certs);
ssl_config_pem_key_cert_pair_destroy(&c->config.pem_key_cert_pair);
}
static grpc_security_status ssl_create_security_connector(
@ -102,18 +98,15 @@ static void ssl_build_config(const char *pem_root_certs,
grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
grpc_ssl_config *config) {
if (pem_root_certs != NULL) {
ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
&config->pem_root_certs_size);
config->pem_root_certs = gpr_strdup(pem_root_certs);
}
if (pem_key_cert_pair != NULL) {
GPR_ASSERT(pem_key_cert_pair->private_key != NULL);
GPR_ASSERT(pem_key_cert_pair->cert_chain != NULL);
ssl_copy_key_material(pem_key_cert_pair->private_key,
&config->pem_private_key,
&config->pem_private_key_size);
ssl_copy_key_material(pem_key_cert_pair->cert_chain,
&config->pem_cert_chain,
&config->pem_cert_chain_size);
config->pem_key_cert_pair.cert_chain =
gpr_strdup(pem_key_cert_pair->cert_chain);
config->pem_key_cert_pair.private_key =
gpr_strdup(pem_key_cert_pair->private_key);
}
}
@ -143,22 +136,10 @@ static void ssl_server_destruct(grpc_exec_ctx *exec_ctx,
grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds;
size_t i;
for (i = 0; i < c->config.num_key_cert_pairs; i++) {
if (c->config.pem_private_keys[i] != NULL) {
gpr_free(c->config.pem_private_keys[i]);
}
if (c->config.pem_cert_chains[i] != NULL) {
gpr_free(c->config.pem_cert_chains[i]);
}
}
if (c->config.pem_private_keys != NULL) gpr_free(c->config.pem_private_keys);
if (c->config.pem_private_keys_sizes != NULL) {
gpr_free(c->config.pem_private_keys_sizes);
}
if (c->config.pem_cert_chains != NULL) gpr_free(c->config.pem_cert_chains);
if (c->config.pem_cert_chains_sizes != NULL) {
gpr_free(c->config.pem_cert_chains_sizes);
ssl_config_pem_key_cert_pair_destroy(&c->config.pem_key_cert_pairs[i]);
}
if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
gpr_free(c->config.pem_key_cert_pairs);
gpr_free(c->config.pem_root_certs);
}
static grpc_security_status ssl_server_create_security_connector(
@ -179,30 +160,21 @@ static void ssl_build_server_config(
size_t i;
config->client_certificate_request = client_certificate_request;
if (pem_root_certs != NULL) {
ssl_copy_key_material(pem_root_certs, &config->pem_root_certs,
&config->pem_root_certs_size);
config->pem_root_certs = gpr_strdup(pem_root_certs);
}
if (num_key_cert_pairs > 0) {
GPR_ASSERT(pem_key_cert_pairs != NULL);
config->pem_private_keys =
gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
config->pem_cert_chains =
gpr_malloc(num_key_cert_pairs * sizeof(unsigned char *));
config->pem_private_keys_sizes =
gpr_malloc(num_key_cert_pairs * sizeof(size_t));
config->pem_cert_chains_sizes =
gpr_malloc(num_key_cert_pairs * sizeof(size_t));
config->pem_key_cert_pairs =
gpr_zalloc(num_key_cert_pairs * sizeof(tsi_ssl_pem_key_cert_pair));
}
config->num_key_cert_pairs = num_key_cert_pairs;
for (i = 0; i < num_key_cert_pairs; i++) {
GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL);
GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL);
ssl_copy_key_material(pem_key_cert_pairs[i].private_key,
&config->pem_private_keys[i],
&config->pem_private_keys_sizes[i]);
ssl_copy_key_material(pem_key_cert_pairs[i].cert_chain,
&config->pem_cert_chains[i],
&config->pem_cert_chains_sizes[i]);
config->pem_key_cert_pairs[i].cert_chain =
gpr_strdup(pem_key_cert_pairs[i].cert_chain);
config->pem_key_cert_pairs[i].private_key =
gpr_strdup(pem_key_cert_pairs[i].private_key);
}
}

@ -695,6 +695,7 @@ static grpc_security_connector_vtable ssl_channel_vtable = {
static grpc_security_connector_vtable ssl_server_vtable = {
ssl_server_destroy, ssl_server_check_peer};
/* returns a NULL terminated slice. */
static grpc_slice compute_default_pem_root_certs_once(void) {
grpc_slice result = grpc_empty_slice();
@ -703,7 +704,7 @@ static grpc_slice compute_default_pem_root_certs_once(void) {
gpr_getenv(GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR);
if (default_root_certs_path != NULL) {
GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(default_root_certs_path, 0, &result));
grpc_load_file(default_root_certs_path, 1, &result));
gpr_free(default_root_certs_path);
}
@ -714,15 +715,18 @@ static grpc_slice compute_default_pem_root_certs_once(void) {
ovrd_res = ssl_roots_override_cb(&pem_root_certs);
if (ovrd_res == GRPC_SSL_ROOTS_OVERRIDE_OK) {
GPR_ASSERT(pem_root_certs != NULL);
result = grpc_slice_new(pem_root_certs, strlen(pem_root_certs), gpr_free);
result = grpc_slice_from_copied_buffer(
pem_root_certs,
strlen(pem_root_certs) + 1); // NULL terminator.
}
gpr_free(pem_root_certs);
}
/* Fall back to installed certs if needed. */
if (GRPC_SLICE_IS_EMPTY(result) &&
ovrd_res != GRPC_SSL_ROOTS_OVERRIDE_FAIL_PERMANENTLY) {
GRPC_LOG_IF_ERROR("load_file",
grpc_load_file(installed_roots_path, 0, &result));
grpc_load_file(installed_roots_path, 1, &result));
}
return result;
}
@ -762,13 +766,14 @@ get_tsi_client_certificate_request_type(
}
}
size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
const char *grpc_get_default_ssl_roots(void) {
/* TODO(jboeuf@google.com): Maybe revisit the approach which consists in
loading all the roots once for the lifetime of the process. */
static gpr_once once = GPR_ONCE_INIT;
gpr_once_init(&once, init_default_pem_root_certs);
*pem_root_certs = GRPC_SLICE_START_PTR(default_pem_root_certs);
return GRPC_SLICE_LENGTH(default_pem_root_certs);
return GRPC_SLICE_IS_EMPTY(default_pem_root_certs)
? NULL
: (const char *)GRPC_SLICE_START_PTR(default_pem_root_certs);
}
grpc_security_status grpc_ssl_channel_security_connector_create(
@ -776,22 +781,16 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
const grpc_ssl_config *config, const char *target_name,
const char *overridden_target_name, grpc_channel_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings =
const char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols);
unsigned char *alpn_protocol_string_lengths =
gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
tsi_result result = TSI_OK;
grpc_ssl_channel_security_connector *c;
size_t i;
const unsigned char *pem_root_certs;
size_t pem_root_certs_size;
const char *pem_root_certs;
char *port;
for (i = 0; i < num_alpn_protocols; i++) {
alpn_protocol_strings[i] =
(const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
alpn_protocol_string_lengths[i] =
(unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i);
}
if (config == NULL || target_name == NULL) {
@ -799,14 +798,13 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
goto error;
}
if (config->pem_root_certs == NULL) {
pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
if (pem_root_certs == NULL || pem_root_certs_size == 0) {
pem_root_certs = grpc_get_default_ssl_roots();
if (pem_root_certs == NULL) {
gpr_log(GPR_ERROR, "Could not get default pem root certs.");
goto error;
}
} else {
pem_root_certs = config->pem_root_certs;
pem_root_certs_size = config->pem_root_certs_size;
}
c = gpr_zalloc(sizeof(grpc_ssl_channel_security_connector));
@ -823,11 +821,12 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
if (overridden_target_name != NULL) {
c->overridden_target_name = gpr_strdup(overridden_target_name);
}
bool has_key_cert_pair = config->pem_key_cert_pair.private_key != NULL &&
config->pem_key_cert_pair.cert_chain != NULL;
result = tsi_create_ssl_client_handshaker_factory(
config->pem_private_key, config->pem_private_key_size,
config->pem_cert_chain, config->pem_cert_chain_size, pem_root_certs,
pem_root_certs_size, ssl_cipher_suites(), alpn_protocol_strings,
alpn_protocol_string_lengths, (uint16_t)num_alpn_protocols,
has_key_cert_pair ? &config->pem_key_cert_pair : NULL, pem_root_certs,
ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols,
&c->handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
@ -838,12 +837,10 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
}
*sc = &c->base;
gpr_free((void *)alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths);
return GRPC_SECURITY_OK;
error:
gpr_free((void *)alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths);
return GRPC_SECURITY_ERROR;
}
@ -851,19 +848,14 @@ grpc_security_status grpc_ssl_server_security_connector_create(
grpc_exec_ctx *exec_ctx, const grpc_ssl_server_config *config,
grpc_server_security_connector **sc) {
size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
const unsigned char **alpn_protocol_strings =
const char **alpn_protocol_strings =
gpr_malloc(sizeof(const char *) * num_alpn_protocols);
unsigned char *alpn_protocol_string_lengths =
gpr_malloc(sizeof(unsigned char) * num_alpn_protocols);
tsi_result result = TSI_OK;
grpc_ssl_server_security_connector *c;
size_t i;
for (i = 0; i < num_alpn_protocols; i++) {
alpn_protocol_strings[i] =
(const unsigned char *)grpc_chttp2_get_alpn_version_index(i);
alpn_protocol_string_lengths[i] =
(unsigned char)strlen(grpc_chttp2_get_alpn_version_index(i));
alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i);
}
if (config == NULL || config->num_key_cert_pairs == 0) {
@ -876,15 +868,11 @@ grpc_security_status grpc_ssl_server_security_connector_create(
c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
c->base.base.vtable = &ssl_server_vtable;
result = tsi_create_ssl_server_handshaker_factory_ex(
(const unsigned char **)config->pem_private_keys,
config->pem_private_keys_sizes,
(const unsigned char **)config->pem_cert_chains,
config->pem_cert_chains_sizes, config->num_key_cert_pairs,
config->pem_root_certs, config->pem_root_certs_size,
get_tsi_client_certificate_request_type(
config->client_certificate_request),
ssl_cipher_suites(), alpn_protocol_strings, alpn_protocol_string_lengths,
(uint16_t)num_alpn_protocols, &c->handshaker_factory);
config->pem_key_cert_pairs, config->num_key_cert_pairs,
config->pem_root_certs, get_tsi_client_certificate_request_type(
config->client_certificate_request),
ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols,
&c->handshaker_factory);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.",
tsi_result_to_string(result));
@ -895,11 +883,9 @@ grpc_security_status grpc_ssl_server_security_connector_create(
c->base.add_handshakers = ssl_server_add_handshakers;
*sc = &c->base;
gpr_free((void *)alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths);
return GRPC_SECURITY_OK;
error:
gpr_free((void *)alpn_protocol_strings);
gpr_free(alpn_protocol_string_lengths);
return GRPC_SECURITY_ERROR;
}

@ -34,11 +34,14 @@
#ifndef GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H
#define GRPC_CORE_LIB_SECURITY_TRANSPORT_SECURITY_CONNECTOR_H
#include <stdbool.h>
#include <grpc/grpc_security.h>
#include "src/core/lib/channel/handshaker.h"
#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/tcp_server.h"
#include "src/core/tsi/ssl_transport_security.h"
#include "src/core/tsi/transport_security_interface.h"
/* --- status enum. --- */
@ -184,13 +187,10 @@ grpc_server_security_connector *grpc_fake_server_security_connector_create(
void);
/* Config for ssl clients. */
typedef struct {
unsigned char *pem_private_key;
size_t pem_private_key_size;
unsigned char *pem_cert_chain;
size_t pem_cert_chain_size;
unsigned char *pem_root_certs;
size_t pem_root_certs_size;
tsi_ssl_pem_key_cert_pair pem_key_cert_pair;
char *pem_root_certs;
} grpc_ssl_config;
/* Creates an SSL channel_security_connector.
@ -211,21 +211,17 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
const grpc_ssl_config *config, const char *target_name,
const char *overridden_target_name, grpc_channel_security_connector **sc);
/* Gets the default ssl roots. */
size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
/* Gets the default ssl roots. Returns NULL if not found. */
const char *grpc_get_default_ssl_roots(void);
/* Exposed for TESTING ONLY!. */
grpc_slice grpc_get_default_ssl_roots_for_testing(void);
/* Config for ssl servers. */
typedef struct {
unsigned char **pem_private_keys;
size_t *pem_private_keys_sizes;
unsigned char **pem_cert_chains;
size_t *pem_cert_chains_sizes;
tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs;
size_t num_key_cert_pairs;
unsigned char *pem_root_certs;
size_t pem_root_certs_size;
char *pem_root_certs;
grpc_ssl_client_certificate_request_type client_certificate_request;
} grpc_ssl_server_config;

@ -479,9 +479,9 @@ 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,
size_t pem_cert_chain_size) {
static tsi_result ssl_ctx_use_certificate_chain(SSL_CTX *context,
const char *pem_cert_chain,
size_t pem_cert_chain_size) {
tsi_result result = TSI_OK;
X509 *certificate = NULL;
BIO *pem;
@ -522,8 +522,7 @@ 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 char *pem_key,
size_t pem_key_size) {
tsi_result result = TSI_OK;
EVP_PKEY *private_key = NULL;
@ -549,9 +548,11 @@ 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,
STACK_OF(X509_NAME) * *root_names) {
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) {
tsi_result result = TSI_OK;
size_t num_roots = 0;
X509 *root = NULL;
@ -618,24 +619,25 @@ 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 tsi_ssl_pem_key_cert_pair *key_cert_pair,
const char *cipher_list) {
tsi_result result = TSI_OK;
if (pem_certificate_chain != NULL) {
result = ssl_ctx_use_certificate_chain(context, pem_certificate_chain,
pem_certificate_chain_size);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Invalid cert chain file.");
return result;
if (key_cert_pair != NULL) {
if (key_cert_pair->cert_chain != NULL) {
result = ssl_ctx_use_certificate_chain(context, key_cert_pair->cert_chain,
strlen(key_cert_pair->cert_chain));
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Invalid cert chain file.");
return result;
}
}
}
if (pem_private_key != NULL) {
result =
ssl_ctx_use_private_key(context, pem_private_key, pem_private_key_size);
if (result != TSI_OK || !SSL_CTX_check_private_key(context)) {
gpr_log(GPR_ERROR, "Invalid private key.");
return result != TSI_OK ? result : TSI_INVALID_ARGUMENT;
if (key_cert_pair->private_key != NULL) {
result = ssl_ctx_use_private_key(context, key_cert_pair->private_key,
strlen(key_cert_pair->private_key));
if (result != TSI_OK || !SSL_CTX_check_private_key(context)) {
gpr_log(GPR_ERROR, "Invalid private key.");
return result != TSI_OK ? result : TSI_INVALID_ARGUMENT;
}
}
}
if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) {
@ -656,13 +658,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) {
static tsi_result extract_x509_subject_names_from_pem_cert(const char *pem_cert,
tsi_peer *peer) {
tsi_result result = TSI_OK;
X509 *cert = NULL;
BIO *pem;
GPR_ASSERT(pem_cert_size <= INT_MAX);
pem = BIO_new_mem_buf((void *)pem_cert, (int)pem_cert_size);
pem = BIO_new_mem_buf((void *)pem_cert, (int)strlen(pem_cert));
if (pem == NULL) return TSI_OUT_OF_RESOURCES;
cert = PEM_read_bio_X509(pem, NULL, NULL, "");
@ -679,8 +680,7 @@ 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,
const char **alpn_protocols, uint16_t num_alpn_protocols,
unsigned char **protocol_name_list, size_t *protocol_name_list_length) {
uint16_t i;
unsigned char *current;
@ -688,19 +688,21 @@ static tsi_result build_alpn_protocol_name_list(
*protocol_name_list_length = 0;
if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
for (i = 0; i < num_alpn_protocols; i++) {
if (alpn_protocols_lengths[i] == 0) {
gpr_log(GPR_ERROR, "Invalid 0-length protocol name.");
size_t length = alpn_protocols[i] == NULL ? 0 : strlen(alpn_protocols[i]);
if (length == 0 || length > 255) {
gpr_log(GPR_ERROR, "Invalid protocol name length: %d.", (int)length);
return TSI_INVALID_ARGUMENT;
}
*protocol_name_list_length += (size_t)alpn_protocols_lengths[i] + 1;
*protocol_name_list_length += length + 1;
}
*protocol_name_list = gpr_malloc(*protocol_name_list_length);
if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES;
current = *protocol_name_list;
for (i = 0; i < num_alpn_protocols; i++) {
*(current++) = alpn_protocols_lengths[i];
memcpy(current, alpn_protocols[i], alpn_protocols_lengths[i]);
current += alpn_protocols_lengths[i];
size_t length = strlen(alpn_protocols[i]);
*(current++) = (uint8_t)length; /* max checked above. */
memcpy(current, alpn_protocols[i], length);
current += length;
}
/* Safety check. */
if ((current < *protocol_name_list) ||
@ -1280,11 +1282,9 @@ static int server_handshaker_factory_npn_advertised_callback(
/* --- 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,
const tsi_ssl_pem_key_cert_pair *pem_key_cert_pair,
const char *pem_root_certs, const char *cipher_suites,
const char **alpn_protocols, uint16_t num_alpn_protocols,
tsi_ssl_client_handshaker_factory **factory) {
SSL_CTX *ssl_context = NULL;
tsi_ssl_client_handshaker_factory *impl = NULL;
@ -1307,20 +1307,19 @@ tsi_result tsi_create_ssl_client_handshaker_factory(
do {
result =
populate_ssl_context(ssl_context, pem_private_key, pem_private_key_size,
pem_cert_chain, pem_cert_chain_size, cipher_list);
populate_ssl_context(ssl_context, pem_key_cert_pair, cipher_suites);
if (result != TSI_OK) break;
result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs,
pem_root_certs_size, NULL);
strlen(pem_root_certs), NULL);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Cannot load server root certificates.");
break;
}
if (num_alpn_protocols != 0) {
result = build_alpn_protocol_name_list(
alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
&impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols,
&impl->alpn_protocol_list,
&impl->alpn_protocol_list_length);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Building alpn list failed with error %s.",
tsi_result_to_string(result));
@ -1352,34 +1351,24 @@ 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, int force_client_auth,
const char *cipher_list, const unsigned char **alpn_protocols,
const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs, const char *pem_client_root_certs,
int force_client_auth, const char *cipher_suites,
const char **alpn_protocols, uint16_t num_alpn_protocols,
tsi_ssl_server_handshaker_factory **factory) {
return tsi_create_ssl_server_handshaker_factory_ex(
pem_private_keys, pem_private_keys_sizes, pem_cert_chains,
pem_cert_chains_sizes, key_cert_pair_count, pem_client_root_certs,
pem_client_root_certs_size,
pem_key_cert_pairs, num_key_cert_pairs, pem_client_root_certs,
force_client_auth ? TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
: TSI_DONT_REQUEST_CLIENT_CERTIFICATE,
cipher_list, alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
factory);
cipher_suites, alpn_protocols, num_alpn_protocols, factory);
}
tsi_result tsi_create_ssl_server_handshaker_factory_ex(
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 tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs, const char *pem_client_root_certs,
tsi_client_certificate_request_type client_certificate_request,
const char *cipher_list, const unsigned char **alpn_protocols,
const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
tsi_ssl_server_handshaker_factory **factory) {
const char *cipher_suites, const char **alpn_protocols,
uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory **factory) {
tsi_ssl_server_handshaker_factory *impl = NULL;
tsi_result result = TSI_OK;
size_t i = 0;
@ -1388,33 +1377,32 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex(
if (factory == NULL) return TSI_INVALID_ARGUMENT;
*factory = NULL;
if (key_cert_pair_count == 0 || pem_private_keys == NULL ||
pem_cert_chains == NULL) {
if (num_key_cert_pairs == 0 || pem_key_cert_pairs == NULL) {
return TSI_INVALID_ARGUMENT;
}
impl = gpr_zalloc(sizeof(*impl));
impl->ssl_contexts = gpr_zalloc(key_cert_pair_count * sizeof(SSL_CTX *));
impl->ssl_contexts = gpr_zalloc(num_key_cert_pairs * sizeof(SSL_CTX *));
impl->ssl_context_x509_subject_names =
gpr_zalloc(key_cert_pair_count * sizeof(tsi_peer));
gpr_zalloc(num_key_cert_pairs * sizeof(tsi_peer));
if (impl->ssl_contexts == NULL ||
impl->ssl_context_x509_subject_names == NULL) {
tsi_ssl_server_handshaker_factory_destroy(impl);
return TSI_OUT_OF_RESOURCES;
}
impl->ssl_context_count = key_cert_pair_count;
impl->ssl_context_count = num_key_cert_pairs;
if (num_alpn_protocols > 0) {
result = build_alpn_protocol_name_list(
alpn_protocols, alpn_protocols_lengths, num_alpn_protocols,
&impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols,
&impl->alpn_protocol_list,
&impl->alpn_protocol_list_length);
if (result != TSI_OK) {
tsi_ssl_server_handshaker_factory_destroy(impl);
return result;
}
}
for (i = 0; i < key_cert_pair_count; i++) {
for (i = 0; i < num_key_cert_pairs; i++) {
do {
impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
if (impl->ssl_contexts[i] == NULL) {
@ -1422,16 +1410,15 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex(
result = TSI_OUT_OF_RESOURCES;
break;
}
result = populate_ssl_context(
impl->ssl_contexts[i], pem_private_keys[i], pem_private_keys_sizes[i],
pem_cert_chains[i], pem_cert_chains_sizes[i], cipher_list);
result = populate_ssl_context(impl->ssl_contexts[i],
&pem_key_cert_pairs[i], cipher_suites);
if (result != TSI_OK) break;
if (pem_client_root_certs != NULL) {
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);
strlen(pem_client_root_certs), &root_names);
if (result != TSI_OK) {
gpr_log(GPR_ERROR, "Invalid verification certs.");
break;
@ -1464,7 +1451,7 @@ tsi_result tsi_create_ssl_server_handshaker_factory_ex(
}
result = extract_x509_subject_names_from_pem_cert(
pem_cert_chains[i], pem_cert_chains_sizes[i],
pem_key_cert_pairs[i].cert_chain,
&impl->ssl_context_x509_subject_names[i]);
if (result != TSI_OK) break;

@ -60,27 +60,32 @@ extern "C" {
typedef struct tsi_ssl_client_handshaker_factory
tsi_ssl_client_handshaker_factory;
/* Object that holds a private key / certificate chain pair in PEM format. */
typedef struct {
/* private_key is the NULL-terminated string containing the PEM encoding of
the client's private key. */
const char *private_key;
/* cert_chain is the NULL-terminated string containing the PEM encoding of
the client's certificate chain. */
const char *cert_chain;
} tsi_ssl_pem_key_cert_pair;
/* Creates a client handshaker factory.
- pem_private_key is the buffer containing the PEM encoding of the client's
private key. This parameter can be NULL if the client does not have a
private key.
- pem_private_key_size is the size of the associated buffer.
- pem_cert_chain is the buffer containing the PEM encoding of the client's
certificate chain. This parameter can be NULL if the client does not have
a certificate chain.
- pem_cert_chain_size is the size of the associated buffer.
- pem_roots_cert is the buffer containing the PEM encoding of the server
root certificates. This parameter cannot be NULL.
- pem_roots_cert_size is the size of the associated buffer.
- 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.
- 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.
This parameter can be set to NULL to use the default set of ciphers.
TODO(jboeuf): Revisit the format of this parameter.
- alpn_protocols is an array containing the protocol names that the
handshakers created with this factory support. This parameter can be NULL.
- alpn_protocols_lengths is an array containing the lengths of the alpn
protocols specified in alpn_protocols. This parameter can be NULL.
- alpn_protocols is an array containing the NULL terminated protocol names
that the handshakers created with this factory support. This parameter can
be NULL.
- num_alpn_protocols is the number of alpn protocols and associated lengths
specified. If this parameter is 0, the other alpn parameters must be NULL.
- factory is the address of the factory pointer to be created.
@ -88,11 +93,9 @@ typedef struct tsi_ssl_client_handshaker_factory
- This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
where a parameter is invalid. */
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_suites, const unsigned char **alpn_protocols,
const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
const tsi_ssl_pem_key_cert_pair *pem_key_cert_pair,
const char *pem_root_certs, const char *cipher_suites,
const char **alpn_protocols, uint16_t num_alpn_protocols,
tsi_ssl_client_handshaker_factory **factory);
/* Creates a client handshaker.
@ -122,37 +125,19 @@ typedef struct tsi_ssl_server_handshaker_factory
tsi_ssl_server_handshaker_factory;
/* Creates a server handshaker factory.
- version indicates which version of the specification to use.
- pem_private_keys is an array containing the PEM encoding of the server's
private keys. This parameter cannot be NULL. The size of the array is
given by the key_cert_pair_count parameter.
- pem_private_keys_sizes is the array containing the sizes of the associated
buffers.
- pem_cert_chains is an array containing the PEM encoding of the server's
cert chains. This parameter cannot be NULL. The size of the array is
given by the key_cert_pair_count parameter.
- pem_cert_chains_sizes is the array containing the sizes of the associated
buffers.
- key_cert_pair_count indicates the number of items in the private_key_files
and cert_chain_files parameters.
- pem_client_roots is the buffer containing the PEM encoding of the client
root certificates. This parameter may be NULL in which case the server will
not authenticate the client. If not NULL, the force_client_auth parameter
specifies if the server will accept only authenticated clients or both
authenticated and non-authenticated clients.
- pem_client_root_certs_size is the size of the associated buffer.
- force_client_auth, if set to non-zero will force the client to authenticate
with an SSL cert. Note that this option is ignored if pem_client_root_certs
is NULL or pem_client_roots_certs_size is 0
- 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.
- 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.
This parameter can be set to NULL to use the default set of ciphers.
TODO(jboeuf): Revisit the format of this parameter.
- alpn_protocols is an array containing the protocol names that the
handshakers created with this factory support. This parameter can be NULL.
- alpn_protocols_lengths is an array containing the lengths of the alpn
protocols specified in alpn_protocols. This parameter can be NULL.
- alpn_protocols is an array containing the NULL terminated protocol names
that the handshakers created with this factory support. This parameter can
be NULL.
- num_alpn_protocols is the number of alpn protocols and associated lengths
specified. If this parameter is 0, the other alpn parameters must be NULL.
- factory is the address of the factory pointer to be created.
@ -160,13 +145,10 @@ typedef struct tsi_ssl_server_handshaker_factory
- This method returns TSI_OK on success or TSI_INVALID_PARAMETER in the case
where a parameter is invalid. */
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, int force_client_auth,
const char *cipher_suites, const unsigned char **alpn_protocols,
const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs, const char *pem_client_root_certs,
int force_client_auth, const char *cipher_suites,
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
@ -176,15 +158,11 @@ tsi_result tsi_create_ssl_server_handshaker_factory(
authenticate with an SSL cert. Note that this option is ignored if
pem_client_root_certs is NULL or pem_client_roots_certs_size is 0 */
tsi_result tsi_create_ssl_server_handshaker_factory_ex(
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 tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs,
size_t num_key_cert_pairs, const char *pem_client_root_certs,
tsi_client_certificate_request_type client_certificate_request,
const char *cipher_suites, const unsigned char **alpn_protocols,
const unsigned char *alpn_protocols_lengths, uint16_t num_alpn_protocols,
tsi_ssl_server_handshaker_factory **factory);
const char *cipher_suites, const char **alpn_protocols,
uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory **factory);
/* Creates a server handshaker.
- self is the factory from which the handshaker will be created.

Loading…
Cancel
Save