blob: f1fff043bd1e045902aa9b41b1bae200963ad608 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080016 *
17 */
18
Craig Tillerb29f1fe2017-03-28 15:49:23 -070019#include "src/core/tsi/ssl_transport_security.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080020
Paul Querna47d841d2016-03-10 11:19:17 -080021#include <grpc/support/port_platform.h>
22
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080023#include <limits.h>
Julien Boeuf330f4c82015-04-27 10:37:42 -070024#include <string.h>
Paul Querna27df6892016-03-13 13:34:27 -070025
Nicolas "Pixel" Noblee3df5a02016-10-27 00:41:13 +020026/* TODO(jboeuf): refactor inet_ntop into a portability header. */
27/* Note: for whomever reads this and tries to refactor this, this
28 can't be in grpc, it has to be in gpr. */
29#ifdef GPR_WINDOWS
30#include <ws2tcpip.h>
31#else
32#include <arpa/inet.h>
Mehrdad Afsharif5839752017-04-18 10:26:40 -070033#include <sys/socket.h>
Nicolas "Pixel" Noblee3df5a02016-10-27 00:41:13 +020034#endif
35
Nicolas "Pixel" Nobleb29d8cf2016-04-08 01:38:29 +020036#include <grpc/support/alloc.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080037#include <grpc/support/log.h>
nnoble8a23a3d2014-12-16 10:10:29 -080038#include <grpc/support/sync.h>
Julien Boeuf4a0a3942015-02-03 15:04:45 -080039#include <grpc/support/thd.h>
Nicolas "Pixel" Noble213ed912015-01-30 02:11:35 +010040#include <grpc/support/useful.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080041
Yash Tibrewal15ce1422017-09-25 17:46:32 -070042extern "C" {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080043#include <openssl/bio.h>
Craig Tillera82950e2015-09-22 12:33:20 -070044#include <openssl/crypto.h> /* For OPENSSL_free */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080045#include <openssl/err.h>
46#include <openssl/ssl.h>
47#include <openssl/x509.h>
48#include <openssl/x509v3.h>
Yash Tibrewal15ce1422017-09-25 17:46:32 -070049}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080050
Craig Tillerb29f1fe2017-03-28 15:49:23 -070051#include "src/core/tsi/ssl_types.h"
52#include "src/core/tsi/transport_security.h"
Craig Tiller0fe5ee72015-12-22 12:50:36 -080053
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080054/* --- Constants. ---*/
55
56#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384
57#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024
58
Julien Boeuf3e29de12015-06-18 23:29:13 +020059/* Putting a macro like this and littering the source file with #if is really
60 bad practice.
61 TODO(jboeuf): refactor all the #if / #endif in a separate module. */
Julien Boeufd1531322015-06-18 11:05:39 +020062#ifndef TSI_OPENSSL_ALPN_SUPPORT
63#define TSI_OPENSSL_ALPN_SUPPORT 1
64#endif
65
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080066/* TODO(jboeuf): I have not found a way to get this number dynamically from the
Julien Boeuf3e29de12015-06-18 23:29:13 +020067 SSL structure. This is what we would ultimately want though... */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080068#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
69
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080070/* --- Structure definitions. ---*/
71
Justin Burke49841352017-08-31 17:42:54 -070072struct tsi_ssl_handshaker_factory {
Craig Tillerbaa14a92017-11-03 09:09:36 -070073 const tsi_ssl_handshaker_factory_vtable* vtable;
Justin Burke49841352017-08-31 17:42:54 -070074 gpr_refcount refcount;
75};
76
Julien Boeuf935d02e2017-04-09 00:07:09 -070077struct tsi_ssl_client_handshaker_factory {
Justin Burke49841352017-08-31 17:42:54 -070078 tsi_ssl_handshaker_factory base;
Craig Tillerbaa14a92017-11-03 09:09:36 -070079 SSL_CTX* ssl_context;
80 unsigned char* alpn_protocol_list;
Julien Boeufd1531322015-06-18 11:05:39 +020081 size_t alpn_protocol_list_length;
Julien Boeuf935d02e2017-04-09 00:07:09 -070082};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080083
Julien Boeuf935d02e2017-04-09 00:07:09 -070084struct tsi_ssl_server_handshaker_factory {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080085 /* Several contexts to support SNI.
86 The tsi_peer array contains the subject names of the server certificates
87 associated with the contexts at the same index. */
Justin Burke49841352017-08-31 17:42:54 -070088 tsi_ssl_handshaker_factory base;
Craig Tillerbaa14a92017-11-03 09:09:36 -070089 SSL_CTX** ssl_contexts;
90 tsi_peer* ssl_context_x509_subject_names;
Julien Boeufb222b4d2015-01-15 17:01:39 -080091 size_t ssl_context_count;
Craig Tillerbaa14a92017-11-03 09:09:36 -070092 unsigned char* alpn_protocol_list;
Julien Boeufb222b4d2015-01-15 17:01:39 -080093 size_t alpn_protocol_list_length;
Julien Boeuf935d02e2017-04-09 00:07:09 -070094};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080095
Craig Tillera82950e2015-09-22 12:33:20 -070096typedef struct {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080097 tsi_handshaker base;
Craig Tillerbaa14a92017-11-03 09:09:36 -070098 SSL* ssl;
99 BIO* into_ssl;
100 BIO* from_ssl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800101 tsi_result result;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700102 tsi_ssl_handshaker_factory* factory_ref;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800103} tsi_ssl_handshaker;
104
Craig Tillera82950e2015-09-22 12:33:20 -0700105typedef struct {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800106 tsi_frame_protector base;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700107 SSL* ssl;
108 BIO* into_ssl;
109 BIO* from_ssl;
110 unsigned char* buffer;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800111 size_t buffer_size;
112 size_t buffer_offset;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800113} tsi_ssl_frame_protector;
114
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800115/* --- Library Initialization. ---*/
116
nnoble8a23a3d2014-12-16 10:10:29 -0800117static gpr_once init_openssl_once = GPR_ONCE_INIT;
Craig Tiller4782d922017-11-10 09:53:21 -0800118static gpr_mu* openssl_mutexes = nullptr;
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800119
Craig Tillerbaa14a92017-11-03 09:09:36 -0700120static void openssl_locking_cb(int mode, int type, const char* file, int line) {
Craig Tillera82950e2015-09-22 12:33:20 -0700121 if (mode & CRYPTO_LOCK) {
122 gpr_mu_lock(&openssl_mutexes[type]);
123 } else {
124 gpr_mu_unlock(&openssl_mutexes[type]);
125 }
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800126}
127
Craig Tillera82950e2015-09-22 12:33:20 -0700128static unsigned long openssl_thread_id_cb(void) {
129 return (unsigned long)gpr_thd_currentid();
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800130}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800131
Craig Tillera82950e2015-09-22 12:33:20 -0700132static void init_openssl(void) {
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800133 int i;
Craig Tiller3121fd42015-09-10 09:56:20 -0700134 int num_locks;
Craig Tillera82950e2015-09-22 12:33:20 -0700135 SSL_library_init();
136 SSL_load_error_strings();
137 OpenSSL_add_all_algorithms();
138 num_locks = CRYPTO_num_locks();
139 GPR_ASSERT(num_locks > 0);
Craig Tillerbaa14a92017-11-03 09:09:36 -0700140 openssl_mutexes = (gpr_mu*)gpr_malloc((size_t)num_locks * sizeof(gpr_mu));
Craig Tillera82950e2015-09-22 12:33:20 -0700141 for (i = 0; i < CRYPTO_num_locks(); i++) {
142 gpr_mu_init(&openssl_mutexes[i]);
143 }
144 CRYPTO_set_locking_callback(openssl_locking_cb);
145 CRYPTO_set_id_callback(openssl_thread_id_cb);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800146}
147
148/* --- Ssl utils. ---*/
149
Craig Tillerbaa14a92017-11-03 09:09:36 -0700150static const char* ssl_error_string(int error) {
Craig Tillera82950e2015-09-22 12:33:20 -0700151 switch (error) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800152 case SSL_ERROR_NONE:
153 return "SSL_ERROR_NONE";
154 case SSL_ERROR_ZERO_RETURN:
155 return "SSL_ERROR_ZERO_RETURN";
156 case SSL_ERROR_WANT_READ:
157 return "SSL_ERROR_WANT_READ";
158 case SSL_ERROR_WANT_WRITE:
159 return "SSL_ERROR_WANT_WRITE";
160 case SSL_ERROR_WANT_CONNECT:
161 return "SSL_ERROR_WANT_CONNECT";
162 case SSL_ERROR_WANT_ACCEPT:
163 return "SSL_ERROR_WANT_ACCEPT";
164 case SSL_ERROR_WANT_X509_LOOKUP:
165 return "SSL_ERROR_WANT_X509_LOOKUP";
166 case SSL_ERROR_SYSCALL:
167 return "SSL_ERROR_SYSCALL";
168 case SSL_ERROR_SSL:
169 return "SSL_ERROR_SSL";
170 default:
171 return "Unknown error";
Craig Tillera82950e2015-09-22 12:33:20 -0700172 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800173}
174
175/* TODO(jboeuf): Remove when we are past the debugging phase with this code. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700176static void ssl_log_where_info(const SSL* ssl, int where, int flag,
177 const char* msg) {
Craig Tiller84f75d42017-05-03 13:06:35 -0700178 if ((where & flag) && GRPC_TRACER_ON(tsi_tracing_enabled)) {
Craig Tillera82950e2015-09-22 12:33:20 -0700179 gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg,
180 SSL_state_string_long(ssl), SSL_state_string(ssl));
181 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800182}
183
184/* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700185static void ssl_info_callback(const SSL* ssl, int where, int ret) {
Craig Tillera82950e2015-09-22 12:33:20 -0700186 if (ret == 0) {
187 gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n");
188 return;
189 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800190
Craig Tillera82950e2015-09-22 12:33:20 -0700191 ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP");
192 ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START");
193 ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800194}
195
Julien Boeuf0170a6c2015-02-24 18:08:01 -0800196/* Returns 1 if name looks like an IP address, 0 otherwise.
Paul Querna4a9e7c42016-03-13 14:00:11 -0700197 This is a very rough heuristic, and only handles IPv6 in hexadecimal form. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700198static int looks_like_ip_address(const char* name) {
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800199 size_t i;
200 size_t dot_count = 0;
201 size_t num_size = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700202 for (i = 0; i < strlen(name); i++) {
Paul Querna4a9e7c42016-03-13 14:00:11 -0700203 if (name[i] == ':') {
204 /* IPv6 Address in hexadecimal form, : is not allowed in DNS names. */
205 return 1;
206 }
Craig Tillera82950e2015-09-22 12:33:20 -0700207 if (name[i] >= '0' && name[i] <= '9') {
208 if (num_size > 3) return 0;
209 num_size++;
210 } else if (name[i] == '.') {
211 if (dot_count > 3 || num_size == 0) return 0;
212 dot_count++;
213 num_size = 0;
214 } else {
215 return 0;
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800216 }
Craig Tillera82950e2015-09-22 12:33:20 -0700217 }
218 if (dot_count < 3 || num_size == 0) return 0;
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800219 return 1;
220}
221
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800222/* Gets the subject CN from an X509 cert. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700223static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8,
224 size_t* utf8_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800225 int common_name_index = -1;
Craig Tiller4782d922017-11-10 09:53:21 -0800226 X509_NAME_ENTRY* common_name_entry = nullptr;
227 ASN1_STRING* common_name_asn1 = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700228 X509_NAME* subject_name = X509_get_subject_name(cert);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800229 int utf8_returned_size = 0;
Craig Tiller4782d922017-11-10 09:53:21 -0800230 if (subject_name == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700231 gpr_log(GPR_ERROR, "Could not get subject name from certificate.");
232 return TSI_NOT_FOUND;
233 }
234 common_name_index =
235 X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
236 if (common_name_index == -1) {
237 gpr_log(GPR_ERROR,
238 "Could not get common name of subject from certificate.");
239 return TSI_NOT_FOUND;
240 }
241 common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);
Craig Tiller4782d922017-11-10 09:53:21 -0800242 if (common_name_entry == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700243 gpr_log(GPR_ERROR, "Could not get common name entry from certificate.");
244 return TSI_INTERNAL_ERROR;
245 }
246 common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
Craig Tiller4782d922017-11-10 09:53:21 -0800247 if (common_name_asn1 == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700248 gpr_log(GPR_ERROR,
249 "Could not get common name entry asn1 from certificate.");
250 return TSI_INTERNAL_ERROR;
251 }
252 utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1);
253 if (utf8_returned_size < 0) {
254 gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string.");
255 return TSI_OUT_OF_RESOURCES;
256 }
257 *utf8_size = (size_t)utf8_returned_size;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800258 return TSI_OK;
259}
260
261/* Gets the subject CN of an X509 cert as a tsi_peer_property. */
Craig Tillera82950e2015-09-22 12:33:20 -0700262static tsi_result peer_property_from_x509_common_name(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700263 X509* cert, tsi_peer_property* property) {
264 unsigned char* common_name;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800265 size_t common_name_size;
Craig Tillera82950e2015-09-22 12:33:20 -0700266 tsi_result result =
267 ssl_get_x509_common_name(cert, &common_name, &common_name_size);
268 if (result != TSI_OK) {
269 if (result == TSI_NOT_FOUND) {
Craig Tiller4782d922017-11-10 09:53:21 -0800270 common_name = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -0700271 common_name_size = 0;
272 } else {
273 return result;
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800274 }
Craig Tillera82950e2015-09-22 12:33:20 -0700275 }
276 result = tsi_construct_string_peer_property(
277 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY,
Craig Tiller4782d922017-11-10 09:53:21 -0800278 common_name == nullptr ? "" : (const char*)common_name, common_name_size,
Craig Tillera82950e2015-09-22 12:33:20 -0700279 property);
280 OPENSSL_free(common_name);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800281 return result;
282}
283
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700284/* Gets the X509 cert in PEM format as a tsi_peer_property. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700285static tsi_result add_pem_certificate(X509* cert, tsi_peer_property* property) {
286 BIO* bio = BIO_new(BIO_s_mem());
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700287 if (!PEM_write_bio_X509(bio, cert)) {
288 BIO_free(bio);
289 return TSI_INTERNAL_ERROR;
290 }
Craig Tillerbaa14a92017-11-03 09:09:36 -0700291 char* contents;
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700292 long len = BIO_get_mem_data(bio, &contents);
293 if (len <= 0) {
294 BIO_free(bio);
295 return TSI_INTERNAL_ERROR;
296 }
297 tsi_result result = tsi_construct_string_peer_property(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700298 TSI_X509_PEM_CERT_PROPERTY, (const char*)contents, (size_t)len, property);
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700299 BIO_free(bio);
300 return result;
301}
302
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800303/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */
Craig Tillera82950e2015-09-22 12:33:20 -0700304static tsi_result add_subject_alt_names_properties_to_peer(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700305 tsi_peer* peer, GENERAL_NAMES* subject_alt_names,
Craig Tillera82950e2015-09-22 12:33:20 -0700306 size_t subject_alt_name_count) {
Craig Tiller3121fd42015-09-10 09:56:20 -0700307 size_t i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800308 tsi_result result = TSI_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800309
310 /* Reset for DNS entries filtering. */
Julien Boeuf77e8c1c2015-05-13 13:50:59 -0700311 peer->property_count -= subject_alt_name_count;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800312
Craig Tillera82950e2015-09-22 12:33:20 -0700313 for (i = 0; i < subject_alt_name_count; i++) {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700314 GENERAL_NAME* subject_alt_name =
Craig Tiller0fe5ee72015-12-22 12:50:36 -0800315 sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
Craig Tillera82950e2015-09-22 12:33:20 -0700316 /* Filter out the non-dns entries names. */
317 if (subject_alt_name->type == GEN_DNS) {
Craig Tiller4782d922017-11-10 09:53:21 -0800318 unsigned char* name = nullptr;
Paul Querna47d841d2016-03-10 11:19:17 -0800319 int name_size;
320 name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName);
321 if (name_size < 0) {
Craig Tillera82950e2015-09-22 12:33:20 -0700322 gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
323 result = TSI_INTERNAL_ERROR;
324 break;
325 }
326 result = tsi_construct_string_peer_property(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700327 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, (const char*)name,
Paul Querna47d841d2016-03-10 11:19:17 -0800328 (size_t)name_size, &peer->properties[peer->property_count++]);
329 OPENSSL_free(name);
330 } else if (subject_alt_name->type == GEN_IPADD) {
331 char ntop_buf[INET6_ADDRSTRLEN];
332 int af;
333
334 if (subject_alt_name->d.iPAddress->length == 4) {
335 af = AF_INET;
336 } else if (subject_alt_name->d.iPAddress->length == 16) {
337 af = AF_INET6;
338 } else {
339 gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP");
340 result = TSI_INTERNAL_ERROR;
341 break;
342 }
Craig Tillerbaa14a92017-11-03 09:09:36 -0700343 const char* name = inet_ntop(af, subject_alt_name->d.iPAddress->data,
Nicolas "Pixel" Noblee3df5a02016-10-27 00:41:13 +0200344 ntop_buf, INET6_ADDRSTRLEN);
Craig Tiller4782d922017-11-10 09:53:21 -0800345 if (name == nullptr) {
Paul Querna47d841d2016-03-10 11:19:17 -0800346 gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet.");
347 result = TSI_INTERNAL_ERROR;
348 break;
349 }
350
351 result = tsi_construct_string_peer_property_from_cstring(
352 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name,
Craig Tillera82950e2015-09-22 12:33:20 -0700353 &peer->properties[peer->property_count++]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800354 }
Paul Querna47d841d2016-03-10 11:19:17 -0800355 if (result != TSI_OK) break;
Craig Tillera82950e2015-09-22 12:33:20 -0700356 }
Julien Boeuf77e8c1c2015-05-13 13:50:59 -0700357 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800358}
359
360/* Gets information about the peer's X509 cert as a tsi_peer object. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700361static tsi_result peer_from_x509(X509* cert, int include_certificate_type,
362 tsi_peer* peer) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800363 /* TODO(jboeuf): Maybe add more properties. */
Craig Tillerbe98d242017-11-10 15:26:57 -0800364 GENERAL_NAMES* subject_alt_names = (GENERAL_NAMES*)X509_get_ext_d2i(
365 cert, NID_subject_alt_name, nullptr, nullptr);
Craig Tiller4782d922017-11-10 09:53:21 -0800366 int subject_alt_name_count = (subject_alt_names != nullptr)
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700367 ? (int)sk_GENERAL_NAME_num(subject_alt_names)
368 : 0;
Craig Tiller3121fd42015-09-10 09:56:20 -0700369 size_t property_count;
370 tsi_result result;
Craig Tillera82950e2015-09-22 12:33:20 -0700371 GPR_ASSERT(subject_alt_name_count >= 0);
372 property_count = (include_certificate_type ? (size_t)1 : 0) +
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700373 2 /* common name, certificate */ +
374 (size_t)subject_alt_name_count;
Craig Tillera82950e2015-09-22 12:33:20 -0700375 result = tsi_construct_peer(property_count, peer);
376 if (result != TSI_OK) return result;
377 do {
378 if (include_certificate_type) {
379 result = tsi_construct_string_peer_property_from_cstring(
380 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
381 &peer->properties[0]);
382 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800383 }
Craig Tillera82950e2015-09-22 12:33:20 -0700384 result = peer_property_from_x509_common_name(
385 cert, &peer->properties[include_certificate_type ? 1 : 0]);
386 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800387
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700388 result = add_pem_certificate(
389 cert, &peer->properties[include_certificate_type ? 2 : 1]);
390 if (result != TSI_OK) break;
391
Craig Tillera82950e2015-09-22 12:33:20 -0700392 if (subject_alt_name_count != 0) {
393 result = add_subject_alt_names_properties_to_peer(
394 peer, subject_alt_names, (size_t)subject_alt_name_count);
395 if (result != TSI_OK) break;
Craig Tiller45724b32015-09-22 10:42:19 -0700396 }
Craig Tillera82950e2015-09-22 12:33:20 -0700397 } while (0);
398
Craig Tiller4782d922017-11-10 09:53:21 -0800399 if (subject_alt_names != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700400 sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
401 }
402 if (result != TSI_OK) tsi_peer_destruct(peer);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800403 return result;
404}
405
nnoble0c475f02014-12-05 15:37:39 -0800406/* Logs the SSL error stack. */
Craig Tillera82950e2015-09-22 12:33:20 -0700407static void log_ssl_error_stack(void) {
nnoble0c475f02014-12-05 15:37:39 -0800408 unsigned long err;
Craig Tillera82950e2015-09-22 12:33:20 -0700409 while ((err = ERR_get_error()) != 0) {
410 char details[256];
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700411 ERR_error_string_n((uint32_t)err, details, sizeof(details));
Craig Tillera82950e2015-09-22 12:33:20 -0700412 gpr_log(GPR_ERROR, "%s", details);
413 }
nnoble0c475f02014-12-05 15:37:39 -0800414}
415
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800416/* Performs an SSL_read and handle errors. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700417static tsi_result do_ssl_read(SSL* ssl, unsigned char* unprotected_bytes,
418 size_t* unprotected_bytes_size) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700419 int read_from_ssl;
Craig Tillera82950e2015-09-22 12:33:20 -0700420 GPR_ASSERT(*unprotected_bytes_size <= INT_MAX);
421 read_from_ssl =
422 SSL_read(ssl, unprotected_bytes, (int)*unprotected_bytes_size);
Julien Boeufce91f4a2017-05-09 15:50:33 -0700423 if (read_from_ssl <= 0) {
Craig Tillera82950e2015-09-22 12:33:20 -0700424 read_from_ssl = SSL_get_error(ssl, read_from_ssl);
425 switch (read_from_ssl) {
Julien Boeufce91f4a2017-05-09 15:50:33 -0700426 case SSL_ERROR_ZERO_RETURN: /* Received a close_notify alert. */
427 case SSL_ERROR_WANT_READ: /* We need more data to finish the frame. */
Craig Tillera82950e2015-09-22 12:33:20 -0700428 *unprotected_bytes_size = 0;
429 return TSI_OK;
430 case SSL_ERROR_WANT_WRITE:
431 gpr_log(
432 GPR_ERROR,
433 "Peer tried to renegotiate SSL connection. This is unsupported.");
434 return TSI_UNIMPLEMENTED;
435 case SSL_ERROR_SSL:
436 gpr_log(GPR_ERROR, "Corruption detected.");
437 log_ssl_error_stack();
438 return TSI_DATA_CORRUPTED;
439 default:
440 gpr_log(GPR_ERROR, "SSL_read failed with error %s.",
441 ssl_error_string(read_from_ssl));
442 return TSI_PROTOCOL_FAILURE;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800443 }
Craig Tillera82950e2015-09-22 12:33:20 -0700444 }
445 *unprotected_bytes_size = (size_t)read_from_ssl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800446 return TSI_OK;
447}
448
449/* Performs an SSL_write and handle errors. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700450static tsi_result do_ssl_write(SSL* ssl, unsigned char* unprotected_bytes,
Craig Tillera82950e2015-09-22 12:33:20 -0700451 size_t unprotected_bytes_size) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700452 int ssl_write_result;
Craig Tillera82950e2015-09-22 12:33:20 -0700453 GPR_ASSERT(unprotected_bytes_size <= INT_MAX);
454 ssl_write_result =
455 SSL_write(ssl, unprotected_bytes, (int)unprotected_bytes_size);
456 if (ssl_write_result < 0) {
457 ssl_write_result = SSL_get_error(ssl, ssl_write_result);
458 if (ssl_write_result == SSL_ERROR_WANT_READ) {
459 gpr_log(GPR_ERROR,
460 "Peer tried to renegotiate SSL connection. This is unsupported.");
461 return TSI_UNIMPLEMENTED;
462 } else {
463 gpr_log(GPR_ERROR, "SSL_write failed with error %s.",
464 ssl_error_string(ssl_write_result));
465 return TSI_INTERNAL_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800466 }
Craig Tillera82950e2015-09-22 12:33:20 -0700467 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800468 return TSI_OK;
469}
470
471/* Loads an in-memory PEM certificate chain into the SSL context. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700472static tsi_result ssl_ctx_use_certificate_chain(SSL_CTX* context,
473 const char* pem_cert_chain,
Julien Boeufb71ef652017-04-12 21:44:49 -0700474 size_t pem_cert_chain_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800475 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -0800476 X509* certificate = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700477 BIO* pem;
Craig Tillera82950e2015-09-22 12:33:20 -0700478 GPR_ASSERT(pem_cert_chain_size <= INT_MAX);
Craig Tillerbaa14a92017-11-03 09:09:36 -0700479 pem = BIO_new_mem_buf((void*)pem_cert_chain, (int)pem_cert_chain_size);
Craig Tiller4782d922017-11-10 09:53:21 -0800480 if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800481
Craig Tillera82950e2015-09-22 12:33:20 -0700482 do {
Craig Tiller4782d922017-11-10 09:53:21 -0800483 certificate = PEM_read_bio_X509_AUX(pem, nullptr, nullptr, (void*)"");
484 if (certificate == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700485 result = TSI_INVALID_ARGUMENT;
486 break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800487 }
Craig Tillera82950e2015-09-22 12:33:20 -0700488 if (!SSL_CTX_use_certificate(context, certificate)) {
489 result = TSI_INVALID_ARGUMENT;
490 break;
491 }
492 while (1) {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700493 X509* certificate_authority =
Craig Tiller4782d922017-11-10 09:53:21 -0800494 PEM_read_bio_X509(pem, nullptr, nullptr, (void*)"");
495 if (certificate_authority == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700496 ERR_clear_error();
497 break; /* Done reading. */
498 }
499 if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) {
500 X509_free(certificate_authority);
501 result = TSI_INVALID_ARGUMENT;
502 break;
503 }
504 /* We don't need to free certificate_authority as its ownership has been
505 transfered to the context. That is not the case for certificate though.
506 */
507 }
508 } while (0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800509
Craig Tiller4782d922017-11-10 09:53:21 -0800510 if (certificate != nullptr) X509_free(certificate);
Craig Tillera82950e2015-09-22 12:33:20 -0700511 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800512 return result;
513}
514
515/* Loads an in-memory PEM private key into the SSL context. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700516static tsi_result ssl_ctx_use_private_key(SSL_CTX* context, const char* pem_key,
Craig Tillera82950e2015-09-22 12:33:20 -0700517 size_t pem_key_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800518 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -0800519 EVP_PKEY* private_key = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700520 BIO* pem;
Craig Tillera82950e2015-09-22 12:33:20 -0700521 GPR_ASSERT(pem_key_size <= INT_MAX);
Craig Tillerbaa14a92017-11-03 09:09:36 -0700522 pem = BIO_new_mem_buf((void*)pem_key, (int)pem_key_size);
Craig Tiller4782d922017-11-10 09:53:21 -0800523 if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
Craig Tillera82950e2015-09-22 12:33:20 -0700524 do {
Craig Tiller4782d922017-11-10 09:53:21 -0800525 private_key = PEM_read_bio_PrivateKey(pem, nullptr, nullptr, (void*)"");
526 if (private_key == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700527 result = TSI_INVALID_ARGUMENT;
528 break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800529 }
Craig Tillera82950e2015-09-22 12:33:20 -0700530 if (!SSL_CTX_use_PrivateKey(context, private_key)) {
531 result = TSI_INVALID_ARGUMENT;
532 break;
533 }
534 } while (0);
Craig Tiller4782d922017-11-10 09:53:21 -0800535 if (private_key != nullptr) EVP_PKEY_free(private_key);
Craig Tillera82950e2015-09-22 12:33:20 -0700536 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800537 return result;
538}
539
540/* Loads in-memory PEM verification certs into the SSL context and optionally
541 returns the verification cert names (root_names can be NULL). */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700542static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context,
543 const char* pem_roots,
Julien Boeufb71ef652017-04-12 21:44:49 -0700544 size_t pem_roots_size,
545 STACK_OF(X509_NAME) *
546 *root_names) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800547 tsi_result result = TSI_OK;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800548 size_t num_roots = 0;
Craig Tiller4782d922017-11-10 09:53:21 -0800549 X509* root = nullptr;
550 X509_NAME* root_name = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700551 BIO* pem;
552 X509_STORE* root_store;
Craig Tillera82950e2015-09-22 12:33:20 -0700553 GPR_ASSERT(pem_roots_size <= INT_MAX);
Craig Tillerbaa14a92017-11-03 09:09:36 -0700554 pem = BIO_new_mem_buf((void*)pem_roots, (int)pem_roots_size);
Craig Tillera82950e2015-09-22 12:33:20 -0700555 root_store = SSL_CTX_get_cert_store(context);
Craig Tiller4782d922017-11-10 09:53:21 -0800556 if (root_store == nullptr) return TSI_INVALID_ARGUMENT;
557 if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
558 if (root_names != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700559 *root_names = sk_X509_NAME_new_null();
Craig Tiller4782d922017-11-10 09:53:21 -0800560 if (*root_names == nullptr) return TSI_OUT_OF_RESOURCES;
Craig Tillera82950e2015-09-22 12:33:20 -0700561 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800562
Craig Tillera82950e2015-09-22 12:33:20 -0700563 while (1) {
Craig Tiller4782d922017-11-10 09:53:21 -0800564 root = PEM_read_bio_X509_AUX(pem, nullptr, nullptr, (void*)"");
565 if (root == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700566 ERR_clear_error();
567 break; /* We're at the end of stream. */
nnoble0c475f02014-12-05 15:37:39 -0800568 }
Craig Tiller4782d922017-11-10 09:53:21 -0800569 if (root_names != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700570 root_name = X509_get_subject_name(root);
Craig Tiller4782d922017-11-10 09:53:21 -0800571 if (root_name == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700572 gpr_log(GPR_ERROR, "Could not get name from root certificate.");
573 result = TSI_INVALID_ARGUMENT;
574 break;
575 }
576 root_name = X509_NAME_dup(root_name);
Craig Tiller4782d922017-11-10 09:53:21 -0800577 if (root_name == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700578 result = TSI_OUT_OF_RESOURCES;
579 break;
580 }
581 sk_X509_NAME_push(*root_names, root_name);
Craig Tiller4782d922017-11-10 09:53:21 -0800582 root_name = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -0700583 }
584 if (!X509_STORE_add_cert(root_store, root)) {
585 gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
586 result = TSI_INTERNAL_ERROR;
587 break;
588 }
589 X509_free(root);
590 num_roots++;
591 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800592
Craig Tillera82950e2015-09-22 12:33:20 -0700593 if (num_roots == 0) {
594 gpr_log(GPR_ERROR, "Could not load any root certificate.");
595 result = TSI_INVALID_ARGUMENT;
596 }
Craig Tiller45724b32015-09-22 10:42:19 -0700597
Craig Tillera82950e2015-09-22 12:33:20 -0700598 if (result != TSI_OK) {
Craig Tiller4782d922017-11-10 09:53:21 -0800599 if (root != nullptr) X509_free(root);
600 if (root_names != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700601 sk_X509_NAME_pop_free(*root_names, X509_NAME_free);
Craig Tiller4782d922017-11-10 09:53:21 -0800602 *root_names = nullptr;
603 if (root_name != nullptr) X509_NAME_free(root_name);
Craig Tiller45724b32015-09-22 10:42:19 -0700604 }
Craig Tillera82950e2015-09-22 12:33:20 -0700605 }
606 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800607 return result;
608}
609
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800610/* Populates the SSL context with a private key and a cert chain, and sets the
611 cipher list and the ephemeral ECDH key. */
Craig Tillera82950e2015-09-22 12:33:20 -0700612static tsi_result populate_ssl_context(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700613 SSL_CTX* context, const tsi_ssl_pem_key_cert_pair* key_cert_pair,
614 const char* cipher_list) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800615 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -0800616 if (key_cert_pair != nullptr) {
617 if (key_cert_pair->cert_chain != nullptr) {
Julien Boeufb71ef652017-04-12 21:44:49 -0700618 result = ssl_ctx_use_certificate_chain(context, key_cert_pair->cert_chain,
619 strlen(key_cert_pair->cert_chain));
620 if (result != TSI_OK) {
621 gpr_log(GPR_ERROR, "Invalid cert chain file.");
622 return result;
623 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800624 }
Craig Tiller4782d922017-11-10 09:53:21 -0800625 if (key_cert_pair->private_key != nullptr) {
Julien Boeufb71ef652017-04-12 21:44:49 -0700626 result = ssl_ctx_use_private_key(context, key_cert_pair->private_key,
627 strlen(key_cert_pair->private_key));
628 if (result != TSI_OK || !SSL_CTX_check_private_key(context)) {
629 gpr_log(GPR_ERROR, "Invalid private key.");
630 return result != TSI_OK ? result : TSI_INVALID_ARGUMENT;
631 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800632 }
Craig Tillera82950e2015-09-22 12:33:20 -0700633 }
Craig Tillerbe98d242017-11-10 15:26:57 -0800634 if ((cipher_list != nullptr) &&
635 !SSL_CTX_set_cipher_list(context, cipher_list)) {
Craig Tillera82950e2015-09-22 12:33:20 -0700636 gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list);
637 return TSI_INVALID_ARGUMENT;
638 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800639 {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700640 EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
Craig Tillera82950e2015-09-22 12:33:20 -0700641 if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
642 gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
643 EC_KEY_free(ecdh);
644 return TSI_INTERNAL_ERROR;
645 }
646 SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
647 EC_KEY_free(ecdh);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800648 }
649 return TSI_OK;
650}
651
652/* Extracts the CN and the SANs from an X509 cert as a peer object. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700653static tsi_result extract_x509_subject_names_from_pem_cert(const char* pem_cert,
654 tsi_peer* peer) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800655 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -0800656 X509* cert = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700657 BIO* pem;
658 pem = BIO_new_mem_buf((void*)pem_cert, (int)strlen(pem_cert));
Craig Tiller4782d922017-11-10 09:53:21 -0800659 if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800660
Craig Tiller4782d922017-11-10 09:53:21 -0800661 cert = PEM_read_bio_X509(pem, nullptr, nullptr, (void*)"");
662 if (cert == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700663 gpr_log(GPR_ERROR, "Invalid certificate");
664 result = TSI_INVALID_ARGUMENT;
665 } else {
666 result = peer_from_x509(cert, 0, peer);
667 }
Craig Tiller4782d922017-11-10 09:53:21 -0800668 if (cert != nullptr) X509_free(cert);
Craig Tillera82950e2015-09-22 12:33:20 -0700669 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800670 return result;
671}
672
673/* Builds the alpn protocol name list according to rfc 7301. */
Craig Tillera82950e2015-09-22 12:33:20 -0700674static tsi_result build_alpn_protocol_name_list(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700675 const char** alpn_protocols, uint16_t num_alpn_protocols,
676 unsigned char** protocol_name_list, size_t* protocol_name_list_length) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800677 uint16_t i;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700678 unsigned char* current;
Craig Tiller4782d922017-11-10 09:53:21 -0800679 *protocol_name_list = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800680 *protocol_name_list_length = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700681 if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
682 for (i = 0; i < num_alpn_protocols; i++) {
Craig Tillerbe98d242017-11-10 15:26:57 -0800683 size_t length =
684 alpn_protocols[i] == nullptr ? 0 : strlen(alpn_protocols[i]);
Julien Boeufb71ef652017-04-12 21:44:49 -0700685 if (length == 0 || length > 255) {
686 gpr_log(GPR_ERROR, "Invalid protocol name length: %d.", (int)length);
Craig Tillera82950e2015-09-22 12:33:20 -0700687 return TSI_INVALID_ARGUMENT;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800688 }
Julien Boeufb71ef652017-04-12 21:44:49 -0700689 *protocol_name_list_length += length + 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700690 }
Craig Tillerbaa14a92017-11-03 09:09:36 -0700691 *protocol_name_list = (unsigned char*)gpr_malloc(*protocol_name_list_length);
Craig Tiller4782d922017-11-10 09:53:21 -0800692 if (*protocol_name_list == nullptr) return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800693 current = *protocol_name_list;
Craig Tillera82950e2015-09-22 12:33:20 -0700694 for (i = 0; i < num_alpn_protocols; i++) {
Julien Boeufb71ef652017-04-12 21:44:49 -0700695 size_t length = strlen(alpn_protocols[i]);
696 *(current++) = (uint8_t)length; /* max checked above. */
697 memcpy(current, alpn_protocols[i], length);
698 current += length;
Craig Tillera82950e2015-09-22 12:33:20 -0700699 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800700 /* Safety check. */
Craig Tillera82950e2015-09-22 12:33:20 -0700701 if ((current < *protocol_name_list) ||
Craig Tiller7536af02015-12-22 13:49:30 -0800702 ((uintptr_t)(current - *protocol_name_list) !=
Craig Tillera82950e2015-09-22 12:33:20 -0700703 *protocol_name_list_length)) {
704 return TSI_INTERNAL_ERROR;
705 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800706 return TSI_OK;
707}
708
Deepak Lukosedba4c5f2016-03-25 12:54:25 -0700709// The verification callback is used for clients that don't really care about
710// the server's certificate, but we need to pull it anyway, in case a higher
711// layer wants to look at it. In this case the verification may fail, but
712// we don't really care.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700713static int NullVerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
Deepak Lukosedba4c5f2016-03-25 12:54:25 -0700714 return 1;
715}
716
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800717/* --- tsi_frame_protector methods implementation. ---*/
718
Craig Tillerbaa14a92017-11-03 09:09:36 -0700719static tsi_result ssl_protector_protect(tsi_frame_protector* self,
720 const unsigned char* unprotected_bytes,
721 size_t* unprotected_bytes_size,
722 unsigned char* protected_output_frames,
723 size_t* protected_output_frames_size) {
724 tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800725 int read_from_ssl;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800726 size_t available;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800727 tsi_result result = TSI_OK;
728
729 /* First see if we have some pending data in the SSL BIO. */
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700730 int pending_in_ssl = (int)BIO_pending(impl->from_ssl);
Craig Tillera82950e2015-09-22 12:33:20 -0700731 if (pending_in_ssl > 0) {
732 *unprotected_bytes_size = 0;
733 GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
734 read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
735 (int)*protected_output_frames_size);
736 if (read_from_ssl < 0) {
737 gpr_log(GPR_ERROR,
738 "Could not read from BIO even though some data is pending");
739 return TSI_INTERNAL_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800740 }
Craig Tillera82950e2015-09-22 12:33:20 -0700741 *protected_output_frames_size = (size_t)read_from_ssl;
742 return TSI_OK;
743 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800744
745 /* Now see if we can send a complete frame. */
746 available = impl->buffer_size - impl->buffer_offset;
Craig Tillera82950e2015-09-22 12:33:20 -0700747 if (available > *unprotected_bytes_size) {
748 /* If we cannot, just copy the data in our internal buffer. */
749 memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes,
750 *unprotected_bytes_size);
751 impl->buffer_offset += *unprotected_bytes_size;
752 *protected_output_frames_size = 0;
753 return TSI_OK;
754 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800755
756 /* If we can, prepare the buffer, send it to SSL_write and read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700757 memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available);
758 result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size);
759 if (result != TSI_OK) return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800760
Craig Tillera82950e2015-09-22 12:33:20 -0700761 GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
762 read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
763 (int)*protected_output_frames_size);
764 if (read_from_ssl < 0) {
765 gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
766 return TSI_INTERNAL_ERROR;
767 }
768 *protected_output_frames_size = (size_t)read_from_ssl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800769 *unprotected_bytes_size = available;
770 impl->buffer_offset = 0;
771 return TSI_OK;
772}
773
Craig Tillera82950e2015-09-22 12:33:20 -0700774static tsi_result ssl_protector_protect_flush(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700775 tsi_frame_protector* self, unsigned char* protected_output_frames,
776 size_t* protected_output_frames_size, size_t* still_pending_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800777 tsi_result result = TSI_OK;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700778 tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800779 int read_from_ssl = 0;
Craig Tiller3121fd42015-09-10 09:56:20 -0700780 int pending;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800781
Craig Tillera82950e2015-09-22 12:33:20 -0700782 if (impl->buffer_offset != 0) {
783 result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset);
784 if (result != TSI_OK) return result;
785 impl->buffer_offset = 0;
786 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800787
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700788 pending = (int)BIO_pending(impl->from_ssl);
Craig Tillera82950e2015-09-22 12:33:20 -0700789 GPR_ASSERT(pending >= 0);
790 *still_pending_size = (size_t)pending;
791 if (*still_pending_size == 0) return TSI_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800792
Craig Tillera82950e2015-09-22 12:33:20 -0700793 GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
794 read_from_ssl = BIO_read(impl->from_ssl, protected_output_frames,
795 (int)*protected_output_frames_size);
796 if (read_from_ssl <= 0) {
797 gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
798 return TSI_INTERNAL_ERROR;
799 }
800 *protected_output_frames_size = (size_t)read_from_ssl;
Julien Boeuf01ac4f02015-10-09 16:08:24 -0700801 pending = (int)BIO_pending(impl->from_ssl);
Craig Tillera82950e2015-09-22 12:33:20 -0700802 GPR_ASSERT(pending >= 0);
803 *still_pending_size = (size_t)pending;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800804 return TSI_OK;
805}
806
Craig Tillera82950e2015-09-22 12:33:20 -0700807static tsi_result ssl_protector_unprotect(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700808 tsi_frame_protector* self, const unsigned char* protected_frames_bytes,
809 size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes,
810 size_t* unprotected_bytes_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800811 tsi_result result = TSI_OK;
812 int written_into_ssl = 0;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800813 size_t output_bytes_size = *unprotected_bytes_size;
814 size_t output_bytes_offset = 0;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700815 tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800816
817 /* First, try to read remaining data from ssl. */
Craig Tillera82950e2015-09-22 12:33:20 -0700818 result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
819 if (result != TSI_OK) return result;
820 if (*unprotected_bytes_size == output_bytes_size) {
821 /* We have read everything we could and cannot process any more input. */
822 *protected_frames_bytes_size = 0;
823 return TSI_OK;
824 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800825 output_bytes_offset = *unprotected_bytes_size;
826 unprotected_bytes += output_bytes_offset;
827 *unprotected_bytes_size = output_bytes_size - output_bytes_offset;
828
829 /* Then, try to write some data to ssl. */
Craig Tillera82950e2015-09-22 12:33:20 -0700830 GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX);
831 written_into_ssl = BIO_write(impl->into_ssl, protected_frames_bytes,
832 (int)*protected_frames_bytes_size);
833 if (written_into_ssl < 0) {
834 gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d",
835 written_into_ssl);
836 return TSI_INTERNAL_ERROR;
837 }
838 *protected_frames_bytes_size = (size_t)written_into_ssl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800839
840 /* Now try to read some data again. */
Craig Tillera82950e2015-09-22 12:33:20 -0700841 result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
842 if (result == TSI_OK) {
843 /* Don't forget to output the total number of bytes read. */
844 *unprotected_bytes_size += output_bytes_offset;
845 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800846 return result;
847}
848
Craig Tillerbaa14a92017-11-03 09:09:36 -0700849static void ssl_protector_destroy(tsi_frame_protector* self) {
850 tsi_ssl_frame_protector* impl = (tsi_ssl_frame_protector*)self;
Craig Tiller4782d922017-11-10 09:53:21 -0800851 if (impl->buffer != nullptr) gpr_free(impl->buffer);
852 if (impl->ssl != nullptr) SSL_free(impl->ssl);
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +0100853 gpr_free(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800854}
855
856static const tsi_frame_protector_vtable frame_protector_vtable = {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700857 ssl_protector_protect,
858 ssl_protector_protect_flush,
859 ssl_protector_unprotect,
Craig Tillera82950e2015-09-22 12:33:20 -0700860 ssl_protector_destroy,
Craig Tillerd6c98df2015-08-18 09:33:44 -0700861};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800862
Justin Burke49841352017-08-31 17:42:54 -0700863/* --- tsi_server_handshaker_factory methods implementation. --- */
864
865static void tsi_ssl_handshaker_factory_destroy(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700866 tsi_ssl_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -0800867 if (self == nullptr) return;
Justin Burke49841352017-08-31 17:42:54 -0700868
Craig Tiller4782d922017-11-10 09:53:21 -0800869 if (self->vtable != nullptr && self->vtable->destroy != nullptr) {
Justin Burke49841352017-08-31 17:42:54 -0700870 self->vtable->destroy(self);
871 }
872 /* Note, we don't free(self) here because this object is always directly
873 * embedded in another object. If tsi_ssl_handshaker_factory_init allocates
874 * any memory, it should be free'd here. */
875}
876
Craig Tillerbaa14a92017-11-03 09:09:36 -0700877static tsi_ssl_handshaker_factory* tsi_ssl_handshaker_factory_ref(
878 tsi_ssl_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -0800879 if (self == nullptr) return nullptr;
Justin Burke49841352017-08-31 17:42:54 -0700880 gpr_refn(&self->refcount, 1);
881 return self;
882}
883
Craig Tillerbaa14a92017-11-03 09:09:36 -0700884static void tsi_ssl_handshaker_factory_unref(tsi_ssl_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -0800885 if (self == nullptr) return;
Justin Burke49841352017-08-31 17:42:54 -0700886
887 if (gpr_unref(&self->refcount)) {
888 tsi_ssl_handshaker_factory_destroy(self);
889 }
890}
891
Craig Tiller4782d922017-11-10 09:53:21 -0800892static tsi_ssl_handshaker_factory_vtable handshaker_factory_vtable = {nullptr};
Justin Burke49841352017-08-31 17:42:54 -0700893
894/* Initializes a tsi_ssl_handshaker_factory object. Caller is responsible for
895 * allocating memory for the factory. */
896static void tsi_ssl_handshaker_factory_init(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700897 tsi_ssl_handshaker_factory* factory) {
Craig Tiller4782d922017-11-10 09:53:21 -0800898 GPR_ASSERT(factory != nullptr);
Justin Burke49841352017-08-31 17:42:54 -0700899
900 factory->vtable = &handshaker_factory_vtable;
901 gpr_ref_init(&factory->refcount, 1);
902}
903
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800904/* --- tsi_handshaker methods implementation. ---*/
905
Craig Tillerbaa14a92017-11-03 09:09:36 -0700906static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self,
907 unsigned char* bytes,
908 size_t* bytes_size) {
909 tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800910 int bytes_read_from_ssl = 0;
Craig Tiller4782d922017-11-10 09:53:21 -0800911 if (bytes == nullptr || bytes_size == nullptr || *bytes_size == 0 ||
Craig Tillera82950e2015-09-22 12:33:20 -0700912 *bytes_size > INT_MAX) {
913 return TSI_INVALID_ARGUMENT;
914 }
915 GPR_ASSERT(*bytes_size <= INT_MAX);
916 bytes_read_from_ssl = BIO_read(impl->from_ssl, bytes, (int)*bytes_size);
917 if (bytes_read_from_ssl < 0) {
918 *bytes_size = 0;
919 if (!BIO_should_retry(impl->from_ssl)) {
920 impl->result = TSI_INTERNAL_ERROR;
921 return impl->result;
922 } else {
923 return TSI_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800924 }
Craig Tillera82950e2015-09-22 12:33:20 -0700925 }
926 *bytes_size = (size_t)bytes_read_from_ssl;
927 return BIO_pending(impl->from_ssl) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800928}
929
Craig Tillerbaa14a92017-11-03 09:09:36 -0700930static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) {
931 tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
Craig Tillera82950e2015-09-22 12:33:20 -0700932 if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) &&
933 SSL_is_init_finished(impl->ssl)) {
934 impl->result = TSI_OK;
935 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800936 return impl->result;
937}
938
Craig Tillera82950e2015-09-22 12:33:20 -0700939static tsi_result ssl_handshaker_process_bytes_from_peer(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700940 tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size) {
941 tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800942 int bytes_written_into_ssl_size = 0;
Craig Tiller4782d922017-11-10 09:53:21 -0800943 if (bytes == nullptr || bytes_size == nullptr || *bytes_size > INT_MAX) {
Craig Tillera82950e2015-09-22 12:33:20 -0700944 return TSI_INVALID_ARGUMENT;
945 }
946 GPR_ASSERT(*bytes_size <= INT_MAX);
947 bytes_written_into_ssl_size =
948 BIO_write(impl->into_ssl, bytes, (int)*bytes_size);
949 if (bytes_written_into_ssl_size < 0) {
950 gpr_log(GPR_ERROR, "Could not write to memory BIO.");
951 impl->result = TSI_INTERNAL_ERROR;
952 return impl->result;
953 }
954 *bytes_size = (size_t)bytes_written_into_ssl_size;
Craig Tiller45724b32015-09-22 10:42:19 -0700955
Craig Tillera82950e2015-09-22 12:33:20 -0700956 if (!tsi_handshaker_is_in_progress(self)) {
957 impl->result = TSI_OK;
958 return impl->result;
959 } else {
960 /* Get ready to get some bytes from SSL. */
961 int ssl_result = SSL_do_handshake(impl->ssl);
962 ssl_result = SSL_get_error(impl->ssl, ssl_result);
963 switch (ssl_result) {
964 case SSL_ERROR_WANT_READ:
965 if (BIO_pending(impl->from_ssl) == 0) {
966 /* We need more data. */
967 return TSI_INCOMPLETE_DATA;
968 } else {
969 return TSI_OK;
970 }
971 case SSL_ERROR_NONE:
972 return TSI_OK;
973 default: {
974 char err_str[256];
975 ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str));
976 gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.",
977 ssl_error_string(ssl_result), err_str);
978 impl->result = TSI_PROTOCOL_FAILURE;
979 return impl->result;
980 }
Craig Tiller45724b32015-09-22 10:42:19 -0700981 }
Craig Tillera82950e2015-09-22 12:33:20 -0700982 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800983}
984
Craig Tillerbaa14a92017-11-03 09:09:36 -0700985static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self,
986 tsi_peer* peer) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800987 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -0800988 const unsigned char* alpn_selected = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800989 unsigned int alpn_selected_len;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700990 tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
991 X509* peer_cert = SSL_get_peer_certificate(impl->ssl);
Craig Tiller4782d922017-11-10 09:53:21 -0800992 if (peer_cert != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700993 result = peer_from_x509(peer_cert, 1, peer);
994 X509_free(peer_cert);
995 if (result != TSI_OK) return result;
996 }
Julien Boeufd1531322015-06-18 11:05:39 +0200997#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -0700998 SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len);
Julien Boeufd1531322015-06-18 11:05:39 +0200999#endif /* TSI_OPENSSL_ALPN_SUPPORT */
Craig Tiller4782d922017-11-10 09:53:21 -08001000 if (alpn_selected == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001001 /* Try npn. */
1002 SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected,
1003 &alpn_selected_len);
1004 }
Craig Tiller4782d922017-11-10 09:53:21 -08001005 if (alpn_selected != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001006 size_t i;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001007 tsi_peer_property* new_properties = (tsi_peer_property*)gpr_zalloc(
Yash Tibrewalacd46e52017-09-20 11:28:25 -07001008 sizeof(*new_properties) * (peer->property_count + 1));
Craig Tillera82950e2015-09-22 12:33:20 -07001009 for (i = 0; i < peer->property_count; i++) {
1010 new_properties[i] = peer->properties[i];
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001011 }
Craig Tillera82950e2015-09-22 12:33:20 -07001012 result = tsi_construct_string_peer_property(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001013 TSI_SSL_ALPN_SELECTED_PROTOCOL, (const char*)alpn_selected,
Craig Tillera82950e2015-09-22 12:33:20 -07001014 alpn_selected_len, &new_properties[peer->property_count]);
1015 if (result != TSI_OK) {
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +01001016 gpr_free(new_properties);
Craig Tillera82950e2015-09-22 12:33:20 -07001017 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001018 }
Craig Tiller4782d922017-11-10 09:53:21 -08001019 if (peer->properties != nullptr) gpr_free(peer->properties);
Craig Tillera82950e2015-09-22 12:33:20 -07001020 peer->property_count++;
1021 peer->properties = new_properties;
1022 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001023 return result;
1024}
1025
Craig Tillera82950e2015-09-22 12:33:20 -07001026static tsi_result ssl_handshaker_create_frame_protector(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001027 tsi_handshaker* self, size_t* max_output_protected_frame_size,
1028 tsi_frame_protector** protector) {
Craig Tillera82950e2015-09-22 12:33:20 -07001029 size_t actual_max_output_protected_frame_size =
1030 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001031 tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
1032 tsi_ssl_frame_protector* protector_impl =
1033 (tsi_ssl_frame_protector*)gpr_zalloc(sizeof(*protector_impl));
Craig Tiller45724b32015-09-22 10:42:19 -07001034
Craig Tiller4782d922017-11-10 09:53:21 -08001035 if (max_output_protected_frame_size != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001036 if (*max_output_protected_frame_size >
1037 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) {
1038 *max_output_protected_frame_size =
1039 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
1040 } else if (*max_output_protected_frame_size <
1041 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) {
1042 *max_output_protected_frame_size =
1043 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND;
Craig Tiller45724b32015-09-22 10:42:19 -07001044 }
Craig Tillera82950e2015-09-22 12:33:20 -07001045 actual_max_output_protected_frame_size = *max_output_protected_frame_size;
1046 }
1047 protector_impl->buffer_size =
1048 actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD;
Yash Tibrewalacd46e52017-09-20 11:28:25 -07001049 protector_impl->buffer =
Craig Tillerbaa14a92017-11-03 09:09:36 -07001050 (unsigned char*)gpr_malloc(protector_impl->buffer_size);
Craig Tiller4782d922017-11-10 09:53:21 -08001051 if (protector_impl->buffer == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001052 gpr_log(GPR_ERROR,
1053 "Could not allocated buffer for tsi_ssl_frame_protector.");
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +01001054 gpr_free(protector_impl);
Craig Tillera82950e2015-09-22 12:33:20 -07001055 return TSI_INTERNAL_ERROR;
1056 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001057
1058 /* Transfer ownership of ssl to the frame protector. It is OK as the caller
1059 * cannot call anything else but destroy on the handshaker after this call. */
1060 protector_impl->ssl = impl->ssl;
Craig Tiller4782d922017-11-10 09:53:21 -08001061 impl->ssl = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001062 protector_impl->into_ssl = impl->into_ssl;
1063 protector_impl->from_ssl = impl->from_ssl;
1064
1065 protector_impl->base.vtable = &frame_protector_vtable;
1066 *protector = &protector_impl->base;
1067 return TSI_OK;
1068}
1069
Craig Tillerbaa14a92017-11-03 09:09:36 -07001070static void ssl_handshaker_destroy(tsi_handshaker* self) {
1071 tsi_ssl_handshaker* impl = (tsi_ssl_handshaker*)self;
Craig Tillera82950e2015-09-22 12:33:20 -07001072 SSL_free(impl->ssl); /* The BIO objects are owned by ssl */
Justin Burke49841352017-08-31 17:42:54 -07001073 tsi_ssl_handshaker_factory_unref(impl->factory_ref);
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +01001074 gpr_free(impl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001075}
1076
1077static const tsi_handshaker_vtable handshaker_vtable = {
Craig Tillera82950e2015-09-22 12:33:20 -07001078 ssl_handshaker_get_bytes_to_send_to_peer,
Craig Tillerf40df232016-03-25 13:38:14 -07001079 ssl_handshaker_process_bytes_from_peer,
1080 ssl_handshaker_get_result,
1081 ssl_handshaker_extract_peer,
1082 ssl_handshaker_create_frame_protector,
Craig Tillera82950e2015-09-22 12:33:20 -07001083 ssl_handshaker_destroy,
Craig Tiller4782d922017-11-10 09:53:21 -08001084 nullptr,
Craig Tillerd6c98df2015-08-18 09:33:44 -07001085};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001086
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001087/* --- tsi_ssl_handshaker_factory common methods. --- */
1088
Craig Tillerbaa14a92017-11-03 09:09:36 -07001089static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client,
1090 const char* server_name_indication,
1091 tsi_ssl_handshaker_factory* factory,
1092 tsi_handshaker** handshaker) {
1093 SSL* ssl = SSL_new(ctx);
Craig Tiller4782d922017-11-10 09:53:21 -08001094 BIO* into_ssl = nullptr;
1095 BIO* from_ssl = nullptr;
1096 tsi_ssl_handshaker* impl = nullptr;
1097 *handshaker = nullptr;
1098 if (ctx == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001099 gpr_log(GPR_ERROR, "SSL Context is null. Should never happen.");
1100 return TSI_INTERNAL_ERROR;
1101 }
Craig Tiller4782d922017-11-10 09:53:21 -08001102 if (ssl == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001103 return TSI_OUT_OF_RESOURCES;
1104 }
1105 SSL_set_info_callback(ssl, ssl_info_callback);
1106
1107 into_ssl = BIO_new(BIO_s_mem());
1108 from_ssl = BIO_new(BIO_s_mem());
Craig Tiller4782d922017-11-10 09:53:21 -08001109 if (into_ssl == nullptr || from_ssl == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001110 gpr_log(GPR_ERROR, "BIO_new failed.");
1111 SSL_free(ssl);
Craig Tiller4782d922017-11-10 09:53:21 -08001112 if (into_ssl != nullptr) BIO_free(into_ssl);
1113 if (from_ssl != nullptr) BIO_free(into_ssl);
Craig Tillera82950e2015-09-22 12:33:20 -07001114 return TSI_OUT_OF_RESOURCES;
1115 }
1116 SSL_set_bio(ssl, into_ssl, from_ssl);
1117 if (is_client) {
1118 int ssl_result;
1119 SSL_set_connect_state(ssl);
Craig Tiller4782d922017-11-10 09:53:21 -08001120 if (server_name_indication != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001121 if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) {
1122 gpr_log(GPR_ERROR, "Invalid server name indication %s.",
1123 server_name_indication);
1124 SSL_free(ssl);
1125 return TSI_INTERNAL_ERROR;
1126 }
1127 }
1128 ssl_result = SSL_do_handshake(ssl);
1129 ssl_result = SSL_get_error(ssl, ssl_result);
1130 if (ssl_result != SSL_ERROR_WANT_READ) {
1131 gpr_log(GPR_ERROR,
1132 "Unexpected error received from first SSL_do_handshake call: %s",
1133 ssl_error_string(ssl_result));
1134 SSL_free(ssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001135 return TSI_INTERNAL_ERROR;
1136 }
Craig Tillera82950e2015-09-22 12:33:20 -07001137 } else {
1138 SSL_set_accept_state(ssl);
1139 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001140
Craig Tillerbaa14a92017-11-03 09:09:36 -07001141 impl = (tsi_ssl_handshaker*)gpr_zalloc(sizeof(*impl));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001142 impl->ssl = ssl;
1143 impl->into_ssl = into_ssl;
1144 impl->from_ssl = from_ssl;
1145 impl->result = TSI_HANDSHAKE_IN_PROGRESS;
1146 impl->base.vtable = &handshaker_vtable;
Justin Burke49841352017-08-31 17:42:54 -07001147 impl->factory_ref = tsi_ssl_handshaker_factory_ref(factory);
1148
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001149 *handshaker = &impl->base;
1150 return TSI_OK;
1151}
1152
Craig Tillerbaa14a92017-11-03 09:09:36 -07001153static int select_protocol_list(const unsigned char** out,
1154 unsigned char* outlen,
1155 const unsigned char* client_list,
Craig Tillera82950e2015-09-22 12:33:20 -07001156 size_t client_list_len,
Craig Tillerbaa14a92017-11-03 09:09:36 -07001157 const unsigned char* server_list,
Craig Tillera82950e2015-09-22 12:33:20 -07001158 size_t server_list_len) {
Craig Tillerbaa14a92017-11-03 09:09:36 -07001159 const unsigned char* client_current = client_list;
Craig Tillera82950e2015-09-22 12:33:20 -07001160 while ((unsigned int)(client_current - client_list) < client_list_len) {
1161 unsigned char client_current_len = *(client_current++);
Craig Tillerbaa14a92017-11-03 09:09:36 -07001162 const unsigned char* server_current = server_list;
Craig Tillera82950e2015-09-22 12:33:20 -07001163 while ((server_current >= server_list) &&
Craig Tiller7536af02015-12-22 13:49:30 -08001164 (uintptr_t)(server_current - server_list) < server_list_len) {
Craig Tillera82950e2015-09-22 12:33:20 -07001165 unsigned char server_current_len = *(server_current++);
1166 if ((client_current_len == server_current_len) &&
1167 !memcmp(client_current, server_current, server_current_len)) {
1168 *out = server_current;
1169 *outlen = server_current_len;
1170 return SSL_TLSEXT_ERR_OK;
1171 }
1172 server_current += server_current_len;
Julien Boeufd1531322015-06-18 11:05:39 +02001173 }
Craig Tillera82950e2015-09-22 12:33:20 -07001174 client_current += client_current_len;
1175 }
Julien Boeufd1531322015-06-18 11:05:39 +02001176 return SSL_TLSEXT_ERR_NOACK;
1177}
1178
Julien Boeuf935d02e2017-04-09 00:07:09 -07001179/* --- tsi_ssl_client_handshaker_factory methods implementation. --- */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001180
Julien Boeuf935d02e2017-04-09 00:07:09 -07001181tsi_result tsi_ssl_client_handshaker_factory_create_handshaker(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001182 tsi_ssl_client_handshaker_factory* self, const char* server_name_indication,
1183 tsi_handshaker** handshaker) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001184 return create_tsi_ssl_handshaker(self->ssl_context, 1, server_name_indication,
Justin Burke49841352017-08-31 17:42:54 -07001185 &self->base, handshaker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001186}
1187
Justin Burke49841352017-08-31 17:42:54 -07001188void tsi_ssl_client_handshaker_factory_unref(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001189 tsi_ssl_client_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -08001190 if (self == nullptr) return;
Justin Burke49841352017-08-31 17:42:54 -07001191 tsi_ssl_handshaker_factory_unref(&self->base);
1192}
1193
1194static void tsi_ssl_client_handshaker_factory_destroy(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001195 tsi_ssl_handshaker_factory* factory) {
Craig Tiller4782d922017-11-10 09:53:21 -08001196 if (factory == nullptr) return;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001197 tsi_ssl_client_handshaker_factory* self =
1198 (tsi_ssl_client_handshaker_factory*)factory;
Craig Tiller4782d922017-11-10 09:53:21 -08001199 if (self->ssl_context != nullptr) SSL_CTX_free(self->ssl_context);
1200 if (self->alpn_protocol_list != nullptr) gpr_free(self->alpn_protocol_list);
Julien Boeuf935d02e2017-04-09 00:07:09 -07001201 gpr_free(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001202}
1203
Craig Tillerbaa14a92017-11-03 09:09:36 -07001204static int client_handshaker_factory_npn_callback(SSL* ssl, unsigned char** out,
1205 unsigned char* outlen,
1206 const unsigned char* in,
Craig Tillera82950e2015-09-22 12:33:20 -07001207 unsigned int inlen,
Craig Tillerbaa14a92017-11-03 09:09:36 -07001208 void* arg) {
1209 tsi_ssl_client_handshaker_factory* factory =
1210 (tsi_ssl_client_handshaker_factory*)arg;
1211 return select_protocol_list((const unsigned char**)out, outlen,
Craig Tillera82950e2015-09-22 12:33:20 -07001212 factory->alpn_protocol_list,
1213 factory->alpn_protocol_list_length, in, inlen);
Julien Boeufd1531322015-06-18 11:05:39 +02001214}
1215
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001216/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
1217
Julien Boeuf935d02e2017-04-09 00:07:09 -07001218tsi_result tsi_ssl_server_handshaker_factory_create_handshaker(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001219 tsi_ssl_server_handshaker_factory* self, tsi_handshaker** handshaker) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001220 if (self->ssl_context_count == 0) return TSI_INVALID_ARGUMENT;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001221 /* Create the handshaker with the first context. We will switch if needed
1222 because of SNI in ssl_server_handshaker_factory_servername_callback. */
Craig Tillerbe98d242017-11-10 15:26:57 -08001223 return create_tsi_ssl_handshaker(self->ssl_contexts[0], 0, nullptr,
1224 &self->base, handshaker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001225}
1226
Justin Burke49841352017-08-31 17:42:54 -07001227void tsi_ssl_server_handshaker_factory_unref(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001228 tsi_ssl_server_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -08001229 if (self == nullptr) return;
Justin Burke49841352017-08-31 17:42:54 -07001230 tsi_ssl_handshaker_factory_unref(&self->base);
1231}
1232
1233static void tsi_ssl_server_handshaker_factory_destroy(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001234 tsi_ssl_handshaker_factory* factory) {
Craig Tiller4782d922017-11-10 09:53:21 -08001235 if (factory == nullptr) return;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001236 tsi_ssl_server_handshaker_factory* self =
1237 (tsi_ssl_server_handshaker_factory*)factory;
Julien Boeufb222b4d2015-01-15 17:01:39 -08001238 size_t i;
Julien Boeuf935d02e2017-04-09 00:07:09 -07001239 for (i = 0; i < self->ssl_context_count; i++) {
Craig Tiller4782d922017-11-10 09:53:21 -08001240 if (self->ssl_contexts[i] != nullptr) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001241 SSL_CTX_free(self->ssl_contexts[i]);
1242 tsi_peer_destruct(&self->ssl_context_x509_subject_names[i]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001243 }
Craig Tillera82950e2015-09-22 12:33:20 -07001244 }
Craig Tiller4782d922017-11-10 09:53:21 -08001245 if (self->ssl_contexts != nullptr) gpr_free(self->ssl_contexts);
1246 if (self->ssl_context_x509_subject_names != nullptr) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001247 gpr_free(self->ssl_context_x509_subject_names);
Craig Tillera82950e2015-09-22 12:33:20 -07001248 }
Craig Tiller4782d922017-11-10 09:53:21 -08001249 if (self->alpn_protocol_list != nullptr) gpr_free(self->alpn_protocol_list);
Julien Boeuf935d02e2017-04-09 00:07:09 -07001250 gpr_free(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001251}
1252
Craig Tillerbaa14a92017-11-03 09:09:36 -07001253static int does_entry_match_name(const char* entry, size_t entry_length,
1254 const char* name) {
1255 const char* dot;
Craig Tiller4782d922017-11-10 09:53:21 -08001256 const char* name_subdomain = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -07001257 size_t name_length = strlen(name);
Julien Boeuf9fff77e2015-02-24 16:50:35 -08001258 size_t name_subdomain_length;
Craig Tillera82950e2015-09-22 12:33:20 -07001259 if (entry_length == 0) return 0;
Julien Boeuf9fff77e2015-02-24 16:50:35 -08001260
1261 /* Take care of '.' terminations. */
Craig Tillera82950e2015-09-22 12:33:20 -07001262 if (name[name_length - 1] == '.') {
1263 name_length--;
1264 }
1265 if (entry[entry_length - 1] == '.') {
1266 entry_length--;
1267 if (entry_length == 0) return 0;
1268 }
Julien Boeuf9fff77e2015-02-24 16:50:35 -08001269
Craig Tillera82950e2015-09-22 12:33:20 -07001270 if ((name_length == entry_length) &&
1271 strncmp(name, entry, entry_length) == 0) {
1272 return 1; /* Perfect match. */
1273 }
1274 if (entry[0] != '*') return 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001275
1276 /* Wildchar subdomain matching. */
Craig Tillera82950e2015-09-22 12:33:20 -07001277 if (entry_length < 3 || entry[1] != '.') { /* At least *.x */
1278 gpr_log(GPR_ERROR, "Invalid wildchar entry.");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001279 return 0;
Craig Tillera82950e2015-09-22 12:33:20 -07001280 }
1281 name_subdomain = strchr(name, '.');
Craig Tiller4782d922017-11-10 09:53:21 -08001282 if (name_subdomain == nullptr) return 0;
Craig Tillera82950e2015-09-22 12:33:20 -07001283 name_subdomain_length = strlen(name_subdomain);
1284 if (name_subdomain_length < 2) return 0;
1285 name_subdomain++; /* Starts after the dot. */
Julien Boeuf0170a6c2015-02-24 18:08:01 -08001286 name_subdomain_length--;
Craig Tillera82950e2015-09-22 12:33:20 -07001287 entry += 2; /* Remove *. */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001288 entry_length -= 2;
Craig Tillera82950e2015-09-22 12:33:20 -07001289 dot = strchr(name_subdomain, '.');
Craig Tiller4782d922017-11-10 09:53:21 -08001290 if ((dot == nullptr) || (dot == &name_subdomain[name_subdomain_length - 1])) {
Craig Tillera82950e2015-09-22 12:33:20 -07001291 gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain);
1292 return 0;
1293 }
1294 if (name_subdomain[name_subdomain_length - 1] == '.') {
1295 name_subdomain_length--;
1296 }
1297 return ((entry_length > 0) && (name_subdomain_length == entry_length) &&
1298 strncmp(entry, name_subdomain, entry_length) == 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001299}
1300
Craig Tillerbaa14a92017-11-03 09:09:36 -07001301static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap,
1302 void* arg) {
1303 tsi_ssl_server_handshaker_factory* impl =
1304 (tsi_ssl_server_handshaker_factory*)arg;
Julien Boeufb222b4d2015-01-15 17:01:39 -08001305 size_t i = 0;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001306 const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
Craig Tiller4782d922017-11-10 09:53:21 -08001307 if (servername == nullptr || strlen(servername) == 0) {
Craig Tillera82950e2015-09-22 12:33:20 -07001308 return SSL_TLSEXT_ERR_NOACK;
1309 }
Craig Tiller45724b32015-09-22 10:42:19 -07001310
Craig Tillera82950e2015-09-22 12:33:20 -07001311 for (i = 0; i < impl->ssl_context_count; i++) {
1312 if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i],
1313 servername)) {
1314 SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]);
1315 return SSL_TLSEXT_ERR_OK;
Craig Tiller45724b32015-09-22 10:42:19 -07001316 }
Craig Tillera82950e2015-09-22 12:33:20 -07001317 }
1318 gpr_log(GPR_ERROR, "No match found for server name: %s.", servername);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001319 return SSL_TLSEXT_ERR_ALERT_WARNING;
1320}
1321
Julien Boeufd1531322015-06-18 11:05:39 +02001322#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001323static int server_handshaker_factory_alpn_callback(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001324 SSL* ssl, const unsigned char** out, unsigned char* outlen,
1325 const unsigned char* in, unsigned int inlen, void* arg) {
1326 tsi_ssl_server_handshaker_factory* factory =
1327 (tsi_ssl_server_handshaker_factory*)arg;
Craig Tillera82950e2015-09-22 12:33:20 -07001328 return select_protocol_list(out, outlen, in, inlen,
1329 factory->alpn_protocol_list,
1330 factory->alpn_protocol_list_length);
Julien Boeufd1531322015-06-18 11:05:39 +02001331}
1332#endif /* TSI_OPENSSL_ALPN_SUPPORT */
1333
Craig Tillera82950e2015-09-22 12:33:20 -07001334static int server_handshaker_factory_npn_advertised_callback(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001335 SSL* ssl, const unsigned char** out, unsigned int* outlen, void* arg) {
1336 tsi_ssl_server_handshaker_factory* factory =
1337 (tsi_ssl_server_handshaker_factory*)arg;
Julien Boeufd1531322015-06-18 11:05:39 +02001338 *out = factory->alpn_protocol_list;
Craig Tillera82950e2015-09-22 12:33:20 -07001339 GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX);
1340 *outlen = (unsigned int)factory->alpn_protocol_list_length;
Julien Boeufd1531322015-06-18 11:05:39 +02001341 return SSL_TLSEXT_ERR_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001342}
1343
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001344/* --- tsi_ssl_handshaker_factory constructors. --- */
1345
Justin Burke49841352017-08-31 17:42:54 -07001346static tsi_ssl_handshaker_factory_vtable client_handshaker_factory_vtable = {
1347 tsi_ssl_client_handshaker_factory_destroy};
1348
Craig Tillera82950e2015-09-22 12:33:20 -07001349tsi_result tsi_create_ssl_client_handshaker_factory(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001350 const tsi_ssl_pem_key_cert_pair* pem_key_cert_pair,
1351 const char* pem_root_certs, const char* cipher_suites,
1352 const char** alpn_protocols, uint16_t num_alpn_protocols,
1353 tsi_ssl_client_handshaker_factory** factory) {
Craig Tiller4782d922017-11-10 09:53:21 -08001354 SSL_CTX* ssl_context = nullptr;
1355 tsi_ssl_client_handshaker_factory* impl = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001356 tsi_result result = TSI_OK;
1357
Craig Tillera82950e2015-09-22 12:33:20 -07001358 gpr_once_init(&init_openssl_once, init_openssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001359
Craig Tiller4782d922017-11-10 09:53:21 -08001360 if (factory == nullptr) return TSI_INVALID_ARGUMENT;
1361 *factory = nullptr;
1362 if (pem_root_certs == nullptr) return TSI_INVALID_ARGUMENT;
Craig Tillera82950e2015-09-22 12:33:20 -07001363
1364 ssl_context = SSL_CTX_new(TLSv1_2_method());
Craig Tiller4782d922017-11-10 09:53:21 -08001365 if (ssl_context == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001366 gpr_log(GPR_ERROR, "Could not create ssl context.");
Craig Tiller45724b32015-09-22 10:42:19 -07001367 return TSI_INVALID_ARGUMENT;
Craig Tillera82950e2015-09-22 12:33:20 -07001368 }
Julien Boeufd1531322015-06-18 11:05:39 +02001369
Craig Tillerbaa14a92017-11-03 09:09:36 -07001370 impl = (tsi_ssl_client_handshaker_factory*)gpr_zalloc(sizeof(*impl));
Justin Burke49841352017-08-31 17:42:54 -07001371 tsi_ssl_handshaker_factory_init(&impl->base);
1372 impl->base.vtable = &client_handshaker_factory_vtable;
1373
Julien Boeufd1531322015-06-18 11:05:39 +02001374 impl->ssl_context = ssl_context;
1375
Craig Tillera82950e2015-09-22 12:33:20 -07001376 do {
1377 result =
Julien Boeufb71ef652017-04-12 21:44:49 -07001378 populate_ssl_context(ssl_context, pem_key_cert_pair, cipher_suites);
Craig Tillera82950e2015-09-22 12:33:20 -07001379 if (result != TSI_OK) break;
1380 result = ssl_ctx_load_verification_certs(ssl_context, pem_root_certs,
Craig Tiller4782d922017-11-10 09:53:21 -08001381 strlen(pem_root_certs), nullptr);
Craig Tillera82950e2015-09-22 12:33:20 -07001382 if (result != TSI_OK) {
1383 gpr_log(GPR_ERROR, "Cannot load server root certificates.");
1384 break;
1385 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001386
Craig Tillera82950e2015-09-22 12:33:20 -07001387 if (num_alpn_protocols != 0) {
Julien Boeufb71ef652017-04-12 21:44:49 -07001388 result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols,
1389 &impl->alpn_protocol_list,
1390 &impl->alpn_protocol_list_length);
Craig Tillera82950e2015-09-22 12:33:20 -07001391 if (result != TSI_OK) {
1392 gpr_log(GPR_ERROR, "Building alpn list failed with error %s.",
1393 tsi_result_to_string(result));
1394 break;
1395 }
Julien Boeufd1531322015-06-18 11:05:39 +02001396#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001397 GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX);
1398 if (SSL_CTX_set_alpn_protos(
1399 ssl_context, impl->alpn_protocol_list,
1400 (unsigned int)impl->alpn_protocol_list_length)) {
1401 gpr_log(GPR_ERROR, "Could not set alpn protocol list to context.");
1402 result = TSI_INVALID_ARGUMENT;
1403 break;
1404 }
Julien Boeufd1531322015-06-18 11:05:39 +02001405#endif /* TSI_OPENSSL_ALPN_SUPPORT */
Craig Tillera82950e2015-09-22 12:33:20 -07001406 SSL_CTX_set_next_proto_select_cb(
1407 ssl_context, client_handshaker_factory_npn_callback, impl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001408 }
Craig Tillera82950e2015-09-22 12:33:20 -07001409 } while (0);
1410 if (result != TSI_OK) {
Justin Burke49841352017-08-31 17:42:54 -07001411 tsi_ssl_handshaker_factory_unref(&impl->base);
Craig Tillera82950e2015-09-22 12:33:20 -07001412 return result;
1413 }
Craig Tiller4782d922017-11-10 09:53:21 -08001414 SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, nullptr);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001415 /* TODO(jboeuf): Add revocation verification. */
1416
Julien Boeuf935d02e2017-04-09 00:07:09 -07001417 *factory = impl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001418 return TSI_OK;
1419}
1420
Justin Burke49841352017-08-31 17:42:54 -07001421static tsi_ssl_handshaker_factory_vtable server_handshaker_factory_vtable = {
1422 tsi_ssl_server_handshaker_factory_destroy};
1423
Craig Tillera82950e2015-09-22 12:33:20 -07001424tsi_result tsi_create_ssl_server_handshaker_factory(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001425 const tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs,
1426 size_t num_key_cert_pairs, const char* pem_client_root_certs,
1427 int force_client_auth, const char* cipher_suites,
1428 const char** alpn_protocols, uint16_t num_alpn_protocols,
1429 tsi_ssl_server_handshaker_factory** factory) {
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001430 return tsi_create_ssl_server_handshaker_factory_ex(
Julien Boeufb71ef652017-04-12 21:44:49 -07001431 pem_key_cert_pairs, num_key_cert_pairs, pem_client_root_certs,
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001432 force_client_auth ? TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
1433 : TSI_DONT_REQUEST_CLIENT_CERTIFICATE,
Julien Boeufb71ef652017-04-12 21:44:49 -07001434 cipher_suites, alpn_protocols, num_alpn_protocols, factory);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001435}
1436
1437tsi_result tsi_create_ssl_server_handshaker_factory_ex(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001438 const tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs,
1439 size_t num_key_cert_pairs, const char* pem_client_root_certs,
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001440 tsi_client_certificate_request_type client_certificate_request,
Craig Tillerbaa14a92017-11-03 09:09:36 -07001441 const char* cipher_suites, const char** alpn_protocols,
1442 uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory** factory) {
Craig Tiller4782d922017-11-10 09:53:21 -08001443 tsi_ssl_server_handshaker_factory* impl = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001444 tsi_result result = TSI_OK;
Julien Boeufb222b4d2015-01-15 17:01:39 -08001445 size_t i = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001446
Craig Tillera82950e2015-09-22 12:33:20 -07001447 gpr_once_init(&init_openssl_once, init_openssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001448
Craig Tiller4782d922017-11-10 09:53:21 -08001449 if (factory == nullptr) return TSI_INVALID_ARGUMENT;
1450 *factory = nullptr;
1451 if (num_key_cert_pairs == 0 || pem_key_cert_pairs == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001452 return TSI_INVALID_ARGUMENT;
1453 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001454
Craig Tillerbaa14a92017-11-03 09:09:36 -07001455 impl = (tsi_ssl_server_handshaker_factory*)gpr_zalloc(sizeof(*impl));
Justin Burke49841352017-08-31 17:42:54 -07001456 tsi_ssl_handshaker_factory_init(&impl->base);
1457 impl->base.vtable = &server_handshaker_factory_vtable;
1458
Yash Tibrewalacd46e52017-09-20 11:28:25 -07001459 impl->ssl_contexts =
Craig Tillerbaa14a92017-11-03 09:09:36 -07001460 (SSL_CTX**)gpr_zalloc(num_key_cert_pairs * sizeof(SSL_CTX*));
Craig Tillera82950e2015-09-22 12:33:20 -07001461 impl->ssl_context_x509_subject_names =
Craig Tillerbaa14a92017-11-03 09:09:36 -07001462 (tsi_peer*)gpr_zalloc(num_key_cert_pairs * sizeof(tsi_peer));
Craig Tiller4782d922017-11-10 09:53:21 -08001463 if (impl->ssl_contexts == nullptr ||
1464 impl->ssl_context_x509_subject_names == nullptr) {
Justin Burke49841352017-08-31 17:42:54 -07001465 tsi_ssl_handshaker_factory_unref(&impl->base);
Craig Tillera82950e2015-09-22 12:33:20 -07001466 return TSI_OUT_OF_RESOURCES;
1467 }
Julien Boeufb71ef652017-04-12 21:44:49 -07001468 impl->ssl_context_count = num_key_cert_pairs;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001469
Craig Tillera82950e2015-09-22 12:33:20 -07001470 if (num_alpn_protocols > 0) {
Julien Boeufb71ef652017-04-12 21:44:49 -07001471 result = build_alpn_protocol_name_list(alpn_protocols, num_alpn_protocols,
1472 &impl->alpn_protocol_list,
1473 &impl->alpn_protocol_list_length);
Craig Tillera82950e2015-09-22 12:33:20 -07001474 if (result != TSI_OK) {
Justin Burke49841352017-08-31 17:42:54 -07001475 tsi_ssl_handshaker_factory_unref(&impl->base);
Craig Tillera82950e2015-09-22 12:33:20 -07001476 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001477 }
Craig Tillera82950e2015-09-22 12:33:20 -07001478 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001479
Julien Boeufb71ef652017-04-12 21:44:49 -07001480 for (i = 0; i < num_key_cert_pairs; i++) {
Craig Tillera82950e2015-09-22 12:33:20 -07001481 do {
1482 impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
Craig Tiller4782d922017-11-10 09:53:21 -08001483 if (impl->ssl_contexts[i] == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001484 gpr_log(GPR_ERROR, "Could not create ssl context.");
1485 result = TSI_OUT_OF_RESOURCES;
1486 break;
1487 }
Julien Boeufb71ef652017-04-12 21:44:49 -07001488 result = populate_ssl_context(impl->ssl_contexts[i],
1489 &pem_key_cert_pairs[i], cipher_suites);
Craig Tillera82950e2015-09-22 12:33:20 -07001490 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001491
Craig Tiller4782d922017-11-10 09:53:21 -08001492 if (pem_client_root_certs != nullptr) {
1493 STACK_OF(X509_NAME)* root_names = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -07001494 result = ssl_ctx_load_verification_certs(
1495 impl->ssl_contexts[i], pem_client_root_certs,
Julien Boeufb71ef652017-04-12 21:44:49 -07001496 strlen(pem_client_root_certs), &root_names);
Craig Tillera82950e2015-09-22 12:33:20 -07001497 if (result != TSI_OK) {
1498 gpr_log(GPR_ERROR, "Invalid verification certs.");
1499 break;
1500 }
1501 SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001502 switch (client_certificate_request) {
1503 case TSI_DONT_REQUEST_CLIENT_CERTIFICATE:
Craig Tiller4782d922017-11-10 09:53:21 -08001504 SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_NONE, nullptr);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001505 break;
1506 case TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
1507 SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER,
1508 NullVerifyCallback);
1509 break;
1510 case TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
Craig Tiller4782d922017-11-10 09:53:21 -08001511 SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, nullptr);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001512 break;
1513 case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
1514 SSL_CTX_set_verify(
1515 impl->ssl_contexts[i],
1516 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1517 NullVerifyCallback);
1518 break;
1519 case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
1520 SSL_CTX_set_verify(
1521 impl->ssl_contexts[i],
Craig Tiller4782d922017-11-10 09:53:21 -08001522 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001523 break;
1524 }
Craig Tillera82950e2015-09-22 12:33:20 -07001525 /* TODO(jboeuf): Add revocation verification. */
1526 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001527
Craig Tillera82950e2015-09-22 12:33:20 -07001528 result = extract_x509_subject_names_from_pem_cert(
Julien Boeufb71ef652017-04-12 21:44:49 -07001529 pem_key_cert_pairs[i].cert_chain,
Craig Tillera82950e2015-09-22 12:33:20 -07001530 &impl->ssl_context_x509_subject_names[i]);
1531 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001532
Craig Tillera82950e2015-09-22 12:33:20 -07001533 SSL_CTX_set_tlsext_servername_callback(
1534 impl->ssl_contexts[i],
1535 ssl_server_handshaker_factory_servername_callback);
1536 SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl);
Julien Boeufd1531322015-06-18 11:05:39 +02001537#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001538 SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i],
1539 server_handshaker_factory_alpn_callback, impl);
Julien Boeufd1531322015-06-18 11:05:39 +02001540#endif /* TSI_OPENSSL_ALPN_SUPPORT */
Craig Tillera82950e2015-09-22 12:33:20 -07001541 SSL_CTX_set_next_protos_advertised_cb(
1542 impl->ssl_contexts[i],
1543 server_handshaker_factory_npn_advertised_callback, impl);
1544 } while (0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001545
Craig Tillera82950e2015-09-22 12:33:20 -07001546 if (result != TSI_OK) {
Justin Burke49841352017-08-31 17:42:54 -07001547 tsi_ssl_handshaker_factory_unref(&impl->base);
Craig Tillera82950e2015-09-22 12:33:20 -07001548 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001549 }
Craig Tillera82950e2015-09-22 12:33:20 -07001550 }
Justin Burke49841352017-08-31 17:42:54 -07001551
Julien Boeuf935d02e2017-04-09 00:07:09 -07001552 *factory = impl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001553 return TSI_OK;
1554}
1555
1556/* --- tsi_ssl utils. --- */
1557
Craig Tillerbaa14a92017-11-03 09:09:36 -07001558int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) {
Julien Boeufb222b4d2015-01-15 17:01:39 -08001559 size_t i = 0;
Julien Boeuf597a4f22015-02-23 15:57:14 -08001560 size_t san_count = 0;
Craig Tiller4782d922017-11-10 09:53:21 -08001561 const tsi_peer_property* cn_property = nullptr;
Paul Querna47d841d2016-03-10 11:19:17 -08001562 int like_ip = looks_like_ip_address(name);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001563
Julien Boeuf597a4f22015-02-23 15:57:14 -08001564 /* Check the SAN first. */
Craig Tillera82950e2015-09-22 12:33:20 -07001565 for (i = 0; i < peer->property_count; i++) {
Craig Tillerbaa14a92017-11-03 09:09:36 -07001566 const tsi_peer_property* property = &peer->properties[i];
Craig Tiller4782d922017-11-10 09:53:21 -08001567 if (property->name == nullptr) continue;
Craig Tillera82950e2015-09-22 12:33:20 -07001568 if (strcmp(property->name,
1569 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
1570 san_count++;
Paul Querna47d841d2016-03-10 11:19:17 -08001571
1572 if (!like_ip && does_entry_match_name(property->value.data,
1573 property->value.length, name)) {
1574 return 1;
1575 } else if (like_ip &&
1576 strncmp(name, property->value.data, property->value.length) ==
1577 0 &&
1578 strlen(name) == property->value.length) {
1579 /* IP Addresses are exact matches only. */
Craig Tillera82950e2015-09-22 12:33:20 -07001580 return 1;
1581 }
1582 } else if (strcmp(property->name,
1583 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
1584 cn_property = property;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001585 }
Craig Tillera82950e2015-09-22 12:33:20 -07001586 }
Julien Boeuf597a4f22015-02-23 15:57:14 -08001587
Paul Querna47d841d2016-03-10 11:19:17 -08001588 /* If there's no SAN, try the CN, but only if its not like an IP Address */
Craig Tiller4782d922017-11-10 09:53:21 -08001589 if (san_count == 0 && cn_property != nullptr && !like_ip) {
Craig Tillera82950e2015-09-22 12:33:20 -07001590 if (does_entry_match_name(cn_property->value.data,
1591 cn_property->value.length, name)) {
1592 return 1;
Julien Boeuf597a4f22015-02-23 15:57:14 -08001593 }
Craig Tillera82950e2015-09-22 12:33:20 -07001594 }
Julien Boeuf597a4f22015-02-23 15:57:14 -08001595
Craig Tillera82950e2015-09-22 12:33:20 -07001596 return 0; /* Not found. */
Craig Tiller190d3602015-02-18 09:23:38 -08001597}
Justin Burke49841352017-08-31 17:42:54 -07001598
1599/* --- Testing support. --- */
Craig Tillerbaa14a92017-11-03 09:09:36 -07001600const tsi_ssl_handshaker_factory_vtable* tsi_ssl_handshaker_factory_swap_vtable(
1601 tsi_ssl_handshaker_factory* factory,
1602 tsi_ssl_handshaker_factory_vtable* new_vtable) {
Craig Tiller4782d922017-11-10 09:53:21 -08001603 GPR_ASSERT(factory != nullptr);
1604 GPR_ASSERT(factory->vtable != nullptr);
Justin Burke49841352017-08-31 17:42:54 -07001605
Craig Tillerbaa14a92017-11-03 09:09:36 -07001606 const tsi_ssl_handshaker_factory_vtable* orig_vtable = factory->vtable;
Justin Burke49841352017-08-31 17:42:54 -07001607 factory->vtable = new_vtable;
1608 return orig_vtable;
1609}