Merge pull request #10427 from ctiller/c++lame

Convert Lame Client Channel code to C++
diff --git a/INSTALL.md b/INSTALL.md
index ac03a5e..29f0060 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -28,16 +28,24 @@
  $ [sudo] apt-get install clang libc++-dev
 ```
 
-## Mac OSX
+## macOS 
 
-For a Mac system, git is not available by default. You will first need to
-install Xcode from the Mac AppStore and then run the following command from a
-terminal:
+On a Mac, you will first need to
+install Xcode or
+[Command Line Tools for Xcode](https://developer.apple.com/download/more/)
+and then run the following command from a terminal:
 
 ```sh
  $ [sudo] xcode-select --install
 ```
 
+To build gRPC from source, you may also need to install the following
+packages, which you can get from [Homebrew](https://brew.sh):
+
+```sh
+ $ brew install autoconf automake libtool shtool
+```
+
 ## Protoc
 
 By default gRPC uses [protocol buffers](https://github.com/google/protobuf),
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 79199cc..5d3cc4f 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -158,7 +158,7 @@
 } 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,
diff --git a/src/core/lib/http/httpcli_security_connector.c b/src/core/lib/http/httpcli_security_connector.c
index 9eab136..7694643 100644
--- a/src/core/lib/http/httpcli_security_connector.c
+++ b/src/core/lib/http/httpcli_security_connector.c
@@ -106,9 +106,8 @@
     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 @@
     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 @@
                           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 @@
   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(
diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.c b/src/core/lib/security/credentials/ssl/ssl_credentials.c
index b63bb6b..7c35ebe 100644
--- a/src/core/lib/security/credentials/ssl/ssl_credentials.c
+++ b/src/core/lib/security/credentials/ssl/ssl_credentials.c
@@ -40,28 +40,24 @@
 
 #include <grpc/support/alloc.h>
 #include <grpc/support/log.h>
-
-//
-// Utils
-//
-
-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);
-}
+#include <grpc/support/string_util.h>
 
 //
 // SSL Channel Credentials.
 //
 
+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);
+}
+
 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 @@
                              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 @@
   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]);
-    }
+    ssl_config_pem_key_cert_pair_destroy(&c->config.pem_key_cert_pairs[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);
-  }
-  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 @@
   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);
   }
 }
 
diff --git a/src/core/lib/security/transport/security_connector.c b/src/core/lib/security/transport/security_connector.c
index b15196e..30431a4 100644
--- a/src/core/lib/security/transport/security_connector.c
+++ b/src/core/lib/security/transport/security_connector.c
@@ -78,9 +78,8 @@
 
 /* Defines the cipher suites that we accept by default. All these cipher suites
    are compliant with HTTP2. */
-#define GRPC_SSL_CIPHER_SUITES                                            \
-  "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-" \
-  "SHA384:ECDHE-RSA-AES256-GCM-SHA384"
+#define GRPC_SSL_CIPHER_SUITES \
+  "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384"
 
 static gpr_once cipher_suites_once = GPR_ONCE_INIT;
 static const char *cipher_suites = NULL;
@@ -695,6 +694,7 @@
 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 +703,7 @@
       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 +714,18 @@
     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 +765,14 @@
   }
 }
 
-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 +780,16 @@
     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 +797,13 @@
     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 +820,12 @@
   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 +836,10 @@
   }
   *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 +847,14 @@
     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 +867,11 @@
   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 +882,9 @@
   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;
 }
diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h
index cf56cb3..d74f673 100644
--- a/src/core/lib/security/transport/security_connector.h
+++ b/src/core/lib/security/transport/security_connector.h
@@ -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 @@
     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 @@
     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;
 
diff --git a/src/core/tsi/ssl_transport_security.c b/src/core/tsi/ssl_transport_security.c
index 5f4705d..f35331e 100644
--- a/src/core/tsi/ssl_transport_security.c
+++ b/src/core/tsi/ssl_transport_security.c
@@ -479,9 +479,9 @@
 }
 
 /* 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 @@
 }
 
 /* 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 @@
 
 /* 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 @@
 /* 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 @@
 }
 
 /* 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 @@
 
 /* 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 @@
   *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 @@
 /* --- 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 @@
 
   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_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 @@
 
   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 @@
         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 @@
       }
 
       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;
 
diff --git a/src/core/tsi/ssl_transport_security.h b/src/core/tsi/ssl_transport_security.h
index 48dcaec..3117571 100644
--- a/src/core/tsi/ssl_transport_security.h
+++ b/src/core/tsi/ssl_transport_security.h
@@ -60,27 +60,32 @@
 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 @@
    - 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 @@
     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 @@
    - 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 @@
      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.
diff --git a/tools/jenkins/run_c_cpp_test.sh b/tools/jenkins/run_c_cpp_test.sh
index a7e5745..afa2e78 100755
--- a/tools/jenkins/run_c_cpp_test.sh
+++ b/tools/jenkins/run_c_cpp_test.sh
@@ -35,10 +35,12 @@
 # Enter the gRPC repo root
 cd $(dirname $0)/../..
 
-AFFECTS_C_CPP=`python -c 'import sys; \
+AFFECTS_C_CPP=`python -c 'import os; \
+               import sys; \
                sys.path.insert(0, "tools/run_tests/python_utils"); \
                import filter_pull_request_tests as filter; \
-               print(filter.affects_c_cpp("origin/$ghprbTargetBranch"))'`
+               github_target_branch = os.environ.get("ghprbTargetBranch"); \
+               print(filter.affects_c_cpp("origin/%s" % github_target_branch))'`
 
 if [ $AFFECTS_C_CPP == "False" ] ; then
   echo "This pull request does not affect C/C++. Tests do not need to be run."