blob: 59fd2b1c93a7ee1e4eb8d1c44cc9123b79c36c7f [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Craig Tillerb29f1fe2017-03-28 15:49:23 -070034#include "src/core/tsi/ssl_transport_security.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080035
Paul Querna47d841d2016-03-10 11:19:17 -080036#include <grpc/support/port_platform.h>
37
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080038#include <limits.h>
Julien Boeuf330f4c82015-04-27 10:37:42 -070039#include <string.h>
Paul Querna27df6892016-03-13 13:34:27 -070040
Nicolas "Pixel" Noblee3df5a02016-10-27 00:41:13 +020041/* TODO(jboeuf): refactor inet_ntop into a portability header. */
42/* Note: for whomever reads this and tries to refactor this, this
43 can't be in grpc, it has to be in gpr. */
44#ifdef GPR_WINDOWS
45#include <ws2tcpip.h>
46#else
47#include <arpa/inet.h>
Mehrdad Afsharif5839752017-04-18 10:26:40 -070048#include <sys/socket.h>
Nicolas "Pixel" Noblee3df5a02016-10-27 00:41:13 +020049#endif
50
Nicolas "Pixel" Nobleb29d8cf2016-04-08 01:38:29 +020051#include <grpc/support/alloc.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080052#include <grpc/support/log.h>
nnoble8a23a3d2014-12-16 10:10:29 -080053#include <grpc/support/sync.h>
Julien Boeuf4a0a3942015-02-03 15:04:45 -080054#include <grpc/support/thd.h>
Nicolas "Pixel" Noble213ed912015-01-30 02:11:35 +010055#include <grpc/support/useful.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080056
57#include <openssl/bio.h>
Craig Tillera82950e2015-09-22 12:33:20 -070058#include <openssl/crypto.h> /* For OPENSSL_free */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080059#include <openssl/err.h>
60#include <openssl/ssl.h>
61#include <openssl/x509.h>
62#include <openssl/x509v3.h>
63
Craig Tillerb29f1fe2017-03-28 15:49:23 -070064#include "src/core/tsi/ssl_types.h"
65#include "src/core/tsi/transport_security.h"
Craig Tiller0fe5ee72015-12-22 12:50:36 -080066
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080067/* --- Constants. ---*/
68
69#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384
70#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024
71
Julien Boeuf3e29de12015-06-18 23:29:13 +020072/* Putting a macro like this and littering the source file with #if is really
73 bad practice.
74 TODO(jboeuf): refactor all the #if / #endif in a separate module. */
Julien Boeufd1531322015-06-18 11:05:39 +020075#ifndef TSI_OPENSSL_ALPN_SUPPORT
76#define TSI_OPENSSL_ALPN_SUPPORT 1
77#endif
78
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080079/* TODO(jboeuf): I have not found a way to get this number dynamically from the
Julien Boeuf3e29de12015-06-18 23:29:13 +020080 SSL structure. This is what we would ultimately want though... */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080081#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
82
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080083/* --- Structure definitions. ---*/
84
Julien Boeuf935d02e2017-04-09 00:07:09 -070085struct tsi_ssl_client_handshaker_factory {
Craig Tiller45724b32015-09-22 10:42:19 -070086 SSL_CTX *ssl_context;
87 unsigned char *alpn_protocol_list;
Julien Boeufd1531322015-06-18 11:05:39 +020088 size_t alpn_protocol_list_length;
Julien Boeuf935d02e2017-04-09 00:07:09 -070089};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080090
Julien Boeuf935d02e2017-04-09 00:07:09 -070091struct tsi_ssl_server_handshaker_factory {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080092 /* Several contexts to support SNI.
93 The tsi_peer array contains the subject names of the server certificates
94 associated with the contexts at the same index. */
Craig Tiller45724b32015-09-22 10:42:19 -070095 SSL_CTX **ssl_contexts;
96 tsi_peer *ssl_context_x509_subject_names;
Julien Boeufb222b4d2015-01-15 17:01:39 -080097 size_t ssl_context_count;
Craig Tiller45724b32015-09-22 10:42:19 -070098 unsigned char *alpn_protocol_list;
Julien Boeufb222b4d2015-01-15 17:01:39 -080099 size_t alpn_protocol_list_length;
Julien Boeuf935d02e2017-04-09 00:07:09 -0700100};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800101
Craig Tillera82950e2015-09-22 12:33:20 -0700102typedef struct {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800103 tsi_handshaker base;
Craig Tiller45724b32015-09-22 10:42:19 -0700104 SSL *ssl;
105 BIO *into_ssl;
106 BIO *from_ssl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800107 tsi_result result;
108} tsi_ssl_handshaker;
109
Craig Tillera82950e2015-09-22 12:33:20 -0700110typedef struct {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800111 tsi_frame_protector base;
Craig Tiller45724b32015-09-22 10:42:19 -0700112 SSL *ssl;
113 BIO *into_ssl;
114 BIO *from_ssl;
115 unsigned char *buffer;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800116 size_t buffer_size;
117 size_t buffer_offset;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800118} tsi_ssl_frame_protector;
119
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800120/* --- Library Initialization. ---*/
121
nnoble8a23a3d2014-12-16 10:10:29 -0800122static gpr_once init_openssl_once = GPR_ONCE_INIT;
Craig Tiller45724b32015-09-22 10:42:19 -0700123static gpr_mu *openssl_mutexes = NULL;
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800124
Craig Tillera82950e2015-09-22 12:33:20 -0700125static void openssl_locking_cb(int mode, int type, const char *file, int line) {
126 if (mode & CRYPTO_LOCK) {
127 gpr_mu_lock(&openssl_mutexes[type]);
128 } else {
129 gpr_mu_unlock(&openssl_mutexes[type]);
130 }
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800131}
132
Craig Tillera82950e2015-09-22 12:33:20 -0700133static unsigned long openssl_thread_id_cb(void) {
134 return (unsigned long)gpr_thd_currentid();
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800135}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800136
Craig Tillera82950e2015-09-22 12:33:20 -0700137static void init_openssl(void) {
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800138 int i;
Craig Tiller3121fd42015-09-10 09:56:20 -0700139 int num_locks;
Craig Tillera82950e2015-09-22 12:33:20 -0700140 SSL_library_init();
141 SSL_load_error_strings();
142 OpenSSL_add_all_algorithms();
143 num_locks = CRYPTO_num_locks();
144 GPR_ASSERT(num_locks > 0);
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +0100145 openssl_mutexes = gpr_malloc((size_t)num_locks * sizeof(gpr_mu));
Craig Tillera82950e2015-09-22 12:33:20 -0700146 for (i = 0; i < CRYPTO_num_locks(); i++) {
147 gpr_mu_init(&openssl_mutexes[i]);
148 }
149 CRYPTO_set_locking_callback(openssl_locking_cb);
150 CRYPTO_set_id_callback(openssl_thread_id_cb);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800151}
152
153/* --- Ssl utils. ---*/
154
Craig Tillera82950e2015-09-22 12:33:20 -0700155static const char *ssl_error_string(int error) {
156 switch (error) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800157 case SSL_ERROR_NONE:
158 return "SSL_ERROR_NONE";
159 case SSL_ERROR_ZERO_RETURN:
160 return "SSL_ERROR_ZERO_RETURN";
161 case SSL_ERROR_WANT_READ:
162 return "SSL_ERROR_WANT_READ";
163 case SSL_ERROR_WANT_WRITE:
164 return "SSL_ERROR_WANT_WRITE";
165 case SSL_ERROR_WANT_CONNECT:
166 return "SSL_ERROR_WANT_CONNECT";
167 case SSL_ERROR_WANT_ACCEPT:
168 return "SSL_ERROR_WANT_ACCEPT";
169 case SSL_ERROR_WANT_X509_LOOKUP:
170 return "SSL_ERROR_WANT_X509_LOOKUP";
171 case SSL_ERROR_SYSCALL:
172 return "SSL_ERROR_SYSCALL";
173 case SSL_ERROR_SSL:
174 return "SSL_ERROR_SSL";
175 default:
176 return "Unknown error";
Craig Tillera82950e2015-09-22 12:33:20 -0700177 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800178}
179
180/* TODO(jboeuf): Remove when we are past the debugging phase with this code. */
Craig Tillera82950e2015-09-22 12:33:20 -0700181static void ssl_log_where_info(const SSL *ssl, int where, int flag,
182 const char *msg) {
Craig Tiller84f75d42017-05-03 13:06:35 -0700183 if ((where & flag) && GRPC_TRACER_ON(tsi_tracing_enabled)) {
Craig Tillera82950e2015-09-22 12:33:20 -0700184 gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg,
185 SSL_state_string_long(ssl), SSL_state_string(ssl));
186 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800187}
188
189/* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */
Craig Tillera82950e2015-09-22 12:33:20 -0700190static void ssl_info_callback(const SSL *ssl, int where, int ret) {
191 if (ret == 0) {
192 gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n");
193 return;
194 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800195
Craig Tillera82950e2015-09-22 12:33:20 -0700196 ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP");
197 ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START");
198 ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800199}
200
Julien Boeuf0170a6c2015-02-24 18:08:01 -0800201/* Returns 1 if name looks like an IP address, 0 otherwise.
Paul Querna4a9e7c42016-03-13 14:00:11 -0700202 This is a very rough heuristic, and only handles IPv6 in hexadecimal form. */
Craig Tillera82950e2015-09-22 12:33:20 -0700203static int looks_like_ip_address(const char *name) {
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800204 size_t i;
205 size_t dot_count = 0;
206 size_t num_size = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700207 for (i = 0; i < strlen(name); i++) {
Paul Querna4a9e7c42016-03-13 14:00:11 -0700208 if (name[i] == ':') {
209 /* IPv6 Address in hexadecimal form, : is not allowed in DNS names. */
210 return 1;
211 }
Craig Tillera82950e2015-09-22 12:33:20 -0700212 if (name[i] >= '0' && name[i] <= '9') {
213 if (num_size > 3) return 0;
214 num_size++;
215 } else if (name[i] == '.') {
216 if (dot_count > 3 || num_size == 0) return 0;
217 dot_count++;
218 num_size = 0;
219 } else {
220 return 0;
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800221 }
Craig Tillera82950e2015-09-22 12:33:20 -0700222 }
223 if (dot_count < 3 || num_size == 0) return 0;
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800224 return 1;
225}
226
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800227/* Gets the subject CN from an X509 cert. */
Craig Tillera82950e2015-09-22 12:33:20 -0700228static tsi_result ssl_get_x509_common_name(X509 *cert, unsigned char **utf8,
229 size_t *utf8_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800230 int common_name_index = -1;
Craig Tiller45724b32015-09-22 10:42:19 -0700231 X509_NAME_ENTRY *common_name_entry = NULL;
232 ASN1_STRING *common_name_asn1 = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700233 X509_NAME *subject_name = X509_get_subject_name(cert);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800234 int utf8_returned_size = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700235 if (subject_name == NULL) {
236 gpr_log(GPR_ERROR, "Could not get subject name from certificate.");
237 return TSI_NOT_FOUND;
238 }
239 common_name_index =
240 X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
241 if (common_name_index == -1) {
242 gpr_log(GPR_ERROR,
243 "Could not get common name of subject from certificate.");
244 return TSI_NOT_FOUND;
245 }
246 common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);
247 if (common_name_entry == NULL) {
248 gpr_log(GPR_ERROR, "Could not get common name entry from certificate.");
249 return TSI_INTERNAL_ERROR;
250 }
251 common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
252 if (common_name_asn1 == NULL) {
253 gpr_log(GPR_ERROR,
254 "Could not get common name entry asn1 from certificate.");
255 return TSI_INTERNAL_ERROR;
256 }
257 utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1);
258 if (utf8_returned_size < 0) {
259 gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string.");
260 return TSI_OUT_OF_RESOURCES;
261 }
262 *utf8_size = (size_t)utf8_returned_size;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800263 return TSI_OK;
264}
265
266/* Gets the subject CN of an X509 cert as a tsi_peer_property. */
Craig Tillera82950e2015-09-22 12:33:20 -0700267static tsi_result peer_property_from_x509_common_name(
268 X509 *cert, tsi_peer_property *property) {
Craig Tiller45724b32015-09-22 10:42:19 -0700269 unsigned char *common_name;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800270 size_t common_name_size;
Craig Tillera82950e2015-09-22 12:33:20 -0700271 tsi_result result =
272 ssl_get_x509_common_name(cert, &common_name, &common_name_size);
273 if (result != TSI_OK) {
274 if (result == TSI_NOT_FOUND) {
275 common_name = NULL;
276 common_name_size = 0;
277 } else {
278 return result;
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800279 }
Craig Tillera82950e2015-09-22 12:33:20 -0700280 }
281 result = tsi_construct_string_peer_property(
282 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY,
283 common_name == NULL ? "" : (const char *)common_name, common_name_size,
284 property);
285 OPENSSL_free(common_name);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800286 return result;
287}
288
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700289/* Gets the X509 cert in PEM format as a tsi_peer_property. */
290static tsi_result add_pem_certificate(X509 *cert, tsi_peer_property *property) {
291 BIO *bio = BIO_new(BIO_s_mem());
292 if (!PEM_write_bio_X509(bio, cert)) {
293 BIO_free(bio);
294 return TSI_INTERNAL_ERROR;
295 }
296 char *contents;
297 long len = BIO_get_mem_data(bio, &contents);
298 if (len <= 0) {
299 BIO_free(bio);
300 return TSI_INTERNAL_ERROR;
301 }
302 tsi_result result = tsi_construct_string_peer_property(
303 TSI_X509_PEM_CERT_PROPERTY, (const char *)contents, (size_t)len,
304 property);
305 BIO_free(bio);
306 return result;
307}
308
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800309/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */
Craig Tillera82950e2015-09-22 12:33:20 -0700310static tsi_result add_subject_alt_names_properties_to_peer(
311 tsi_peer *peer, GENERAL_NAMES *subject_alt_names,
312 size_t subject_alt_name_count) {
Craig Tiller3121fd42015-09-10 09:56:20 -0700313 size_t i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800314 tsi_result result = TSI_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800315
316 /* Reset for DNS entries filtering. */
Julien Boeuf77e8c1c2015-05-13 13:50:59 -0700317 peer->property_count -= subject_alt_name_count;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800318
Craig Tillera82950e2015-09-22 12:33:20 -0700319 for (i = 0; i < subject_alt_name_count; i++) {
320 GENERAL_NAME *subject_alt_name =
Craig Tiller0fe5ee72015-12-22 12:50:36 -0800321 sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
Craig Tillera82950e2015-09-22 12:33:20 -0700322 /* Filter out the non-dns entries names. */
323 if (subject_alt_name->type == GEN_DNS) {
Paul Querna47d841d2016-03-10 11:19:17 -0800324 unsigned char *name = NULL;
325 int name_size;
326 name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName);
327 if (name_size < 0) {
Craig Tillera82950e2015-09-22 12:33:20 -0700328 gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
329 result = TSI_INTERNAL_ERROR;
330 break;
331 }
332 result = tsi_construct_string_peer_property(
Paul Querna47d841d2016-03-10 11:19:17 -0800333 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char *)name,
334 (size_t)name_size, &peer->properties[peer->property_count++]);
335 OPENSSL_free(name);
336 } else if (subject_alt_name->type == GEN_IPADD) {
337 char ntop_buf[INET6_ADDRSTRLEN];
338 int af;
339
340 if (subject_alt_name->d.iPAddress->length == 4) {
341 af = AF_INET;
342 } else if (subject_alt_name->d.iPAddress->length == 16) {
343 af = AF_INET6;
344 } else {
345 gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP");
346 result = TSI_INTERNAL_ERROR;
347 break;
348 }
Nicolas "Pixel" Noblee3df5a02016-10-27 00:41:13 +0200349 const char *name = inet_ntop(af, subject_alt_name->d.iPAddress->data,
350 ntop_buf, INET6_ADDRSTRLEN);
Paul Querna47d841d2016-03-10 11:19:17 -0800351 if (name == NULL) {
352 gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet.");
353 result = TSI_INTERNAL_ERROR;
354 break;
355 }
356
357 result = tsi_construct_string_peer_property_from_cstring(
358 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name,
Craig Tillera82950e2015-09-22 12:33:20 -0700359 &peer->properties[peer->property_count++]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800360 }
Paul Querna47d841d2016-03-10 11:19:17 -0800361 if (result != TSI_OK) break;
Craig Tillera82950e2015-09-22 12:33:20 -0700362 }
Julien Boeuf77e8c1c2015-05-13 13:50:59 -0700363 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800364}
365
366/* Gets information about the peer's X509 cert as a tsi_peer object. */
Craig Tillera82950e2015-09-22 12:33:20 -0700367static tsi_result peer_from_x509(X509 *cert, int include_certificate_type,
368 tsi_peer *peer) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800369 /* TODO(jboeuf): Maybe add more properties. */
Craig Tillera82950e2015-09-22 12:33:20 -0700370 GENERAL_NAMES *subject_alt_names =
371 X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0);
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700372 int subject_alt_name_count = (subject_alt_names != NULL)
373 ? (int)sk_GENERAL_NAME_num(subject_alt_names)
374 : 0;
Craig Tiller3121fd42015-09-10 09:56:20 -0700375 size_t property_count;
376 tsi_result result;
Craig Tillera82950e2015-09-22 12:33:20 -0700377 GPR_ASSERT(subject_alt_name_count >= 0);
378 property_count = (include_certificate_type ? (size_t)1 : 0) +
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700379 2 /* common name, certificate */ +
380 (size_t)subject_alt_name_count;
Craig Tillera82950e2015-09-22 12:33:20 -0700381 result = tsi_construct_peer(property_count, peer);
382 if (result != TSI_OK) return result;
383 do {
384 if (include_certificate_type) {
385 result = tsi_construct_string_peer_property_from_cstring(
386 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
387 &peer->properties[0]);
388 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800389 }
Craig Tillera82950e2015-09-22 12:33:20 -0700390 result = peer_property_from_x509_common_name(
391 cert, &peer->properties[include_certificate_type ? 1 : 0]);
392 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800393
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700394 result = add_pem_certificate(
395 cert, &peer->properties[include_certificate_type ? 2 : 1]);
396 if (result != TSI_OK) break;
397
Craig Tillera82950e2015-09-22 12:33:20 -0700398 if (subject_alt_name_count != 0) {
399 result = add_subject_alt_names_properties_to_peer(
400 peer, subject_alt_names, (size_t)subject_alt_name_count);
401 if (result != TSI_OK) break;
Craig Tiller45724b32015-09-22 10:42:19 -0700402 }
Craig Tillera82950e2015-09-22 12:33:20 -0700403 } while (0);
404
405 if (subject_alt_names != NULL) {
406 sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
407 }
408 if (result != TSI_OK) tsi_peer_destruct(peer);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800409 return result;
410}
411
nnoble0c475f02014-12-05 15:37:39 -0800412/* Logs the SSL error stack. */
Craig Tillera82950e2015-09-22 12:33:20 -0700413static void log_ssl_error_stack(void) {
nnoble0c475f02014-12-05 15:37:39 -0800414 unsigned long err;
Craig Tillera82950e2015-09-22 12:33:20 -0700415 while ((err = ERR_get_error()) != 0) {
416 char details[256];
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700417 ERR_error_string_n((uint32_t)err, details, sizeof(details));
Craig Tillera82950e2015-09-22 12:33:20 -0700418 gpr_log(GPR_ERROR, "%s", details);
419 }
nnoble0c475f02014-12-05 15:37:39 -0800420}
421
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800422/* Performs an SSL_read and handle errors. */
Craig Tillera82950e2015-09-22 12:33:20 -0700423static tsi_result do_ssl_read(SSL *ssl, unsigned char *unprotected_bytes,
424 size_t *unprotected_bytes_size) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700425 int read_from_ssl;
Craig Tillera82950e2015-09-22 12:33:20 -0700426 GPR_ASSERT(*unprotected_bytes_size <= INT_MAX);
427 read_from_ssl =
428 SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size);
429 if (read_from_ssl == 0) {
430 gpr_log(GPR_ERROR, "SSL_read returned 0 unexpectedly.");
431 return TSI_INTERNAL_ERROR;
432 }
433 if (read_from_ssl < 0) {
434 read_from_ssl = SSL_get_error(ssl, read_from_ssl);
435 switch (read_from_ssl) {
436 case SSL_ERROR_WANT_READ:
437 /* We need more data to finish the frame. */
438 *unprotected_bytes_size = 0;
439 return TSI_OK;
440 case SSL_ERROR_WANT_WRITE:
441 gpr_log(
442 GPR_ERROR,
443 "Peer tried to renegotiate SSL connection. This is unsupported.");
444 return TSI_UNIMPLEMENTED;
445 case SSL_ERROR_SSL:
446 gpr_log(GPR_ERROR, "Corruption detected.");
447 log_ssl_error_stack();
448 return TSI_DATA_CORRUPTED;
449 default:
450 gpr_log(GPR_ERROR, "SSL_read failed with error %s.",
451 ssl_error_string(read_from_ssl));
452 return TSI_PROTOCOL_FAILURE;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800453 }
Craig Tillera82950e2015-09-22 12:33:20 -0700454 }
455 *unprotected_bytes_size = (size_t)read_from_ssl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800456 return TSI_OK;
457}
458
459/* Performs an SSL_write and handle errors. */
Craig Tillera82950e2015-09-22 12:33:20 -0700460static tsi_result do_ssl_write(SSL *ssl, unsigned char *unprotected_bytes,
461 size_t unprotected_bytes_size) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700462 int ssl_write_result;
Craig Tillera82950e2015-09-22 12:33:20 -0700463 GPR_ASSERT(unprotected_bytes_size <= INT_MAX);
464 ssl_write_result =
465 SSL_write(ssl, unprotected_bytes, (int)unprotected_bytes_size);
466 if (ssl_write_result < 0) {
467 ssl_write_result = SSL_get_error(ssl, ssl_write_result);
468 if (ssl_write_result == SSL_ERROR_WANT_READ) {
469 gpr_log(GPR_ERROR,
470 "Peer tried to renegotiate SSL connection. This is unsupported.");
471 return TSI_UNIMPLEMENTED;
472 } else {
473 gpr_log(GPR_ERROR, "SSL_write failed with error %s.",
474 ssl_error_string(ssl_write_result));
475 return TSI_INTERNAL_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800476 }
Craig Tillera82950e2015-09-22 12:33:20 -0700477 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800478 return TSI_OK;
479}
480
481/* Loads an in-memory PEM certificate chain into the SSL context. */
Julien Boeufb71ef652017-04-12 21:44:49 -0700482static tsi_result ssl_ctx_use_certificate_chain(SSL_CTX *context,
483 const char *pem_cert_chain,
484 size_t pem_cert_chain_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800485 tsi_result result = TSI_OK;
Craig Tiller45724b32015-09-22 10:42:19 -0700486 X509 *certificate = NULL;
487 BIO *pem;
Craig Tillera82950e2015-09-22 12:33:20 -0700488 GPR_ASSERT(pem_cert_chain_size <= INT_MAX);
489 pem = BIO_new_mem_buf((void *)pem_cert_chain, (int)pem_cert_chain_size);
490 if (pem == NULL) return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800491
Craig Tillera82950e2015-09-22 12:33:20 -0700492 do {
493 certificate = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
494 if (certificate == NULL) {
495 result = TSI_INVALID_ARGUMENT;
496 break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800497 }
Craig Tillera82950e2015-09-22 12:33:20 -0700498 if (!SSL_CTX_use_certificate(context, certificate)) {
499 result = TSI_INVALID_ARGUMENT;
500 break;
501 }
502 while (1) {
503 X509 *certificate_authority = PEM_read_bio_X509(pem, NULL, NULL, "");
504 if (certificate_authority == NULL) {
505 ERR_clear_error();
506 break; /* Done reading. */
507 }
508 if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) {
509 X509_free(certificate_authority);
510 result = TSI_INVALID_ARGUMENT;
511 break;
512 }
513 /* We don't need to free certificate_authority as its ownership has been
514 transfered to the context. That is not the case for certificate though.
515 */
516 }
517 } while (0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800518
Craig Tillera82950e2015-09-22 12:33:20 -0700519 if (certificate != NULL) X509_free(certificate);
520 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800521 return result;
522}
523
524/* Loads an in-memory PEM private key into the SSL context. */
Julien Boeufb71ef652017-04-12 21:44:49 -0700525static tsi_result ssl_ctx_use_private_key(SSL_CTX *context, const char *pem_key,
Craig Tillera82950e2015-09-22 12:33:20 -0700526 size_t pem_key_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800527 tsi_result result = TSI_OK;
Craig Tiller45724b32015-09-22 10:42:19 -0700528 EVP_PKEY *private_key = NULL;
529 BIO *pem;
Craig Tillera82950e2015-09-22 12:33:20 -0700530 GPR_ASSERT(pem_key_size <= INT_MAX);
531 pem = BIO_new_mem_buf((void *)pem_key, (int)pem_key_size);
532 if (pem == NULL) return TSI_OUT_OF_RESOURCES;
533 do {
534 private_key = PEM_read_bio_PrivateKey(pem, NULL, NULL, "");
535 if (private_key == NULL) {
536 result = TSI_INVALID_ARGUMENT;
537 break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800538 }
Craig Tillera82950e2015-09-22 12:33:20 -0700539 if (!SSL_CTX_use_PrivateKey(context, private_key)) {
540 result = TSI_INVALID_ARGUMENT;
541 break;
542 }
543 } while (0);
544 if (private_key != NULL) EVP_PKEY_free(private_key);
545 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800546 return result;
547}
548
549/* Loads in-memory PEM verification certs into the SSL context and optionally
550 returns the verification cert names (root_names can be NULL). */
Julien Boeufb71ef652017-04-12 21:44:49 -0700551static tsi_result ssl_ctx_load_verification_certs(SSL_CTX *context,
552 const char *pem_roots,
553 size_t pem_roots_size,
554 STACK_OF(X509_NAME) *
555 *root_names) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800556 tsi_result result = TSI_OK;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800557 size_t num_roots = 0;
Craig Tiller45724b32015-09-22 10:42:19 -0700558 X509 *root = NULL;
559 X509_NAME *root_name = NULL;
560 BIO *pem;
561 X509_STORE *root_store;
Craig Tillera82950e2015-09-22 12:33:20 -0700562 GPR_ASSERT(pem_roots_size <= INT_MAX);
563 pem = BIO_new_mem_buf((void *)pem_roots, (int)pem_roots_size);
564 root_store = SSL_CTX_get_cert_store(context);
565 if (root_store == NULL) return TSI_INVALID_ARGUMENT;
566 if (pem == NULL) return TSI_OUT_OF_RESOURCES;
567 if (root_names != NULL) {
568 *root_names = sk_X509_NAME_new_null();
569 if (*root_names == NULL) return TSI_OUT_OF_RESOURCES;
570 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800571
Craig Tillera82950e2015-09-22 12:33:20 -0700572 while (1) {
573 root = PEM_read_bio_X509_AUX(pem, NULL, NULL, "");
574 if (root == NULL) {
575 ERR_clear_error();
576 break; /* We're at the end of stream. */
nnoble0c475f02014-12-05 15:37:39 -0800577 }
Craig Tillera82950e2015-09-22 12:33:20 -0700578 if (root_names != NULL) {
579 root_name = X509_get_subject_name(root);
580 if (root_name == NULL) {
581 gpr_log(GPR_ERROR, "Could not get name from root certificate.");
582 result = TSI_INVALID_ARGUMENT;
583 break;
584 }
585 root_name = X509_NAME_dup(root_name);
586 if (root_name == NULL) {
587 result = TSI_OUT_OF_RESOURCES;
588 break;
589 }
590 sk_X509_NAME_push(*root_names, root_name);
591 root_name = NULL;
592 }
593 if (!X509_STORE_add_cert(root_store, root)) {
594 gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
595 result = TSI_INTERNAL_ERROR;
596 break;
597 }
598 X509_free(root);
599 num_roots++;
600 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800601
Craig Tillera82950e2015-09-22 12:33:20 -0700602 if (num_roots == 0) {
603 gpr_log(GPR_ERROR, "Could not load any root certificate.");
604 result = TSI_INVALID_ARGUMENT;
605 }
Craig Tiller45724b32015-09-22 10:42:19 -0700606
Craig Tillera82950e2015-09-22 12:33:20 -0700607 if (result != TSI_OK) {
608 if (root != NULL) X509_free(root);
609 if (root_names != NULL) {
610 sk_X509_NAME_pop_free(*root_names, X509_NAME_free);
611 *root_names = NULL;
612 if (root_name != NULL) X509_NAME_free(root_name);
Craig Tiller45724b32015-09-22 10:42:19 -0700613 }
Craig Tillera82950e2015-09-22 12:33:20 -0700614 }
615 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800616 return result;
617}
618
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800619/* Populates the SSL context with a private key and a cert chain, and sets the
620 cipher list and the ephemeral ECDH key. */
Craig Tillera82950e2015-09-22 12:33:20 -0700621static tsi_result populate_ssl_context(
Julien Boeufb71ef652017-04-12 21:44:49 -0700622 SSL_CTX *context, const tsi_ssl_pem_key_cert_pair *key_cert_pair,
623 const char *cipher_list) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800624 tsi_result result = TSI_OK;
Julien Boeufb71ef652017-04-12 21:44:49 -0700625 if (key_cert_pair != NULL) {
626 if (key_cert_pair->cert_chain != NULL) {
627 result = ssl_ctx_use_certificate_chain(context, key_cert_pair->cert_chain,
628 strlen(key_cert_pair->cert_chain));
629 if (result != TSI_OK) {
630 gpr_log(GPR_ERROR, "Invalid cert chain file.");
631 return result;
632 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800633 }
Julien Boeufb71ef652017-04-12 21:44:49 -0700634 if (key_cert_pair->private_key != NULL) {
635 result = ssl_ctx_use_private_key(context, key_cert_pair->private_key,
636 strlen(key_cert_pair->private_key));
637 if (result != TSI_OK || !SSL_CTX_check_private_key(context)) {
638 gpr_log(GPR_ERROR, "Invalid private key.");
639 return result != TSI_OK ? result : TSI_INVALID_ARGUMENT;
640 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800641 }
Craig Tillera82950e2015-09-22 12:33:20 -0700642 }
643 if ((cipher_list != NULL) && !SSL_CTX_set_cipher_list(context, cipher_list)) {
644 gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list);
645 return TSI_INVALID_ARGUMENT;
646 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800647 {
Craig Tillera82950e2015-09-22 12:33:20 -0700648 EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
649 if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
650 gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
651 EC_KEY_free(ecdh);
652 return TSI_INTERNAL_ERROR;
653 }
654 SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
655 EC_KEY_free(ecdh);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800656 }
657 return TSI_OK;
658}
659
660/* Extracts the CN and the SANs from an X509 cert as a peer object. */
Julien Boeufb71ef652017-04-12 21:44:49 -0700661static tsi_result extract_x509_subject_names_from_pem_cert(const char *pem_cert,
662 tsi_peer *peer) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800663 tsi_result result = TSI_OK;
Craig Tiller45724b32015-09-22 10:42:19 -0700664 X509 *cert = NULL;
665 BIO *pem;
Julien Boeufb71ef652017-04-12 21:44:49 -0700666 pem = BIO_new_mem_buf((void *)pem_cert, (int)strlen(pem_cert));
Craig Tillera82950e2015-09-22 12:33:20 -0700667 if (pem == NULL) return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800668
Craig Tillera82950e2015-09-22 12:33:20 -0700669 cert = PEM_read_bio_X509(pem, NULL, NULL, "");
670 if (cert == NULL) {
671 gpr_log(GPR_ERROR, "Invalid certificate");
672 result = TSI_INVALID_ARGUMENT;
673 } else {
674 result = peer_from_x509(cert, 0, peer);
675 }
676 if (cert != NULL) X509_free(cert);
677 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800678 return result;
679}
680
681/* Builds the alpn protocol name list according to rfc 7301. */
Craig Tillera82950e2015-09-22 12:33:20 -0700682static tsi_result build_alpn_protocol_name_list(
Julien Boeufb71ef652017-04-12 21:44:49 -0700683 const char **alpn_protocols, uint16_t num_alpn_protocols,
Craig Tillera82950e2015-09-22 12:33:20 -0700684 unsigned char **protocol_name_list, size_t *protocol_name_list_length) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800685 uint16_t i;
Craig Tiller45724b32015-09-22 10:42:19 -0700686 unsigned char *current;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800687 *protocol_name_list = NULL;
688 *protocol_name_list_length = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700689 if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
690 for (i = 0; i < num_alpn_protocols; i++) {
Julien Boeufb71ef652017-04-12 21:44:49 -0700691 size_t length = alpn_protocols[i] == NULL ? 0 : strlen(alpn_protocols[i]);
692 if (length == 0 || length > 255) {
693 gpr_log(GPR_ERROR, "Invalid protocol name length: %d.", (int)length);
Craig Tillera82950e2015-09-22 12:33:20 -0700694 return TSI_INVALID_ARGUMENT;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800695 }
Julien Boeufb71ef652017-04-12 21:44:49 -0700696 *protocol_name_list_length += length + 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700697 }
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +0100698 *protocol_name_list = gpr_malloc(*protocol_name_list_length);
Craig Tillera82950e2015-09-22 12:33:20 -0700699 if (*protocol_name_list == NULL) return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800700 current = *protocol_name_list;
Craig Tillera82950e2015-09-22 12:33:20 -0700701 for (i = 0; i < num_alpn_protocols; i++) {
Julien Boeufb71ef652017-04-12 21:44:49 -0700702 size_t length = strlen(alpn_protocols[i]);
703 *(current++) = (uint8_t)length; /* max checked above. */
704 memcpy(current, alpn_protocols[i], length);
705 current += length;
Craig Tillera82950e2015-09-22 12:33:20 -0700706 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800707 /* Safety check. */
Craig Tillera82950e2015-09-22 12:33:20 -0700708 if ((current < *protocol_name_list) ||
Craig Tiller7536af02015-12-22 13:49:30 -0800709 ((uintptr_t)(current - *protocol_name_list) !=
Craig Tillera82950e2015-09-22 12:33:20 -0700710 *protocol_name_list_length)) {
711 return TSI_INTERNAL_ERROR;
712 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800713 return TSI_OK;
714}
715
Deepak Lukosedba4c5f2016-03-25 12:54:25 -0700716// The verification callback is used for clients that don't really care about
717// the server's certificate, but we need to pull it anyway, in case a higher
718// layer wants to look at it. In this case the verification may fail, but
719// we don't really care.
720static int NullVerifyCallback(int preverify_ok, X509_STORE_CTX *ctx) {
721 return 1;
722}
723
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800724/* --- tsi_frame_protector methods implementation. ---*/
725
Craig Tillera82950e2015-09-22 12:33:20 -0700726static tsi_result ssl_protector_protect(tsi_frame_protector *self,
727 const unsigned char *unprotected_bytes,
728 size_t *unprotected_bytes_size,
729 unsigned char *protected_output_frames,
730 size_t *protected_output_frames_size) {
731 tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800732 int read_from_ssl;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800733 size_t available;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800734 tsi_result result = TSI_OK;
735
736 /* First see if we have some pending data in the SSL BIO. */
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700737 int pending_in_ssl = (int)BIO_pending(impl->from_ssl);
Craig Tillera82950e2015-09-22 12:33:20 -0700738 if (pending_in_ssl > 0) {
739 *unprotected_bytes_size = 0;
740 GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
741 read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
742 (int)*protected_output_frames_size);
743 if (read_from_ssl < 0) {
744 gpr_log(GPR_ERROR,
745 "Could not read from BIO even though some data is pending");
746 return TSI_INTERNAL_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800747 }
Craig Tillera82950e2015-09-22 12:33:20 -0700748 *protected_output_frames_size = (size_t)read_from_ssl;
749 return TSI_OK;
750 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800751
752 /* Now see if we can send a complete frame. */
753 available = impl->buffer_size - impl->buffer_offset;
Craig Tillera82950e2015-09-22 12:33:20 -0700754 if (available > *unprotected_bytes_size) {
755 /* If we cannot, just copy the data in our internal buffer. */
756 memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes,
757 *unprotected_bytes_size);
758 impl->buffer_offset += *unprotected_bytes_size;
759 *protected_output_frames_size = 0;
760 return TSI_OK;
761 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800762
763 /* If we can, prepare the buffer, send it to SSL_write and read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700764 memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available);
765 result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size);
766 if (result != TSI_OK) return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800767
Craig Tillera82950e2015-09-22 12:33:20 -0700768 GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
769 read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
770 (int)*protected_output_frames_size);
771 if (read_from_ssl < 0) {
772 gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
773 return TSI_INTERNAL_ERROR;
774 }
775 *protected_output_frames_size = (size_t)read_from_ssl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800776 *unprotected_bytes_size = available;
777 impl->buffer_offset = 0;
778 return TSI_OK;
779}
780
Craig Tillera82950e2015-09-22 12:33:20 -0700781static tsi_result ssl_protector_protect_flush(
782 tsi_frame_protector *self, unsigned char *protected_output_frames,
783 size_t *protected_output_frames_size, size_t *still_pending_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800784 tsi_result result = TSI_OK;
Craig Tillera82950e2015-09-22 12:33:20 -0700785 tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800786 int read_from_ssl = 0;
Craig Tiller3121fd42015-09-10 09:56:20 -0700787 int pending;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800788
Craig Tillera82950e2015-09-22 12:33:20 -0700789 if (impl->buffer_offset != 0) {
790 result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset);
791 if (result != TSI_OK) return result;
792 impl->buffer_offset = 0;
793 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800794
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700795 pending = (int)BIO_pending(impl->from_ssl);
Craig Tillera82950e2015-09-22 12:33:20 -0700796 GPR_ASSERT(pending >= 0);
797 *still_pending_size = (size_t)pending;
798 if (*still_pending_size == 0) return TSI_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800799
Craig Tillera82950e2015-09-22 12:33:20 -0700800 GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
801 read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
802 (int)*protected_output_frames_size);
803 if (read_from_ssl <= 0) {
804 gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
805 return TSI_INTERNAL_ERROR;
806 }
807 *protected_output_frames_size = (size_t)read_from_ssl;
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700808 pending = (int)BIO_pending(impl->from_ssl);
Craig Tillera82950e2015-09-22 12:33:20 -0700809 GPR_ASSERT(pending >= 0);
810 *still_pending_size = (size_t)pending;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800811 return TSI_OK;
812}
813
Craig Tillera82950e2015-09-22 12:33:20 -0700814static tsi_result ssl_protector_unprotect(
815 tsi_frame_protector *self, const unsigned char *protected_frames_bytes,
816 size_t *protected_frames_bytes_size, unsigned char *unprotected_bytes,
817 size_t *unprotected_bytes_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800818 tsi_result result = TSI_OK;
819 int written_into_ssl = 0;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800820 size_t output_bytes_size = *unprotected_bytes_size;
821 size_t output_bytes_offset = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700822 tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800823
824 /* First, try to read remaining data from ssl. */
Craig Tillera82950e2015-09-22 12:33:20 -0700825 result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
826 if (result != TSI_OK) return result;
827 if (*unprotected_bytes_size == output_bytes_size) {
828 /* We have read everything we could and cannot process any more input. */
829 *protected_frames_bytes_size = 0;
830 return TSI_OK;
831 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800832 output_bytes_offset = *unprotected_bytes_size;
833 unprotected_bytes += output_bytes_offset;
834 *unprotected_bytes_size = output_bytes_size - output_bytes_offset;
835
836 /* Then, try to write some data to ssl. */
Craig Tillera82950e2015-09-22 12:33:20 -0700837 GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX);
838 written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes,
839 (int)*protected_frames_bytes_size);
840 if (written_into_ssl < 0) {
841 gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d",
842 written_into_ssl);
843 return TSI_INTERNAL_ERROR;
844 }
845 *protected_frames_bytes_size = (size_t)written_into_ssl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800846
847 /* Now try to read some data again. */
Craig Tillera82950e2015-09-22 12:33:20 -0700848 result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
849 if (result == TSI_OK) {
850 /* Don't forget to output the total number of bytes read. */
851 *unprotected_bytes_size += output_bytes_offset;
852 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800853 return result;
854}
855
Craig Tillera82950e2015-09-22 12:33:20 -0700856static void ssl_protector_destroy(tsi_frame_protector *self) {
857 tsi_ssl_frame_protector *impl = (tsi_ssl_frame_protector *)self;
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +0100858 if (impl->buffer != NULL) gpr_free(impl->buffer);
Craig Tillera82950e2015-09-22 12:33:20 -0700859 if (impl->ssl != NULL) SSL_free(impl->ssl);
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +0100860 gpr_free(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800861}
862
863static const tsi_frame_protector_vtable frame_protector_vtable = {
Craig Tillera82950e2015-09-22 12:33:20 -0700864 ssl_protector_protect, ssl_protector_protect_flush, ssl_protector_unprotect,
865 ssl_protector_destroy,
Craig Tillerd6c98df2015-08-18 09:33:44 -0700866};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800867
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800868/* --- tsi_handshaker methods implementation. ---*/
869
Craig Tillera82950e2015-09-22 12:33:20 -0700870static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker *self,
871 unsigned char *bytes,
872 size_t *bytes_size) {
873 tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800874 int bytes_read_from_ssl = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700875 if (bytes == NULL || bytes_size == NULL || *bytes_size == 0 ||
876 *bytes_size > INT_MAX) {
877 return TSI_INVALID_ARGUMENT;
878 }
879 GPR_ASSERT(*bytes_size <= INT_MAX);
880 bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, (int)*bytes_size);
881 if (bytes_read_from_ssl < 0) {
882 *bytes_size = 0;
883 if (!BIO_should_retry(impl->from_ssl)) {
884 impl->result = TSI_INTERNAL_ERROR;
885 return impl->result;
886 } else {
887 return TSI_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800888 }
Craig Tillera82950e2015-09-22 12:33:20 -0700889 }
890 *bytes_size = (size_t)bytes_read_from_ssl;
891 return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800892}
893
Craig Tillera82950e2015-09-22 12:33:20 -0700894static tsi_result ssl_handshaker_get_result(tsi_handshaker *self) {
895 tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
896 if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) &&
897 SSL_is_init_finished(impl->ssl)) {
898 impl->result = TSI_OK;
899 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800900 return impl->result;
901}
902
Craig Tillera82950e2015-09-22 12:33:20 -0700903static tsi_result ssl_handshaker_process_bytes_from_peer(
904 tsi_handshaker *self, const unsigned char *bytes, size_t *bytes_size) {
905 tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800906 int bytes_written_into_ssl_size = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700907 if (bytes == NULL || bytes_size == 0 || *bytes_size > INT_MAX) {
908 return TSI_INVALID_ARGUMENT;
909 }
910 GPR_ASSERT(*bytes_size <= INT_MAX);
911 bytes_written_into_ssl_size =
912 BIO_write(impl->into_ssl, bytes, (int)*bytes_size);
913 if (bytes_written_into_ssl_size < 0) {
914 gpr_log(GPR_ERROR, "Could not write to memory BIO.");
915 impl->result = TSI_INTERNAL_ERROR;
916 return impl->result;
917 }
918 *bytes_size = (size_t)bytes_written_into_ssl_size;
Craig Tiller45724b32015-09-22 10:42:19 -0700919
Craig Tillera82950e2015-09-22 12:33:20 -0700920 if (!tsi_handshaker_is_in_progress(self)) {
921 impl->result = TSI_OK;
922 return impl->result;
923 } else {
924 /* Get ready to get some bytes from SSL. */
925 int ssl_result = SSL_do_handshake(impl->ssl);
926 ssl_result = SSL_get_error(impl->ssl, ssl_result);
927 switch (ssl_result) {
928 case SSL_ERROR_WANT_READ:
929 if (BIO_pending(impl->from_ssl) == 0) {
930 /* We need more data. */
931 return TSI_INCOMPLETE_DATA;
932 } else {
933 return TSI_OK;
934 }
935 case SSL_ERROR_NONE:
936 return TSI_OK;
937 default: {
938 char err_str[256];
939 ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str));
940 gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.",
941 ssl_error_string(ssl_result), err_str);
942 impl->result = TSI_PROTOCOL_FAILURE;
943 return impl->result;
944 }
Craig Tiller45724b32015-09-22 10:42:19 -0700945 }
Craig Tillera82950e2015-09-22 12:33:20 -0700946 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800947}
948
Craig Tillera82950e2015-09-22 12:33:20 -0700949static tsi_result ssl_handshaker_extract_peer(tsi_handshaker *self,
950 tsi_peer *peer) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800951 tsi_result result = TSI_OK;
Craig Tiller45724b32015-09-22 10:42:19 -0700952 const unsigned char *alpn_selected = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800953 unsigned int alpn_selected_len;
Craig Tillera82950e2015-09-22 12:33:20 -0700954 tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
955 X509 *peer_cert = SSL_get_peer_certificate(impl->ssl);
956 if (peer_cert != NULL) {
957 result = peer_from_x509(peer_cert, 1, peer);
958 X509_free(peer_cert);
959 if (result != TSI_OK) return result;
960 }
Julien Boeufd1531322015-06-18 11:05:39 +0200961#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -0700962 SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len);
Julien Boeufd1531322015-06-18 11:05:39 +0200963#endif /* TSI_OPENSSL_ALPN_SUPPORT */
Craig Tillera82950e2015-09-22 12:33:20 -0700964 if (alpn_selected == NULL) {
965 /* Try npn. */
966 SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected,
967 &alpn_selected_len);
968 }
969 if (alpn_selected != NULL) {
970 size_t i;
971 tsi_peer_property *new_properties =
Craig Tiller6f417882017-02-16 14:09:39 -0800972 gpr_zalloc(sizeof(*new_properties) * (peer->property_count + 1));
Craig Tillera82950e2015-09-22 12:33:20 -0700973 for (i = 0; i < peer->property_count; i++) {
974 new_properties[i] = peer->properties[i];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800975 }
Craig Tillera82950e2015-09-22 12:33:20 -0700976 result = tsi_construct_string_peer_property(
977 TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char *)alpn_selected,
978 alpn_selected_len, &new_properties[peer->property_count]);
979 if (result != TSI_OK) {
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +0100980 gpr_free(new_properties);
Craig Tillera82950e2015-09-22 12:33:20 -0700981 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800982 }
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +0100983 if (peer->properties != NULL) gpr_free(peer->properties);
Craig Tillera82950e2015-09-22 12:33:20 -0700984 peer->property_count++;
985 peer->properties = new_properties;
986 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800987 return result;
988}
989
Craig Tillera82950e2015-09-22 12:33:20 -0700990static tsi_result ssl_handshaker_create_frame_protector(
991 tsi_handshaker *self, size_t *max_output_protected_frame_size,
992 tsi_frame_protector **protector) {
993 size_t actual_max_output_protected_frame_size =
994 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
995 tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
Craig Tiller6f417882017-02-16 14:09:39 -0800996 tsi_ssl_frame_protector *protector_impl = gpr_zalloc(sizeof(*protector_impl));
Craig Tiller45724b32015-09-22 10:42:19 -0700997
Craig Tillera82950e2015-09-22 12:33:20 -0700998 if (max_output_protected_frame_size != NULL) {
999 if (*max_output_protected_frame_size >
1000 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) {
1001 *max_output_protected_frame_size =
1002 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
1003 } else if (*max_output_protected_frame_size <
1004 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) {
1005 *max_output_protected_frame_size =
1006 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND;
Craig Tiller45724b32015-09-22 10:42:19 -07001007 }
Craig Tillera82950e2015-09-22 12:33:20 -07001008 actual_max_output_protected_frame_size = *max_output_protected_frame_size;
1009 }
1010 protector_impl->buffer_size =
1011 actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD;
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +01001012 protector_impl->buffer = gpr_malloc(protector_impl->buffer_size);
Craig Tillera82950e2015-09-22 12:33:20 -07001013 if (protector_impl->buffer == NULL) {
1014 gpr_log(GPR_ERROR,
1015 "Could not allocated buffer for tsi_ssl_frame_protector.");
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +01001016 gpr_free(protector_impl);
Craig Tillera82950e2015-09-22 12:33:20 -07001017 return TSI_INTERNAL_ERROR;
1018 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001019
1020 /* Transfer ownership of ssl to the frame protector. It is OK as the caller
1021 * cannot call anything else but destroy on the handshaker after this call. */
1022 protector_impl->ssl = impl->ssl;
1023 impl->ssl = NULL;
1024 protector_impl->into_ssl = impl->into_ssl;
1025 protector_impl->from_ssl = impl->from_ssl;
1026
1027 protector_impl->base.vtable = &frame_protector_vtable;
1028 *protector = &protector_impl->base;
1029 return TSI_OK;
1030}
1031
Craig Tillera82950e2015-09-22 12:33:20 -07001032static void ssl_handshaker_destroy(tsi_handshaker *self) {
1033 tsi_ssl_handshaker *impl = (tsi_ssl_handshaker *)self;
1034 SSL_free(impl->ssl); /* The BIO objects are owned by ssl */
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +01001035 gpr_free(impl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001036}
1037
1038static const tsi_handshaker_vtable handshaker_vtable = {
Craig Tillera82950e2015-09-22 12:33:20 -07001039 ssl_handshaker_get_bytes_to_send_to_peer,
Craig Tillerf40df232016-03-25 13:38:14 -07001040 ssl_handshaker_process_bytes_from_peer,
1041 ssl_handshaker_get_result,
1042 ssl_handshaker_extract_peer,
1043 ssl_handshaker_create_frame_protector,
Craig Tillera82950e2015-09-22 12:33:20 -07001044 ssl_handshaker_destroy,
jiangtaoli201620b9f942017-04-07 12:50:33 -07001045 NULL,
Craig Tillerd6c98df2015-08-18 09:33:44 -07001046};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001047
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001048/* --- tsi_ssl_handshaker_factory common methods. --- */
1049
Craig Tillera82950e2015-09-22 12:33:20 -07001050static tsi_result create_tsi_ssl_handshaker(SSL_CTX *ctx, int is_client,
1051 const char *server_name_indication,
1052 tsi_handshaker **handshaker) {
1053 SSL *ssl = SSL_new(ctx);
Craig Tiller45724b32015-09-22 10:42:19 -07001054 BIO *into_ssl = NULL;
1055 BIO *from_ssl = NULL;
1056 tsi_ssl_handshaker *impl = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001057 *handshaker = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -07001058 if (ctx == NULL) {
1059 gpr_log(GPR_ERROR, "SSL Context is null. Should never happen.");
1060 return TSI_INTERNAL_ERROR;
1061 }
1062 if (ssl == NULL) {
1063 return TSI_OUT_OF_RESOURCES;
1064 }
1065 SSL_set_info_callback(ssl, ssl_info_callback);
1066
1067 into_ssl = BIO_new(BIO_s_mem());
1068 from_ssl = BIO_new(BIO_s_mem());
1069 if (into_ssl == NULL || from_ssl == NULL) {
1070 gpr_log(GPR_ERROR, "BIO_new failed.");
1071 SSL_free(ssl);
1072 if (into_ssl != NULL) BIO_free(into_ssl);
1073 if (from_ssl != NULL) BIO_free(into_ssl);
1074 return TSI_OUT_OF_RESOURCES;
1075 }
1076 SSL_set_bio(ssl, into_ssl, from_ssl);
1077 if (is_client) {
1078 int ssl_result;
1079 SSL_set_connect_state(ssl);
1080 if (server_name_indication != NULL) {
1081 if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) {
1082 gpr_log(GPR_ERROR, "Invalid server name indication %s.",
1083 server_name_indication);
1084 SSL_free(ssl);
1085 return TSI_INTERNAL_ERROR;
1086 }
1087 }
1088 ssl_result = SSL_do_handshake(ssl);
1089 ssl_result = SSL_get_error(ssl, ssl_result);
1090 if (ssl_result != SSL_ERROR_WANT_READ) {
1091 gpr_log(GPR_ERROR,
1092 "Unexpected error received from first SSL_do_handshake call: %s",
1093 ssl_error_string(ssl_result));
1094 SSL_free(ssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001095 return TSI_INTERNAL_ERROR;
1096 }
Craig Tillera82950e2015-09-22 12:33:20 -07001097 } else {
1098 SSL_set_accept_state(ssl);
1099 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001100
Craig Tiller6f417882017-02-16 14:09:39 -08001101 impl = gpr_zalloc(sizeof(*impl));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001102 impl->ssl = ssl;
1103 impl->into_ssl = into_ssl;
1104 impl->from_ssl = from_ssl;
1105 impl->result = TSI_HANDSHAKE_IN_PROGRESS;
1106 impl->base.vtable = &handshaker_vtable;
1107 *handshaker = &impl->base;
1108 return TSI_OK;
1109}
1110
Craig Tillera82950e2015-09-22 12:33:20 -07001111static int select_protocol_list(const unsigned char **out,
1112 unsigned char *outlen,
1113 const unsigned char *client_list,
1114 size_t client_list_len,
1115 const unsigned char *server_list,
1116 size_t server_list_len) {
Craig Tiller45724b32015-09-22 10:42:19 -07001117 const unsigned char *client_current = client_list;
Craig Tillera82950e2015-09-22 12:33:20 -07001118 while ((unsigned int)(client_current - client_list) < client_list_len) {
1119 unsigned char client_current_len = *(client_current++);
1120 const unsigned char *server_current = server_list;
1121 while ((server_current >= server_list) &&
Craig Tiller7536af02015-12-22 13:49:30 -08001122 (uintptr_t)(server_current - server_list) < server_list_len) {
Craig Tillera82950e2015-09-22 12:33:20 -07001123 unsigned char server_current_len = *(server_current++);
1124 if ((client_current_len == server_current_len) &&
1125 !memcmp(client_current, server_current, server_current_len)) {
1126 *out = server_current;
1127 *outlen = server_current_len;
1128 return SSL_TLSEXT_ERR_OK;
1129 }
1130 server_current += server_current_len;
Julien Boeufd1531322015-06-18 11:05:39 +02001131 }
Craig Tillera82950e2015-09-22 12:33:20 -07001132 client_current += client_current_len;
1133 }
Julien Boeufd1531322015-06-18 11:05:39 +02001134 return SSL_TLSEXT_ERR_NOACK;
1135}
1136
Julien Boeuf935d02e2017-04-09 00:07:09 -07001137/* --- tsi_ssl_client_handshaker_factory methods implementation. --- */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001138
Julien Boeuf935d02e2017-04-09 00:07:09 -07001139tsi_result tsi_ssl_client_handshaker_factory_create_handshaker(
1140 tsi_ssl_client_handshaker_factory *self, const char *server_name_indication,
Craig Tillera82950e2015-09-22 12:33:20 -07001141 tsi_handshaker **handshaker) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001142 return create_tsi_ssl_handshaker(self->ssl_context, 1, server_name_indication,
Craig Tillera82950e2015-09-22 12:33:20 -07001143 handshaker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001144}
1145
Julien Boeuf935d02e2017-04-09 00:07:09 -07001146void tsi_ssl_client_handshaker_factory_destroy(
1147 tsi_ssl_client_handshaker_factory *self) {
1148 if (self->ssl_context != NULL) SSL_CTX_free(self->ssl_context);
1149 if (self->alpn_protocol_list != NULL) gpr_free(self->alpn_protocol_list);
1150 gpr_free(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001151}
1152
Craig Tillera82950e2015-09-22 12:33:20 -07001153static int client_handshaker_factory_npn_callback(SSL *ssl, unsigned char **out,
1154 unsigned char *outlen,
1155 const unsigned char *in,
1156 unsigned int inlen,
1157 void *arg) {
1158 tsi_ssl_client_handshaker_factory *factory =
1159 (tsi_ssl_client_handshaker_factory *)arg;
1160 return select_protocol_list((const unsigned char **)out, outlen,
1161 factory->alpn_protocol_list,
1162 factory->alpn_protocol_list_length, in, inlen);
Julien Boeufd1531322015-06-18 11:05:39 +02001163}
1164
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001165/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
1166
Julien Boeuf935d02e2017-04-09 00:07:09 -07001167tsi_result tsi_ssl_server_handshaker_factory_create_handshaker(
1168 tsi_ssl_server_handshaker_factory *self, tsi_handshaker **handshaker) {
1169 if (self->ssl_context_count == 0) return TSI_INVALID_ARGUMENT;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001170 /* Create the handshaker with the first context. We will switch if needed
1171 because of SNI in ssl_server_handshaker_factory_servername_callback. */
Julien Boeuf935d02e2017-04-09 00:07:09 -07001172 return create_tsi_ssl_handshaker(self->ssl_contexts[0], 0, NULL, handshaker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001173}
1174
Julien Boeuf935d02e2017-04-09 00:07:09 -07001175void tsi_ssl_server_handshaker_factory_destroy(
1176 tsi_ssl_server_handshaker_factory *self) {
Julien Boeufb222b4d2015-01-15 17:01:39 -08001177 size_t i;
Julien Boeuf935d02e2017-04-09 00:07:09 -07001178 for (i = 0; i < self->ssl_context_count; i++) {
1179 if (self->ssl_contexts[i] != NULL) {
1180 SSL_CTX_free(self->ssl_contexts[i]);
1181 tsi_peer_destruct(&self->ssl_context_x509_subject_names[i]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001182 }
Craig Tillera82950e2015-09-22 12:33:20 -07001183 }
Julien Boeuf935d02e2017-04-09 00:07:09 -07001184 if (self->ssl_contexts != NULL) gpr_free(self->ssl_contexts);
1185 if (self->ssl_context_x509_subject_names != NULL) {
1186 gpr_free(self->ssl_context_x509_subject_names);
Craig Tillera82950e2015-09-22 12:33:20 -07001187 }
Julien Boeuf935d02e2017-04-09 00:07:09 -07001188 if (self->alpn_protocol_list != NULL) gpr_free(self->alpn_protocol_list);
1189 gpr_free(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001190}
1191
Craig Tillera82950e2015-09-22 12:33:20 -07001192static int does_entry_match_name(const char *entry, size_t entry_length,
1193 const char *name) {
Craig Tiller45724b32015-09-22 10:42:19 -07001194 const char *dot;
1195 const char *name_subdomain = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -07001196 size_t name_length = strlen(name);
Julien Boeuf9fff77e2015-02-24 16:50:35 -08001197 size_t name_subdomain_length;
Craig Tillera82950e2015-09-22 12:33:20 -07001198 if (entry_length == 0) return 0;
Julien Boeuf9fff77e2015-02-24 16:50:35 -08001199
1200 /* Take care of '.' terminations. */
Craig Tillera82950e2015-09-22 12:33:20 -07001201 if (name[name_length - 1] == '.') {
1202 name_length--;
1203 }
1204 if (entry[entry_length - 1] == '.') {
1205 entry_length--;
1206 if (entry_length == 0) return 0;
1207 }
Julien Boeuf9fff77e2015-02-24 16:50:35 -08001208
Craig Tillera82950e2015-09-22 12:33:20 -07001209 if ((name_length == entry_length) &&
1210 strncmp(name, entry, entry_length) == 0) {
1211 return 1; /* Perfect match. */
1212 }
1213 if (entry[0] != '*') return 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001214
1215 /* Wildchar subdomain matching. */
Craig Tillera82950e2015-09-22 12:33:20 -07001216 if (entry_length < 3 || entry[1] != '.') { /* At least *.x */
1217 gpr_log(GPR_ERROR, "Invalid wildchar entry.");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001218 return 0;
Craig Tillera82950e2015-09-22 12:33:20 -07001219 }
1220 name_subdomain = strchr(name, '.');
1221 if (name_subdomain == NULL) return 0;
1222 name_subdomain_length = strlen(name_subdomain);
1223 if (name_subdomain_length < 2) return 0;
1224 name_subdomain++; /* Starts after the dot. */
Julien Boeuf0170a6c2015-02-24 18:08:01 -08001225 name_subdomain_length--;
Craig Tillera82950e2015-09-22 12:33:20 -07001226 entry += 2; /* Remove *. */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001227 entry_length -= 2;
Craig Tillera82950e2015-09-22 12:33:20 -07001228 dot = strchr(name_subdomain, '.');
1229 if ((dot == NULL) || (dot == &name_subdomain[name_subdomain_length - 1])) {
1230 gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain);
1231 return 0;
1232 }
1233 if (name_subdomain[name_subdomain_length - 1] == '.') {
1234 name_subdomain_length--;
1235 }
1236 return ((entry_length > 0) && (name_subdomain_length == entry_length) &&
1237 strncmp(entry, name_subdomain, entry_length) == 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001238}
1239
Craig Tillera82950e2015-09-22 12:33:20 -07001240static int ssl_server_handshaker_factory_servername_callback(SSL *ssl, int *ap,
1241 void *arg) {
1242 tsi_ssl_server_handshaker_factory *impl =
1243 (tsi_ssl_server_handshaker_factory *)arg;
Julien Boeufb222b4d2015-01-15 17:01:39 -08001244 size_t i = 0;
Craig Tillera82950e2015-09-22 12:33:20 -07001245 const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
1246 if (servername == NULL || strlen(servername) == 0) {
1247 return SSL_TLSEXT_ERR_NOACK;
1248 }
Craig Tiller45724b32015-09-22 10:42:19 -07001249
Craig Tillera82950e2015-09-22 12:33:20 -07001250 for (i = 0; i < impl->ssl_context_count; i++) {
1251 if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i],
1252 servername)) {
1253 SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]);
1254 return SSL_TLSEXT_ERR_OK;
Craig Tiller45724b32015-09-22 10:42:19 -07001255 }
Craig Tillera82950e2015-09-22 12:33:20 -07001256 }
1257 gpr_log(GPR_ERROR, "No match found for server name: %s.", servername);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001258 return SSL_TLSEXT_ERR_ALERT_WARNING;
1259}
1260
Julien Boeufd1531322015-06-18 11:05:39 +02001261#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001262static int server_handshaker_factory_alpn_callback(
1263 SSL *ssl, const unsigned char **out, unsigned char *outlen,
1264 const unsigned char *in, unsigned int inlen, void *arg) {
1265 tsi_ssl_server_handshaker_factory *factory =
1266 (tsi_ssl_server_handshaker_factory *)arg;
1267 return select_protocol_list(out, outlen, in, inlen,
1268 factory->alpn_protocol_list,
1269 factory->alpn_protocol_list_length);
Julien Boeufd1531322015-06-18 11:05:39 +02001270}
1271#endif /* TSI_OPENSSL_ALPN_SUPPORT */
1272
Craig Tillera82950e2015-09-22 12:33:20 -07001273static int server_handshaker_factory_npn_advertised_callback(
1274 SSL *ssl, const unsigned char **out, unsigned int *outlen, void *arg) {
1275 tsi_ssl_server_handshaker_factory *factory =
1276 (tsi_ssl_server_handshaker_factory *)arg;
Julien Boeufd1531322015-06-18 11:05:39 +02001277 *out = factory->alpn_protocol_list;
Craig Tillera82950e2015-09-22 12:33:20 -07001278 GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX);
1279 *outlen = (unsigned int)factory->alpn_protocol_list_length;
Julien Boeufd1531322015-06-18 11:05:39 +02001280 return SSL_TLSEXT_ERR_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001281}
1282
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001283/* --- tsi_ssl_handshaker_factory constructors. --- */
1284
Craig Tillera82950e2015-09-22 12:33:20 -07001285tsi_result tsi_create_ssl_client_handshaker_factory(
Julien Boeufb71ef652017-04-12 21:44:49 -07001286 const tsi_ssl_pem_key_cert_pair *pem_key_cert_pair,
1287 const char *pem_root_certs, const char *cipher_suites,
1288 const char **alpn_protocols, uint16_t num_alpn_protocols,
Julien Boeuf935d02e2017-04-09 00:07:09 -07001289 tsi_ssl_client_handshaker_factory **factory) {
Craig Tiller45724b32015-09-22 10:42:19 -07001290 SSL_CTX *ssl_context = NULL;
1291 tsi_ssl_client_handshaker_factory *impl = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001292 tsi_result result = TSI_OK;
1293
Craig Tillera82950e2015-09-22 12:33:20 -07001294 gpr_once_init(&init_openssl_once, init_openssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001295
Craig Tillera82950e2015-09-22 12:33:20 -07001296 if (factory == NULL) return TSI_INVALID_ARGUMENT;
Craig Tiller45724b32015-09-22 10:42:19 -07001297 *factory = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -07001298 if (pem_root_certs == NULL) return TSI_INVALID_ARGUMENT;
1299
1300 ssl_context = SSL_CTX_new(TLSv1_2_method());
1301 if (ssl_context == NULL) {
1302 gpr_log(GPR_ERROR, "Could not create ssl context.");
Craig Tiller45724b32015-09-22 10:42:19 -07001303 return TSI_INVALID_ARGUMENT;
Craig Tillera82950e2015-09-22 12:33:20 -07001304 }
Julien Boeufd1531322015-06-18 11:05:39 +02001305
Craig Tiller6f417882017-02-16 14:09:39 -08001306 impl = gpr_zalloc(sizeof(*impl));
Julien Boeufd1531322015-06-18 11:05:39 +02001307 impl->ssl_context = ssl_context;
1308
Craig Tillera82950e2015-09-22 12:33:20 -07001309 do {
1310 result =
Julien Boeufb71ef652017-04-12 21:44:49 -07001311 populate_ssl_context(ssl_context, pem_key_cert_pair, cipher_suites);
Craig Tillera82950e2015-09-22 12:33:20 -07001312 if (result != TSI_OK) break;
1313 result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs,
Julien Boeufb71ef652017-04-12 21:44:49 -07001314 strlen(pem_root_certs), NULL);
Craig Tillera82950e2015-09-22 12:33:20 -07001315 if (result != TSI_OK) {
1316 gpr_log(GPR_ERROR, "Cannot load server root certificates.");
1317 break;
1318 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001319
Craig Tillera82950e2015-09-22 12:33:20 -07001320 if (num_alpn_protocols != 0) {
Julien Boeufb71ef652017-04-12 21:44:49 -07001321 result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols,
1322 &impl->alpn_protocol_list,
1323 &impl->alpn_protocol_list_length);
Craig Tillera82950e2015-09-22 12:33:20 -07001324 if (result != TSI_OK) {
1325 gpr_log(GPR_ERROR, "Building alpn list failed with error %s.",
1326 tsi_result_to_string(result));
1327 break;
1328 }
Julien Boeufd1531322015-06-18 11:05:39 +02001329#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001330 GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX);
1331 if (SSL_CTX_set_alpn_protos(
1332 ssl_context, impl->alpn_protocol_list,
1333 (unsigned int)impl->alpn_protocol_list_length)) {
1334 gpr_log(GPR_ERROR, "Could not set alpn protocol list to context.");
1335 result = TSI_INVALID_ARGUMENT;
1336 break;
1337 }
Julien Boeufd1531322015-06-18 11:05:39 +02001338#endif /* TSI_OPENSSL_ALPN_SUPPORT */
Craig Tillera82950e2015-09-22 12:33:20 -07001339 SSL_CTX_set_next_proto_select_cb(
1340 ssl_context, client_handshaker_factory_npn_callback, impl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001341 }
Craig Tillera82950e2015-09-22 12:33:20 -07001342 } while (0);
1343 if (result != TSI_OK) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001344 tsi_ssl_client_handshaker_factory_destroy(impl);
Craig Tillera82950e2015-09-22 12:33:20 -07001345 return result;
1346 }
1347 SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, NULL);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001348 /* TODO(jboeuf): Add revocation verification. */
1349
Julien Boeuf935d02e2017-04-09 00:07:09 -07001350 *factory = impl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001351 return TSI_OK;
1352}
1353
Craig Tillera82950e2015-09-22 12:33:20 -07001354tsi_result tsi_create_ssl_server_handshaker_factory(
Julien Boeufb71ef652017-04-12 21:44:49 -07001355 const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs,
1356 size_t num_key_cert_pairs, const char *pem_client_root_certs,
1357 int force_client_auth, const char *cipher_suites,
1358 const char **alpn_protocols, uint16_t num_alpn_protocols,
Julien Boeuf935d02e2017-04-09 00:07:09 -07001359 tsi_ssl_server_handshaker_factory **factory) {
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001360 return tsi_create_ssl_server_handshaker_factory_ex(
Julien Boeufb71ef652017-04-12 21:44:49 -07001361 pem_key_cert_pairs, num_key_cert_pairs, pem_client_root_certs,
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001362 force_client_auth ? TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
1363 : TSI_DONT_REQUEST_CLIENT_CERTIFICATE,
Julien Boeufb71ef652017-04-12 21:44:49 -07001364 cipher_suites, alpn_protocols, num_alpn_protocols, factory);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001365}
1366
1367tsi_result tsi_create_ssl_server_handshaker_factory_ex(
Julien Boeufb71ef652017-04-12 21:44:49 -07001368 const tsi_ssl_pem_key_cert_pair *pem_key_cert_pairs,
1369 size_t num_key_cert_pairs, const char *pem_client_root_certs,
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001370 tsi_client_certificate_request_type client_certificate_request,
Julien Boeufb71ef652017-04-12 21:44:49 -07001371 const char *cipher_suites, const char **alpn_protocols,
1372 uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory **factory) {
Craig Tiller45724b32015-09-22 10:42:19 -07001373 tsi_ssl_server_handshaker_factory *impl = NULL;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001374 tsi_result result = TSI_OK;
Julien Boeufb222b4d2015-01-15 17:01:39 -08001375 size_t i = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001376
Craig Tillera82950e2015-09-22 12:33:20 -07001377 gpr_once_init(&init_openssl_once, init_openssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001378
Craig Tillera82950e2015-09-22 12:33:20 -07001379 if (factory == NULL) return TSI_INVALID_ARGUMENT;
Craig Tiller45724b32015-09-22 10:42:19 -07001380 *factory = NULL;
Julien Boeufb71ef652017-04-12 21:44:49 -07001381 if (num_key_cert_pairs == 0 || pem_key_cert_pairs == NULL) {
Craig Tillera82950e2015-09-22 12:33:20 -07001382 return TSI_INVALID_ARGUMENT;
1383 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001384
Craig Tiller6f417882017-02-16 14:09:39 -08001385 impl = gpr_zalloc(sizeof(*impl));
Julien Boeufb71ef652017-04-12 21:44:49 -07001386 impl->ssl_contexts = gpr_zalloc(num_key_cert_pairs * sizeof(SSL_CTX *));
Craig Tillera82950e2015-09-22 12:33:20 -07001387 impl->ssl_context_x509_subject_names =
Julien Boeufb71ef652017-04-12 21:44:49 -07001388 gpr_zalloc(num_key_cert_pairs * sizeof(tsi_peer));
Craig Tillera82950e2015-09-22 12:33:20 -07001389 if (impl->ssl_contexts == NULL ||
1390 impl->ssl_context_x509_subject_names == NULL) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001391 tsi_ssl_server_handshaker_factory_destroy(impl);
Craig Tillera82950e2015-09-22 12:33:20 -07001392 return TSI_OUT_OF_RESOURCES;
1393 }
Julien Boeufb71ef652017-04-12 21:44:49 -07001394 impl->ssl_context_count = num_key_cert_pairs;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001395
Craig Tillera82950e2015-09-22 12:33:20 -07001396 if (num_alpn_protocols > 0) {
Julien Boeufb71ef652017-04-12 21:44:49 -07001397 result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols,
1398 &impl->alpn_protocol_list,
1399 &impl->alpn_protocol_list_length);
Craig Tillera82950e2015-09-22 12:33:20 -07001400 if (result != TSI_OK) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001401 tsi_ssl_server_handshaker_factory_destroy(impl);
Craig Tillera82950e2015-09-22 12:33:20 -07001402 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001403 }
Craig Tillera82950e2015-09-22 12:33:20 -07001404 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001405
Julien Boeufb71ef652017-04-12 21:44:49 -07001406 for (i = 0; i < num_key_cert_pairs; i++) {
Craig Tillera82950e2015-09-22 12:33:20 -07001407 do {
1408 impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
1409 if (impl->ssl_contexts[i] == NULL) {
1410 gpr_log(GPR_ERROR, "Could not create ssl context.");
1411 result = TSI_OUT_OF_RESOURCES;
1412 break;
1413 }
Julien Boeufb71ef652017-04-12 21:44:49 -07001414 result = populate_ssl_context(impl->ssl_contexts[i],
1415 &pem_key_cert_pairs[i], cipher_suites);
Craig Tillera82950e2015-09-22 12:33:20 -07001416 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001417
Craig Tillera82950e2015-09-22 12:33:20 -07001418 if (pem_client_root_certs != NULL) {
Craig Tillera82950e2015-09-22 12:33:20 -07001419 STACK_OF(X509_NAME) *root_names = NULL;
1420 result = ssl_ctx_load_verification_certs(
1421 impl->ssl_contexts[i], pem_client_root_certs,
Julien Boeufb71ef652017-04-12 21:44:49 -07001422 strlen(pem_client_root_certs), &root_names);
Craig Tillera82950e2015-09-22 12:33:20 -07001423 if (result != TSI_OK) {
1424 gpr_log(GPR_ERROR, "Invalid verification certs.");
1425 break;
1426 }
1427 SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001428 switch (client_certificate_request) {
1429 case TSI_DONT_REQUEST_CLIENT_CERTIFICATE:
1430 SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_NONE, NULL);
1431 break;
1432 case TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
1433 SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER,
1434 NullVerifyCallback);
1435 break;
1436 case TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
1437 SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, NULL);
1438 break;
1439 case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
1440 SSL_CTX_set_verify(
1441 impl->ssl_contexts[i],
1442 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1443 NullVerifyCallback);
1444 break;
1445 case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
1446 SSL_CTX_set_verify(
1447 impl->ssl_contexts[i],
1448 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
1449 break;
1450 }
Craig Tillera82950e2015-09-22 12:33:20 -07001451 /* TODO(jboeuf): Add revocation verification. */
1452 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001453
Craig Tillera82950e2015-09-22 12:33:20 -07001454 result = extract_x509_subject_names_from_pem_cert(
Julien Boeufb71ef652017-04-12 21:44:49 -07001455 pem_key_cert_pairs[i].cert_chain,
Craig Tillera82950e2015-09-22 12:33:20 -07001456 &impl->ssl_context_x509_subject_names[i]);
1457 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001458
Craig Tillera82950e2015-09-22 12:33:20 -07001459 SSL_CTX_set_tlsext_servername_callback(
1460 impl->ssl_contexts[i],
1461 ssl_server_handshaker_factory_servername_callback);
1462 SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl);
Julien Boeufd1531322015-06-18 11:05:39 +02001463#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001464 SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i],
1465 server_handshaker_factory_alpn_callback, impl);
Julien Boeufd1531322015-06-18 11:05:39 +02001466#endif /* TSI_OPENSSL_ALPN_SUPPORT */
Craig Tillera82950e2015-09-22 12:33:20 -07001467 SSL_CTX_set_next_protos_advertised_cb(
1468 impl->ssl_contexts[i],
1469 server_handshaker_factory_npn_advertised_callback, impl);
1470 } while (0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001471
Craig Tillera82950e2015-09-22 12:33:20 -07001472 if (result != TSI_OK) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001473 tsi_ssl_server_handshaker_factory_destroy(impl);
Craig Tillera82950e2015-09-22 12:33:20 -07001474 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001475 }
Craig Tillera82950e2015-09-22 12:33:20 -07001476 }
Julien Boeuf935d02e2017-04-09 00:07:09 -07001477 *factory = impl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001478 return TSI_OK;
1479}
1480
1481/* --- tsi_ssl utils. --- */
1482
Craig Tillera82950e2015-09-22 12:33:20 -07001483int tsi_ssl_peer_matches_name(const tsi_peer *peer, const char *name) {
Julien Boeufb222b4d2015-01-15 17:01:39 -08001484 size_t i = 0;
Julien Boeuf597a4f22015-02-23 15:57:14 -08001485 size_t san_count = 0;
Craig Tiller45724b32015-09-22 10:42:19 -07001486 const tsi_peer_property *cn_property = NULL;
Paul Querna47d841d2016-03-10 11:19:17 -08001487 int like_ip = looks_like_ip_address(name);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001488
Julien Boeuf597a4f22015-02-23 15:57:14 -08001489 /* Check the SAN first. */
Craig Tillera82950e2015-09-22 12:33:20 -07001490 for (i = 0; i < peer->property_count; i++) {
1491 const tsi_peer_property *property = &peer->properties[i];
1492 if (property->name == NULL) continue;
1493 if (strcmp(property->name,
1494 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
1495 san_count++;
Paul Querna47d841d2016-03-10 11:19:17 -08001496
1497 if (!like_ip && does_entry_match_name(property->value.data,
1498 property->value.length, name)) {
1499 return 1;
1500 } else if (like_ip &&
1501 strncmp(name, property->value.data, property->value.length) ==
1502 0 &&
1503 strlen(name) == property->value.length) {
1504 /* IP Addresses are exact matches only. */
Craig Tillera82950e2015-09-22 12:33:20 -07001505 return 1;
1506 }
1507 } else if (strcmp(property->name,
1508 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
1509 cn_property = property;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001510 }
Craig Tillera82950e2015-09-22 12:33:20 -07001511 }
Julien Boeuf597a4f22015-02-23 15:57:14 -08001512
Paul Querna47d841d2016-03-10 11:19:17 -08001513 /* If there's no SAN, try the CN, but only if its not like an IP Address */
1514 if (san_count == 0 && cn_property != NULL && !like_ip) {
Craig Tillera82950e2015-09-22 12:33:20 -07001515 if (does_entry_match_name(cn_property->value.data,
1516 cn_property->value.length, name)) {
1517 return 1;
Julien Boeuf597a4f22015-02-23 15:57:14 -08001518 }
Craig Tillera82950e2015-09-22 12:33:20 -07001519 }
Julien Boeuf597a4f22015-02-23 15:57:14 -08001520
Craig Tillera82950e2015-09-22 12:33:20 -07001521 return 0; /* Not found. */
Craig Tiller190d3602015-02-18 09:23:38 -08001522}