blob: 0ba6587678b3468ab0bfb2ea8f9a166f8716e5dc [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
Paul Querna47d841d2016-03-10 11:19:17 -080019#include <grpc/support/port_platform.h>
20
Alexander Polcyndb3e8982018-02-21 16:59:24 -080021#include "src/core/tsi/ssl_transport_security.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>
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -080038#include <grpc/support/string_util.h>
nnoble8a23a3d2014-12-16 10:10:29 -080039#include <grpc/support/sync.h>
Vijay Paic7456902018-02-12 10:28:24 -080040#include <grpc/support/thd_id.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
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -080051#include "src/core/lib/gpr/useful.h"
52#include "src/core/tsi/ssl/session_cache/ssl_session_cache.h"
Craig Tillerb29f1fe2017-03-28 15:49:23 -070053#include "src/core/tsi/ssl_types.h"
54#include "src/core/tsi/transport_security.h"
Craig Tiller0fe5ee72015-12-22 12:50:36 -080055
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080056/* --- Constants. ---*/
57
58#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND 16384
59#define TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND 1024
60
Julien Boeuf3e29de12015-06-18 23:29:13 +020061/* Putting a macro like this and littering the source file with #if is really
62 bad practice.
63 TODO(jboeuf): refactor all the #if / #endif in a separate module. */
Julien Boeufd1531322015-06-18 11:05:39 +020064#ifndef TSI_OPENSSL_ALPN_SUPPORT
65#define TSI_OPENSSL_ALPN_SUPPORT 1
66#endif
67
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080068/* TODO(jboeuf): I have not found a way to get this number dynamically from the
Julien Boeuf3e29de12015-06-18 23:29:13 +020069 SSL structure. This is what we would ultimately want though... */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080070#define TSI_SSL_MAX_PROTECTION_OVERHEAD 100
71
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080072/* --- Structure definitions. ---*/
73
jiangtaoli2016144f5552018-03-23 11:28:48 -070074struct tsi_ssl_root_certs_store {
75 X509_STORE* store;
76};
77
Justin Burke49841352017-08-31 17:42:54 -070078struct tsi_ssl_handshaker_factory {
Craig Tillerbaa14a92017-11-03 09:09:36 -070079 const tsi_ssl_handshaker_factory_vtable* vtable;
Justin Burke49841352017-08-31 17:42:54 -070080 gpr_refcount refcount;
81};
82
Julien Boeuf935d02e2017-04-09 00:07:09 -070083struct tsi_ssl_client_handshaker_factory {
Justin Burke49841352017-08-31 17:42:54 -070084 tsi_ssl_handshaker_factory base;
Craig Tillerbaa14a92017-11-03 09:09:36 -070085 SSL_CTX* ssl_context;
86 unsigned char* alpn_protocol_list;
Julien Boeufd1531322015-06-18 11:05:39 +020087 size_t alpn_protocol_list_length;
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -080088 grpc_core::RefCountedPtr<tsi::SslSessionLRUCache> session_cache;
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. */
Justin Burke49841352017-08-31 17:42:54 -070095 tsi_ssl_handshaker_factory base;
Craig Tillerbaa14a92017-11-03 09:09:36 -070096 SSL_CTX** ssl_contexts;
97 tsi_peer* ssl_context_x509_subject_names;
Julien Boeufb222b4d2015-01-15 17:01:39 -080098 size_t ssl_context_count;
Craig Tillerbaa14a92017-11-03 09:09:36 -070099 unsigned char* alpn_protocol_list;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800100 size_t alpn_protocol_list_length;
Julien Boeuf935d02e2017-04-09 00:07:09 -0700101};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800102
Craig Tillera82950e2015-09-22 12:33:20 -0700103typedef struct {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800104 tsi_handshaker base;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700105 SSL* ssl;
Ruslan Nigmatullin17226402018-01-17 18:45:53 -0800106 BIO* network_io;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800107 tsi_result result;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700108 tsi_ssl_handshaker_factory* factory_ref;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800109} tsi_ssl_handshaker;
110
Craig Tillera82950e2015-09-22 12:33:20 -0700111typedef struct {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800112 tsi_frame_protector base;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700113 SSL* ssl;
Ruslan Nigmatullin17226402018-01-17 18:45:53 -0800114 BIO* network_io;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700115 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
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -0800122static gpr_once g_init_openssl_once = GPR_ONCE_INIT;
123static gpr_mu* g_openssl_mutexes = nullptr;
124static int g_ssl_ctx_ex_factory_index = -1;
Yuchen Zengc6ae9b52018-01-04 16:29:06 -0800125static void openssl_locking_cb(int mode, int type, const char* file,
126 int line) GRPC_UNUSED;
127static unsigned long openssl_thread_id_cb(void) GRPC_UNUSED;
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -0800128static const unsigned char kSslSessionIdContext[] = {'g', 'r', 'p', 'c'};
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800129
Craig Tillerbaa14a92017-11-03 09:09:36 -0700130static void openssl_locking_cb(int mode, int type, const char* file, int line) {
Craig Tillera82950e2015-09-22 12:33:20 -0700131 if (mode & CRYPTO_LOCK) {
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -0800132 gpr_mu_lock(&g_openssl_mutexes[type]);
Craig Tillera82950e2015-09-22 12:33:20 -0700133 } else {
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -0800134 gpr_mu_unlock(&g_openssl_mutexes[type]);
Craig Tillera82950e2015-09-22 12:33:20 -0700135 }
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800136}
137
Craig Tillera82950e2015-09-22 12:33:20 -0700138static unsigned long openssl_thread_id_cb(void) {
Noah Eisenbe82e642018-02-09 09:16:55 -0800139 return static_cast<unsigned long>(gpr_thd_currentid());
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800140}
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800141
Craig Tillera82950e2015-09-22 12:33:20 -0700142static void init_openssl(void) {
Julien Boeuf4a0a3942015-02-03 15:04:45 -0800143 int i;
Craig Tiller3121fd42015-09-10 09:56:20 -0700144 int num_locks;
Craig Tillera82950e2015-09-22 12:33:20 -0700145 SSL_library_init();
146 SSL_load_error_strings();
147 OpenSSL_add_all_algorithms();
148 num_locks = CRYPTO_num_locks();
149 GPR_ASSERT(num_locks > 0);
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -0800150 g_openssl_mutexes = static_cast<gpr_mu*>(
Noah Eisen4d20a662018-02-09 09:34:04 -0800151 gpr_malloc(static_cast<size_t>(num_locks) * sizeof(gpr_mu)));
Craig Tillera82950e2015-09-22 12:33:20 -0700152 for (i = 0; i < CRYPTO_num_locks(); i++) {
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -0800153 gpr_mu_init(&g_openssl_mutexes[i]);
Craig Tillera82950e2015-09-22 12:33:20 -0700154 }
155 CRYPTO_set_locking_callback(openssl_locking_cb);
156 CRYPTO_set_id_callback(openssl_thread_id_cb);
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -0800157 g_ssl_ctx_ex_factory_index =
158 SSL_CTX_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr);
159 GPR_ASSERT(g_ssl_ctx_ex_factory_index != -1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800160}
161
162/* --- Ssl utils. ---*/
163
Craig Tillerbaa14a92017-11-03 09:09:36 -0700164static const char* ssl_error_string(int error) {
Craig Tillera82950e2015-09-22 12:33:20 -0700165 switch (error) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800166 case SSL_ERROR_NONE:
167 return "SSL_ERROR_NONE";
168 case SSL_ERROR_ZERO_RETURN:
169 return "SSL_ERROR_ZERO_RETURN";
170 case SSL_ERROR_WANT_READ:
171 return "SSL_ERROR_WANT_READ";
172 case SSL_ERROR_WANT_WRITE:
173 return "SSL_ERROR_WANT_WRITE";
174 case SSL_ERROR_WANT_CONNECT:
175 return "SSL_ERROR_WANT_CONNECT";
176 case SSL_ERROR_WANT_ACCEPT:
177 return "SSL_ERROR_WANT_ACCEPT";
178 case SSL_ERROR_WANT_X509_LOOKUP:
179 return "SSL_ERROR_WANT_X509_LOOKUP";
180 case SSL_ERROR_SYSCALL:
181 return "SSL_ERROR_SYSCALL";
182 case SSL_ERROR_SSL:
183 return "SSL_ERROR_SSL";
184 default:
185 return "Unknown error";
Craig Tillera82950e2015-09-22 12:33:20 -0700186 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800187}
188
189/* TODO(jboeuf): Remove when we are past the debugging phase with this code. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700190static void ssl_log_where_info(const SSL* ssl, int where, int flag,
191 const char* msg) {
Craig Tiller6014e8a2017-10-16 13:50:29 -0700192 if ((where & flag) && tsi_tracing_enabled.enabled()) {
Craig Tillera82950e2015-09-22 12:33:20 -0700193 gpr_log(GPR_INFO, "%20.20s - %30.30s - %5.10s", msg,
194 SSL_state_string_long(ssl), SSL_state_string(ssl));
195 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800196}
197
198/* Used for debugging. TODO(jboeuf): Remove when code is mature enough. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700199static void ssl_info_callback(const SSL* ssl, int where, int ret) {
Craig Tillera82950e2015-09-22 12:33:20 -0700200 if (ret == 0) {
201 gpr_log(GPR_ERROR, "ssl_info_callback: error occured.\n");
202 return;
203 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800204
Craig Tillera82950e2015-09-22 12:33:20 -0700205 ssl_log_where_info(ssl, where, SSL_CB_LOOP, "LOOP");
206 ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_START, "HANDSHAKE START");
207 ssl_log_where_info(ssl, where, SSL_CB_HANDSHAKE_DONE, "HANDSHAKE DONE");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800208}
209
Julien Boeuf0170a6c2015-02-24 18:08:01 -0800210/* Returns 1 if name looks like an IP address, 0 otherwise.
Paul Querna4a9e7c42016-03-13 14:00:11 -0700211 This is a very rough heuristic, and only handles IPv6 in hexadecimal form. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700212static int looks_like_ip_address(const char* name) {
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800213 size_t i;
214 size_t dot_count = 0;
215 size_t num_size = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700216 for (i = 0; i < strlen(name); i++) {
Paul Querna4a9e7c42016-03-13 14:00:11 -0700217 if (name[i] == ':') {
218 /* IPv6 Address in hexadecimal form, : is not allowed in DNS names. */
219 return 1;
220 }
Craig Tillera82950e2015-09-22 12:33:20 -0700221 if (name[i] >= '0' && name[i] <= '9') {
222 if (num_size > 3) return 0;
223 num_size++;
224 } else if (name[i] == '.') {
225 if (dot_count > 3 || num_size == 0) return 0;
226 dot_count++;
227 num_size = 0;
228 } else {
229 return 0;
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800230 }
Craig Tillera82950e2015-09-22 12:33:20 -0700231 }
232 if (dot_count < 3 || num_size == 0) return 0;
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800233 return 1;
234}
235
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800236/* Gets the subject CN from an X509 cert. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700237static tsi_result ssl_get_x509_common_name(X509* cert, unsigned char** utf8,
238 size_t* utf8_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800239 int common_name_index = -1;
Craig Tiller4782d922017-11-10 09:53:21 -0800240 X509_NAME_ENTRY* common_name_entry = nullptr;
241 ASN1_STRING* common_name_asn1 = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700242 X509_NAME* subject_name = X509_get_subject_name(cert);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800243 int utf8_returned_size = 0;
Craig Tiller4782d922017-11-10 09:53:21 -0800244 if (subject_name == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700245 gpr_log(GPR_ERROR, "Could not get subject name from certificate.");
246 return TSI_NOT_FOUND;
247 }
248 common_name_index =
249 X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
250 if (common_name_index == -1) {
251 gpr_log(GPR_ERROR,
252 "Could not get common name of subject from certificate.");
253 return TSI_NOT_FOUND;
254 }
255 common_name_entry = X509_NAME_get_entry(subject_name, common_name_index);
Craig Tiller4782d922017-11-10 09:53:21 -0800256 if (common_name_entry == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700257 gpr_log(GPR_ERROR, "Could not get common name entry from certificate.");
258 return TSI_INTERNAL_ERROR;
259 }
260 common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
Craig Tiller4782d922017-11-10 09:53:21 -0800261 if (common_name_asn1 == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700262 gpr_log(GPR_ERROR,
263 "Could not get common name entry asn1 from certificate.");
264 return TSI_INTERNAL_ERROR;
265 }
266 utf8_returned_size = ASN1_STRING_to_UTF8(utf8, common_name_asn1);
267 if (utf8_returned_size < 0) {
268 gpr_log(GPR_ERROR, "Could not extract utf8 from asn1 string.");
269 return TSI_OUT_OF_RESOURCES;
270 }
Noah Eisenbe82e642018-02-09 09:16:55 -0800271 *utf8_size = static_cast<size_t>(utf8_returned_size);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800272 return TSI_OK;
273}
274
275/* Gets the subject CN of an X509 cert as a tsi_peer_property. */
Craig Tillera82950e2015-09-22 12:33:20 -0700276static tsi_result peer_property_from_x509_common_name(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700277 X509* cert, tsi_peer_property* property) {
278 unsigned char* common_name;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800279 size_t common_name_size;
Craig Tillera82950e2015-09-22 12:33:20 -0700280 tsi_result result =
281 ssl_get_x509_common_name(cert, &common_name, &common_name_size);
282 if (result != TSI_OK) {
283 if (result == TSI_NOT_FOUND) {
Craig Tiller4782d922017-11-10 09:53:21 -0800284 common_name = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -0700285 common_name_size = 0;
286 } else {
287 return result;
Julien Boeuf9fff77e2015-02-24 16:50:35 -0800288 }
Craig Tillera82950e2015-09-22 12:33:20 -0700289 }
290 result = tsi_construct_string_peer_property(
291 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY,
Noah Eisen4d20a662018-02-09 09:34:04 -0800292 common_name == nullptr ? "" : reinterpret_cast<const char*>(common_name),
293 common_name_size, property);
Craig Tillera82950e2015-09-22 12:33:20 -0700294 OPENSSL_free(common_name);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800295 return result;
296}
297
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700298/* Gets the X509 cert in PEM format as a tsi_peer_property. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700299static tsi_result add_pem_certificate(X509* cert, tsi_peer_property* property) {
300 BIO* bio = BIO_new(BIO_s_mem());
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700301 if (!PEM_write_bio_X509(bio, cert)) {
302 BIO_free(bio);
303 return TSI_INTERNAL_ERROR;
304 }
Craig Tillerbaa14a92017-11-03 09:09:36 -0700305 char* contents;
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700306 long len = BIO_get_mem_data(bio, &contents);
307 if (len <= 0) {
308 BIO_free(bio);
309 return TSI_INTERNAL_ERROR;
310 }
311 tsi_result result = tsi_construct_string_peer_property(
Noah Eisen4d20a662018-02-09 09:34:04 -0800312 TSI_X509_PEM_CERT_PROPERTY, (const char*)contents,
313 static_cast<size_t>(len), property);
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700314 BIO_free(bio);
315 return result;
316}
317
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800318/* Gets the subject SANs from an X509 cert as a tsi_peer_property. */
Craig Tillera82950e2015-09-22 12:33:20 -0700319static tsi_result add_subject_alt_names_properties_to_peer(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700320 tsi_peer* peer, GENERAL_NAMES* subject_alt_names,
Craig Tillera82950e2015-09-22 12:33:20 -0700321 size_t subject_alt_name_count) {
Craig Tiller3121fd42015-09-10 09:56:20 -0700322 size_t i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800323 tsi_result result = TSI_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800324
325 /* Reset for DNS entries filtering. */
Julien Boeuf77e8c1c2015-05-13 13:50:59 -0700326 peer->property_count -= subject_alt_name_count;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800327
Craig Tillera82950e2015-09-22 12:33:20 -0700328 for (i = 0; i < subject_alt_name_count; i++) {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700329 GENERAL_NAME* subject_alt_name =
Craig Tiller0fe5ee72015-12-22 12:50:36 -0800330 sk_GENERAL_NAME_value(subject_alt_names, TSI_SIZE_AS_SIZE(i));
Craig Tillera82950e2015-09-22 12:33:20 -0700331 /* Filter out the non-dns entries names. */
332 if (subject_alt_name->type == GEN_DNS) {
Craig Tiller4782d922017-11-10 09:53:21 -0800333 unsigned char* name = nullptr;
Paul Querna47d841d2016-03-10 11:19:17 -0800334 int name_size;
335 name_size = ASN1_STRING_to_UTF8(&name, subject_alt_name->d.dNSName);
336 if (name_size < 0) {
Craig Tillera82950e2015-09-22 12:33:20 -0700337 gpr_log(GPR_ERROR, "Could not get utf8 from asn1 string.");
338 result = TSI_INTERNAL_ERROR;
339 break;
340 }
341 result = tsi_construct_string_peer_property(
Noah Eisen4d20a662018-02-09 09:34:04 -0800342 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY,
343 reinterpret_cast<const char*>(name), static_cast<size_t>(name_size),
344 &peer->properties[peer->property_count++]);
Paul Querna47d841d2016-03-10 11:19:17 -0800345 OPENSSL_free(name);
346 } else if (subject_alt_name->type == GEN_IPADD) {
347 char ntop_buf[INET6_ADDRSTRLEN];
348 int af;
349
350 if (subject_alt_name->d.iPAddress->length == 4) {
351 af = AF_INET;
352 } else if (subject_alt_name->d.iPAddress->length == 16) {
353 af = AF_INET6;
354 } else {
355 gpr_log(GPR_ERROR, "SAN IP Address contained invalid IP");
356 result = TSI_INTERNAL_ERROR;
357 break;
358 }
Craig Tillerbaa14a92017-11-03 09:09:36 -0700359 const char* name = inet_ntop(af, subject_alt_name->d.iPAddress->data,
Nicolas "Pixel" Noblee3df5a02016-10-27 00:41:13 +0200360 ntop_buf, INET6_ADDRSTRLEN);
Craig Tiller4782d922017-11-10 09:53:21 -0800361 if (name == nullptr) {
Paul Querna47d841d2016-03-10 11:19:17 -0800362 gpr_log(GPR_ERROR, "Could not get IP string from asn1 octet.");
363 result = TSI_INTERNAL_ERROR;
364 break;
365 }
366
367 result = tsi_construct_string_peer_property_from_cstring(
368 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY, name,
Craig Tillera82950e2015-09-22 12:33:20 -0700369 &peer->properties[peer->property_count++]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800370 }
Paul Querna47d841d2016-03-10 11:19:17 -0800371 if (result != TSI_OK) break;
Craig Tillera82950e2015-09-22 12:33:20 -0700372 }
Julien Boeuf77e8c1c2015-05-13 13:50:59 -0700373 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800374}
375
376/* Gets information about the peer's X509 cert as a tsi_peer object. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700377static tsi_result peer_from_x509(X509* cert, int include_certificate_type,
378 tsi_peer* peer) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800379 /* TODO(jboeuf): Maybe add more properties. */
Noah Eisen4d20a662018-02-09 09:34:04 -0800380 GENERAL_NAMES* subject_alt_names = static_cast<GENERAL_NAMES*>(
381 X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr));
382 int subject_alt_name_count =
383 (subject_alt_names != nullptr)
384 ? static_cast<int>(sk_GENERAL_NAME_num(subject_alt_names))
385 : 0;
Craig Tiller3121fd42015-09-10 09:56:20 -0700386 size_t property_count;
387 tsi_result result;
Craig Tillera82950e2015-09-22 12:33:20 -0700388 GPR_ASSERT(subject_alt_name_count >= 0);
Noah Eisenbe82e642018-02-09 09:16:55 -0800389 property_count = (include_certificate_type ? static_cast<size_t>(1) : 0) +
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700390 2 /* common name, certificate */ +
Noah Eisenbe82e642018-02-09 09:16:55 -0800391 static_cast<size_t>(subject_alt_name_count);
Craig Tillera82950e2015-09-22 12:33:20 -0700392 result = tsi_construct_peer(property_count, peer);
393 if (result != TSI_OK) return result;
394 do {
395 if (include_certificate_type) {
396 result = tsi_construct_string_peer_property_from_cstring(
397 TSI_CERTIFICATE_TYPE_PEER_PROPERTY, TSI_X509_CERTIFICATE_TYPE,
398 &peer->properties[0]);
399 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800400 }
Craig Tillera82950e2015-09-22 12:33:20 -0700401 result = peer_property_from_x509_common_name(
402 cert, &peer->properties[include_certificate_type ? 1 : 0]);
403 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800404
Deepak Lukosee61cbe32016-03-14 14:10:44 -0700405 result = add_pem_certificate(
406 cert, &peer->properties[include_certificate_type ? 2 : 1]);
407 if (result != TSI_OK) break;
408
Craig Tillera82950e2015-09-22 12:33:20 -0700409 if (subject_alt_name_count != 0) {
410 result = add_subject_alt_names_properties_to_peer(
Noah Eisenbe82e642018-02-09 09:16:55 -0800411 peer, subject_alt_names, static_cast<size_t>(subject_alt_name_count));
Craig Tillera82950e2015-09-22 12:33:20 -0700412 if (result != TSI_OK) break;
Craig Tiller45724b32015-09-22 10:42:19 -0700413 }
Craig Tillera82950e2015-09-22 12:33:20 -0700414 } while (0);
415
Craig Tiller4782d922017-11-10 09:53:21 -0800416 if (subject_alt_names != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700417 sk_GENERAL_NAME_pop_free(subject_alt_names, GENERAL_NAME_free);
418 }
419 if (result != TSI_OK) tsi_peer_destruct(peer);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800420 return result;
421}
422
nnoble0c475f02014-12-05 15:37:39 -0800423/* Logs the SSL error stack. */
Craig Tillera82950e2015-09-22 12:33:20 -0700424static void log_ssl_error_stack(void) {
nnoble0c475f02014-12-05 15:37:39 -0800425 unsigned long err;
Craig Tillera82950e2015-09-22 12:33:20 -0700426 while ((err = ERR_get_error()) != 0) {
427 char details[256];
Noah Eisenbe82e642018-02-09 09:16:55 -0800428 ERR_error_string_n(static_cast<uint32_t>(err), details, sizeof(details));
Craig Tillera82950e2015-09-22 12:33:20 -0700429 gpr_log(GPR_ERROR, "%s", details);
430 }
nnoble0c475f02014-12-05 15:37:39 -0800431}
432
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800433/* Performs an SSL_read and handle errors. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700434static tsi_result do_ssl_read(SSL* ssl, unsigned char* unprotected_bytes,
435 size_t* unprotected_bytes_size) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700436 int read_from_ssl;
Craig Tillera82950e2015-09-22 12:33:20 -0700437 GPR_ASSERT(*unprotected_bytes_size <= INT_MAX);
Noah Eisen4d20a662018-02-09 09:34:04 -0800438 read_from_ssl = SSL_read(ssl, unprotected_bytes,
439 static_cast<int>(*unprotected_bytes_size));
Julien Boeufce91f4a2017-05-09 15:50:33 -0700440 if (read_from_ssl <= 0) {
Craig Tillera82950e2015-09-22 12:33:20 -0700441 read_from_ssl = SSL_get_error(ssl, read_from_ssl);
442 switch (read_from_ssl) {
Julien Boeufce91f4a2017-05-09 15:50:33 -0700443 case SSL_ERROR_ZERO_RETURN: /* Received a close_notify alert. */
444 case SSL_ERROR_WANT_READ: /* We need more data to finish the frame. */
Craig Tillera82950e2015-09-22 12:33:20 -0700445 *unprotected_bytes_size = 0;
446 return TSI_OK;
447 case SSL_ERROR_WANT_WRITE:
448 gpr_log(
449 GPR_ERROR,
450 "Peer tried to renegotiate SSL connection. This is unsupported.");
451 return TSI_UNIMPLEMENTED;
452 case SSL_ERROR_SSL:
453 gpr_log(GPR_ERROR, "Corruption detected.");
454 log_ssl_error_stack();
455 return TSI_DATA_CORRUPTED;
456 default:
457 gpr_log(GPR_ERROR, "SSL_read failed with error %s.",
458 ssl_error_string(read_from_ssl));
459 return TSI_PROTOCOL_FAILURE;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800460 }
Craig Tillera82950e2015-09-22 12:33:20 -0700461 }
Noah Eisenbe82e642018-02-09 09:16:55 -0800462 *unprotected_bytes_size = static_cast<size_t>(read_from_ssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800463 return TSI_OK;
464}
465
466/* Performs an SSL_write and handle errors. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700467static tsi_result do_ssl_write(SSL* ssl, unsigned char* unprotected_bytes,
Craig Tillera82950e2015-09-22 12:33:20 -0700468 size_t unprotected_bytes_size) {
Craig Tillerf96dfc32015-09-10 14:43:18 -0700469 int ssl_write_result;
Craig Tillera82950e2015-09-22 12:33:20 -0700470 GPR_ASSERT(unprotected_bytes_size <= INT_MAX);
Noah Eisen4d20a662018-02-09 09:34:04 -0800471 ssl_write_result = SSL_write(ssl, unprotected_bytes,
472 static_cast<int>(unprotected_bytes_size));
Craig Tillera82950e2015-09-22 12:33:20 -0700473 if (ssl_write_result < 0) {
474 ssl_write_result = SSL_get_error(ssl, ssl_write_result);
475 if (ssl_write_result == SSL_ERROR_WANT_READ) {
476 gpr_log(GPR_ERROR,
477 "Peer tried to renegotiate SSL connection. This is unsupported.");
478 return TSI_UNIMPLEMENTED;
479 } else {
480 gpr_log(GPR_ERROR, "SSL_write failed with error %s.",
481 ssl_error_string(ssl_write_result));
482 return TSI_INTERNAL_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800483 }
Craig Tillera82950e2015-09-22 12:33:20 -0700484 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800485 return TSI_OK;
486}
487
488/* Loads an in-memory PEM certificate chain into the SSL context. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700489static tsi_result ssl_ctx_use_certificate_chain(SSL_CTX* context,
490 const char* pem_cert_chain,
Julien Boeufb71ef652017-04-12 21:44:49 -0700491 size_t pem_cert_chain_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800492 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -0800493 X509* certificate = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700494 BIO* pem;
Craig Tillera82950e2015-09-22 12:33:20 -0700495 GPR_ASSERT(pem_cert_chain_size <= INT_MAX);
Noah Eisen4d20a662018-02-09 09:34:04 -0800496 pem = BIO_new_mem_buf((void*)pem_cert_chain,
497 static_cast<int>(pem_cert_chain_size));
Craig Tiller4782d922017-11-10 09:53:21 -0800498 if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800499
Craig Tillera82950e2015-09-22 12:33:20 -0700500 do {
Craig Tiller4782d922017-11-10 09:53:21 -0800501 certificate = PEM_read_bio_X509_AUX(pem, nullptr, nullptr, (void*)"");
502 if (certificate == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700503 result = TSI_INVALID_ARGUMENT;
504 break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800505 }
Craig Tillera82950e2015-09-22 12:33:20 -0700506 if (!SSL_CTX_use_certificate(context, certificate)) {
507 result = TSI_INVALID_ARGUMENT;
508 break;
509 }
510 while (1) {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700511 X509* certificate_authority =
Craig Tiller4782d922017-11-10 09:53:21 -0800512 PEM_read_bio_X509(pem, nullptr, nullptr, (void*)"");
513 if (certificate_authority == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700514 ERR_clear_error();
515 break; /* Done reading. */
516 }
517 if (!SSL_CTX_add_extra_chain_cert(context, certificate_authority)) {
518 X509_free(certificate_authority);
519 result = TSI_INVALID_ARGUMENT;
520 break;
521 }
522 /* We don't need to free certificate_authority as its ownership has been
523 transfered to the context. That is not the case for certificate though.
524 */
525 }
526 } while (0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800527
Craig Tiller4782d922017-11-10 09:53:21 -0800528 if (certificate != nullptr) X509_free(certificate);
Craig Tillera82950e2015-09-22 12:33:20 -0700529 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800530 return result;
531}
532
533/* Loads an in-memory PEM private key into the SSL context. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700534static tsi_result ssl_ctx_use_private_key(SSL_CTX* context, const char* pem_key,
Craig Tillera82950e2015-09-22 12:33:20 -0700535 size_t pem_key_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800536 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -0800537 EVP_PKEY* private_key = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700538 BIO* pem;
Craig Tillera82950e2015-09-22 12:33:20 -0700539 GPR_ASSERT(pem_key_size <= INT_MAX);
Noah Eisenbe82e642018-02-09 09:16:55 -0800540 pem = BIO_new_mem_buf((void*)pem_key, static_cast<int>(pem_key_size));
Craig Tiller4782d922017-11-10 09:53:21 -0800541 if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
Craig Tillera82950e2015-09-22 12:33:20 -0700542 do {
Craig Tiller4782d922017-11-10 09:53:21 -0800543 private_key = PEM_read_bio_PrivateKey(pem, nullptr, nullptr, (void*)"");
544 if (private_key == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700545 result = TSI_INVALID_ARGUMENT;
546 break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800547 }
Craig Tillera82950e2015-09-22 12:33:20 -0700548 if (!SSL_CTX_use_PrivateKey(context, private_key)) {
549 result = TSI_INVALID_ARGUMENT;
550 break;
551 }
552 } while (0);
Craig Tiller4782d922017-11-10 09:53:21 -0800553 if (private_key != nullptr) EVP_PKEY_free(private_key);
Craig Tillera82950e2015-09-22 12:33:20 -0700554 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800555 return result;
556}
557
558/* Loads in-memory PEM verification certs into the SSL context and optionally
559 returns the verification cert names (root_names can be NULL). */
jiangtaoli2016144f5552018-03-23 11:28:48 -0700560static tsi_result x509_store_load_certs(X509_STORE* cert_store,
561 const char* pem_roots,
562 size_t pem_roots_size,
563 STACK_OF(X509_NAME) * *root_names) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800564 tsi_result result = TSI_OK;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800565 size_t num_roots = 0;
Craig Tiller4782d922017-11-10 09:53:21 -0800566 X509* root = nullptr;
567 X509_NAME* root_name = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700568 BIO* pem;
Craig Tillera82950e2015-09-22 12:33:20 -0700569 GPR_ASSERT(pem_roots_size <= INT_MAX);
Noah Eisenbe82e642018-02-09 09:16:55 -0800570 pem = BIO_new_mem_buf((void*)pem_roots, static_cast<int>(pem_roots_size));
jiangtaoli2016144f5552018-03-23 11:28:48 -0700571 if (cert_store == nullptr) return TSI_INVALID_ARGUMENT;
Craig Tiller4782d922017-11-10 09:53:21 -0800572 if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
573 if (root_names != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700574 *root_names = sk_X509_NAME_new_null();
Craig Tiller4782d922017-11-10 09:53:21 -0800575 if (*root_names == nullptr) return TSI_OUT_OF_RESOURCES;
Craig Tillera82950e2015-09-22 12:33:20 -0700576 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800577
Craig Tillera82950e2015-09-22 12:33:20 -0700578 while (1) {
Craig Tiller4782d922017-11-10 09:53:21 -0800579 root = PEM_read_bio_X509_AUX(pem, nullptr, nullptr, (void*)"");
580 if (root == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700581 ERR_clear_error();
582 break; /* We're at the end of stream. */
nnoble0c475f02014-12-05 15:37:39 -0800583 }
Craig Tiller4782d922017-11-10 09:53:21 -0800584 if (root_names != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700585 root_name = X509_get_subject_name(root);
Craig Tiller4782d922017-11-10 09:53:21 -0800586 if (root_name == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700587 gpr_log(GPR_ERROR, "Could not get name from root certificate.");
588 result = TSI_INVALID_ARGUMENT;
589 break;
590 }
591 root_name = X509_NAME_dup(root_name);
Craig Tiller4782d922017-11-10 09:53:21 -0800592 if (root_name == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700593 result = TSI_OUT_OF_RESOURCES;
594 break;
595 }
596 sk_X509_NAME_push(*root_names, root_name);
Craig Tiller4782d922017-11-10 09:53:21 -0800597 root_name = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -0700598 }
jiangtaoli2016144f5552018-03-23 11:28:48 -0700599 if (!X509_STORE_add_cert(cert_store, root)) {
Craig Tillera82950e2015-09-22 12:33:20 -0700600 gpr_log(GPR_ERROR, "Could not add root certificate to ssl context.");
601 result = TSI_INTERNAL_ERROR;
602 break;
603 }
604 X509_free(root);
605 num_roots++;
606 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800607
Craig Tillera82950e2015-09-22 12:33:20 -0700608 if (num_roots == 0) {
609 gpr_log(GPR_ERROR, "Could not load any root certificate.");
610 result = TSI_INVALID_ARGUMENT;
611 }
Craig Tiller45724b32015-09-22 10:42:19 -0700612
Craig Tillera82950e2015-09-22 12:33:20 -0700613 if (result != TSI_OK) {
Craig Tiller4782d922017-11-10 09:53:21 -0800614 if (root != nullptr) X509_free(root);
615 if (root_names != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700616 sk_X509_NAME_pop_free(*root_names, X509_NAME_free);
Craig Tiller4782d922017-11-10 09:53:21 -0800617 *root_names = nullptr;
618 if (root_name != nullptr) X509_NAME_free(root_name);
Craig Tiller45724b32015-09-22 10:42:19 -0700619 }
Craig Tillera82950e2015-09-22 12:33:20 -0700620 }
621 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800622 return result;
623}
624
jiangtaoli2016144f5552018-03-23 11:28:48 -0700625static tsi_result ssl_ctx_load_verification_certs(SSL_CTX* context,
626 const char* pem_roots,
627 size_t pem_roots_size,
628 STACK_OF(X509_NAME) *
629 *root_name) {
630 X509_STORE* cert_store = SSL_CTX_get_cert_store(context);
631 return x509_store_load_certs(cert_store, pem_roots, pem_roots_size,
632 root_name);
633}
634
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800635/* Populates the SSL context with a private key and a cert chain, and sets the
636 cipher list and the ephemeral ECDH key. */
Craig Tillera82950e2015-09-22 12:33:20 -0700637static tsi_result populate_ssl_context(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700638 SSL_CTX* context, const tsi_ssl_pem_key_cert_pair* key_cert_pair,
639 const char* cipher_list) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800640 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -0800641 if (key_cert_pair != nullptr) {
642 if (key_cert_pair->cert_chain != nullptr) {
Julien Boeufb71ef652017-04-12 21:44:49 -0700643 result = ssl_ctx_use_certificate_chain(context, key_cert_pair->cert_chain,
644 strlen(key_cert_pair->cert_chain));
645 if (result != TSI_OK) {
646 gpr_log(GPR_ERROR, "Invalid cert chain file.");
647 return result;
648 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800649 }
Craig Tiller4782d922017-11-10 09:53:21 -0800650 if (key_cert_pair->private_key != nullptr) {
Julien Boeufb71ef652017-04-12 21:44:49 -0700651 result = ssl_ctx_use_private_key(context, key_cert_pair->private_key,
652 strlen(key_cert_pair->private_key));
653 if (result != TSI_OK || !SSL_CTX_check_private_key(context)) {
654 gpr_log(GPR_ERROR, "Invalid private key.");
655 return result != TSI_OK ? result : TSI_INVALID_ARGUMENT;
656 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800657 }
Craig Tillera82950e2015-09-22 12:33:20 -0700658 }
Craig Tillerbe98d242017-11-10 15:26:57 -0800659 if ((cipher_list != nullptr) &&
660 !SSL_CTX_set_cipher_list(context, cipher_list)) {
Craig Tillera82950e2015-09-22 12:33:20 -0700661 gpr_log(GPR_ERROR, "Invalid cipher list: %s.", cipher_list);
662 return TSI_INVALID_ARGUMENT;
663 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800664 {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700665 EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
Craig Tillera82950e2015-09-22 12:33:20 -0700666 if (!SSL_CTX_set_tmp_ecdh(context, ecdh)) {
667 gpr_log(GPR_ERROR, "Could not set ephemeral ECDH key.");
668 EC_KEY_free(ecdh);
669 return TSI_INTERNAL_ERROR;
670 }
671 SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
672 EC_KEY_free(ecdh);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800673 }
674 return TSI_OK;
675}
676
677/* Extracts the CN and the SANs from an X509 cert as a peer object. */
Craig Tillerbaa14a92017-11-03 09:09:36 -0700678static tsi_result extract_x509_subject_names_from_pem_cert(const char* pem_cert,
679 tsi_peer* peer) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800680 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -0800681 X509* cert = nullptr;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700682 BIO* pem;
Noah Eisenbe82e642018-02-09 09:16:55 -0800683 pem = BIO_new_mem_buf((void*)pem_cert, static_cast<int>(strlen(pem_cert)));
Craig Tiller4782d922017-11-10 09:53:21 -0800684 if (pem == nullptr) return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800685
Craig Tiller4782d922017-11-10 09:53:21 -0800686 cert = PEM_read_bio_X509(pem, nullptr, nullptr, (void*)"");
687 if (cert == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -0700688 gpr_log(GPR_ERROR, "Invalid certificate");
689 result = TSI_INVALID_ARGUMENT;
690 } else {
691 result = peer_from_x509(cert, 0, peer);
692 }
Craig Tiller4782d922017-11-10 09:53:21 -0800693 if (cert != nullptr) X509_free(cert);
Craig Tillera82950e2015-09-22 12:33:20 -0700694 BIO_free(pem);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800695 return result;
696}
697
698/* Builds the alpn protocol name list according to rfc 7301. */
Craig Tillera82950e2015-09-22 12:33:20 -0700699static tsi_result build_alpn_protocol_name_list(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700700 const char** alpn_protocols, uint16_t num_alpn_protocols,
701 unsigned char** protocol_name_list, size_t* protocol_name_list_length) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800702 uint16_t i;
Craig Tillerbaa14a92017-11-03 09:09:36 -0700703 unsigned char* current;
Craig Tiller4782d922017-11-10 09:53:21 -0800704 *protocol_name_list = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800705 *protocol_name_list_length = 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700706 if (num_alpn_protocols == 0) return TSI_INVALID_ARGUMENT;
707 for (i = 0; i < num_alpn_protocols; i++) {
Craig Tillerbe98d242017-11-10 15:26:57 -0800708 size_t length =
709 alpn_protocols[i] == nullptr ? 0 : strlen(alpn_protocols[i]);
Julien Boeufb71ef652017-04-12 21:44:49 -0700710 if (length == 0 || length > 255) {
Noah Eisen4d20a662018-02-09 09:34:04 -0800711 gpr_log(GPR_ERROR, "Invalid protocol name length: %d.",
712 static_cast<int>(length));
Craig Tillera82950e2015-09-22 12:33:20 -0700713 return TSI_INVALID_ARGUMENT;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800714 }
Julien Boeufb71ef652017-04-12 21:44:49 -0700715 *protocol_name_list_length += length + 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700716 }
Noah Eisen4d20a662018-02-09 09:34:04 -0800717 *protocol_name_list =
718 static_cast<unsigned char*>(gpr_malloc(*protocol_name_list_length));
Craig Tiller4782d922017-11-10 09:53:21 -0800719 if (*protocol_name_list == nullptr) return TSI_OUT_OF_RESOURCES;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800720 current = *protocol_name_list;
Craig Tillera82950e2015-09-22 12:33:20 -0700721 for (i = 0; i < num_alpn_protocols; i++) {
Julien Boeufb71ef652017-04-12 21:44:49 -0700722 size_t length = strlen(alpn_protocols[i]);
Noah Eisenbe82e642018-02-09 09:16:55 -0800723 *(current++) = static_cast<uint8_t>(length); /* max checked above. */
Julien Boeufb71ef652017-04-12 21:44:49 -0700724 memcpy(current, alpn_protocols[i], length);
725 current += length;
Craig Tillera82950e2015-09-22 12:33:20 -0700726 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800727 /* Safety check. */
Craig Tillera82950e2015-09-22 12:33:20 -0700728 if ((current < *protocol_name_list) ||
Noah Eisenbe82e642018-02-09 09:16:55 -0800729 (static_cast<uintptr_t>(current - *protocol_name_list) !=
Craig Tillera82950e2015-09-22 12:33:20 -0700730 *protocol_name_list_length)) {
731 return TSI_INTERNAL_ERROR;
732 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800733 return TSI_OK;
734}
735
Deepak Lukosedba4c5f2016-03-25 12:54:25 -0700736// The verification callback is used for clients that don't really care about
737// the server's certificate, but we need to pull it anyway, in case a higher
738// layer wants to look at it. In this case the verification may fail, but
739// we don't really care.
Craig Tillerbaa14a92017-11-03 09:09:36 -0700740static int NullVerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
Deepak Lukosedba4c5f2016-03-25 12:54:25 -0700741 return 1;
742}
743
jiangtaoli2016144f5552018-03-23 11:28:48 -0700744/* --- tsi_ssl_root_certs_store methods implementation. ---*/
745
746tsi_ssl_root_certs_store* tsi_ssl_root_certs_store_create(
747 const char* pem_roots) {
748 if (pem_roots == nullptr) {
749 gpr_log(GPR_ERROR, "The root certificates are empty.");
750 return nullptr;
751 }
752 tsi_ssl_root_certs_store* root_store = static_cast<tsi_ssl_root_certs_store*>(
753 gpr_zalloc(sizeof(tsi_ssl_root_certs_store)));
754 if (root_store == nullptr) {
755 gpr_log(GPR_ERROR, "Could not allocate buffer for ssl_root_certs_store.");
756 return nullptr;
757 }
758 root_store->store = X509_STORE_new();
759 if (root_store->store == nullptr) {
760 gpr_log(GPR_ERROR, "Could not allocate buffer for X509_STORE.");
761 gpr_free(root_store);
762 return nullptr;
763 }
764 tsi_result result = x509_store_load_certs(root_store->store, pem_roots,
765 strlen(pem_roots), nullptr);
766 if (result != TSI_OK) {
767 gpr_log(GPR_ERROR, "Could not load root certificates.");
768 X509_STORE_free(root_store->store);
769 gpr_free(root_store);
770 return nullptr;
771 }
772 return root_store;
773}
774
775void tsi_ssl_root_certs_store_destroy(tsi_ssl_root_certs_store* self) {
776 if (self == nullptr) return;
777 X509_STORE_free(self->store);
778 gpr_free(self);
779}
780
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -0800781/* --- tsi_ssl_session_cache methods implementation. ---*/
782
783tsi_ssl_session_cache* tsi_ssl_session_cache_create_lru(size_t capacity) {
784 /* Pointer will be dereferenced by unref call. */
785 return reinterpret_cast<tsi_ssl_session_cache*>(
786 tsi::SslSessionLRUCache::Create(capacity).release());
787}
788
789void tsi_ssl_session_cache_ref(tsi_ssl_session_cache* cache) {
790 /* Pointer will be dereferenced by unref call. */
791 reinterpret_cast<tsi::SslSessionLRUCache*>(cache)->Ref().release();
792}
793
794void tsi_ssl_session_cache_unref(tsi_ssl_session_cache* cache) {
795 reinterpret_cast<tsi::SslSessionLRUCache*>(cache)->Unref();
796}
797
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800798/* --- tsi_frame_protector methods implementation. ---*/
799
Craig Tillerbaa14a92017-11-03 09:09:36 -0700800static tsi_result ssl_protector_protect(tsi_frame_protector* self,
801 const unsigned char* unprotected_bytes,
802 size_t* unprotected_bytes_size,
803 unsigned char* protected_output_frames,
804 size_t* protected_output_frames_size) {
Noah Eisen4d20a662018-02-09 09:34:04 -0800805 tsi_ssl_frame_protector* impl =
806 reinterpret_cast<tsi_ssl_frame_protector*>(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800807 int read_from_ssl;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800808 size_t available;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800809 tsi_result result = TSI_OK;
810
811 /* First see if we have some pending data in the SSL BIO. */
Noah Eisenbe82e642018-02-09 09:16:55 -0800812 int pending_in_ssl = static_cast<int>(BIO_pending(impl->network_io));
Craig Tillera82950e2015-09-22 12:33:20 -0700813 if (pending_in_ssl > 0) {
814 *unprotected_bytes_size = 0;
815 GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -0800816 read_from_ssl = BIO_read(impl->network_io, protected_output_frames,
Noah Eisenbe82e642018-02-09 09:16:55 -0800817 static_cast<int>(*protected_output_frames_size));
Craig Tillera82950e2015-09-22 12:33:20 -0700818 if (read_from_ssl < 0) {
819 gpr_log(GPR_ERROR,
820 "Could not read from BIO even though some data is pending");
821 return TSI_INTERNAL_ERROR;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800822 }
Noah Eisenbe82e642018-02-09 09:16:55 -0800823 *protected_output_frames_size = static_cast<size_t>(read_from_ssl);
Craig Tillera82950e2015-09-22 12:33:20 -0700824 return TSI_OK;
825 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800826
827 /* Now see if we can send a complete frame. */
828 available = impl->buffer_size - impl->buffer_offset;
Craig Tillera82950e2015-09-22 12:33:20 -0700829 if (available > *unprotected_bytes_size) {
830 /* If we cannot, just copy the data in our internal buffer. */
831 memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes,
832 *unprotected_bytes_size);
833 impl->buffer_offset += *unprotected_bytes_size;
834 *protected_output_frames_size = 0;
835 return TSI_OK;
836 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800837
838 /* If we can, prepare the buffer, send it to SSL_write and read. */
Craig Tillera82950e2015-09-22 12:33:20 -0700839 memcpy(impl->buffer + impl->buffer_offset, unprotected_bytes, available);
840 result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_size);
841 if (result != TSI_OK) return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800842
Craig Tillera82950e2015-09-22 12:33:20 -0700843 GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -0800844 read_from_ssl = BIO_read(impl->network_io, protected_output_frames,
Noah Eisenbe82e642018-02-09 09:16:55 -0800845 static_cast<int>(*protected_output_frames_size));
Craig Tillera82950e2015-09-22 12:33:20 -0700846 if (read_from_ssl < 0) {
847 gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
848 return TSI_INTERNAL_ERROR;
849 }
Noah Eisenbe82e642018-02-09 09:16:55 -0800850 *protected_output_frames_size = static_cast<size_t>(read_from_ssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800851 *unprotected_bytes_size = available;
852 impl->buffer_offset = 0;
853 return TSI_OK;
854}
855
Craig Tillera82950e2015-09-22 12:33:20 -0700856static tsi_result ssl_protector_protect_flush(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700857 tsi_frame_protector* self, unsigned char* protected_output_frames,
858 size_t* protected_output_frames_size, size_t* still_pending_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800859 tsi_result result = TSI_OK;
Noah Eisen4d20a662018-02-09 09:34:04 -0800860 tsi_ssl_frame_protector* impl =
861 reinterpret_cast<tsi_ssl_frame_protector*>(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800862 int read_from_ssl = 0;
Craig Tiller3121fd42015-09-10 09:56:20 -0700863 int pending;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800864
Craig Tillera82950e2015-09-22 12:33:20 -0700865 if (impl->buffer_offset != 0) {
866 result = do_ssl_write(impl->ssl, impl->buffer, impl->buffer_offset);
867 if (result != TSI_OK) return result;
868 impl->buffer_offset = 0;
869 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800870
Noah Eisenbe82e642018-02-09 09:16:55 -0800871 pending = static_cast<int>(BIO_pending(impl->network_io));
Craig Tillera82950e2015-09-22 12:33:20 -0700872 GPR_ASSERT(pending >= 0);
Noah Eisenbe82e642018-02-09 09:16:55 -0800873 *still_pending_size = static_cast<size_t>(pending);
Craig Tillera82950e2015-09-22 12:33:20 -0700874 if (*still_pending_size == 0) return TSI_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800875
Craig Tillera82950e2015-09-22 12:33:20 -0700876 GPR_ASSERT(*protected_output_frames_size <= INT_MAX);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -0800877 read_from_ssl = BIO_read(impl->network_io, protected_output_frames,
Noah Eisenbe82e642018-02-09 09:16:55 -0800878 static_cast<int>(*protected_output_frames_size));
Craig Tillera82950e2015-09-22 12:33:20 -0700879 if (read_from_ssl <= 0) {
880 gpr_log(GPR_ERROR, "Could not read from BIO after SSL_write.");
881 return TSI_INTERNAL_ERROR;
882 }
Noah Eisenbe82e642018-02-09 09:16:55 -0800883 *protected_output_frames_size = static_cast<size_t>(read_from_ssl);
884 pending = static_cast<int>(BIO_pending(impl->network_io));
Craig Tillera82950e2015-09-22 12:33:20 -0700885 GPR_ASSERT(pending >= 0);
Noah Eisenbe82e642018-02-09 09:16:55 -0800886 *still_pending_size = static_cast<size_t>(pending);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800887 return TSI_OK;
888}
889
Craig Tillera82950e2015-09-22 12:33:20 -0700890static tsi_result ssl_protector_unprotect(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700891 tsi_frame_protector* self, const unsigned char* protected_frames_bytes,
892 size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes,
893 size_t* unprotected_bytes_size) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800894 tsi_result result = TSI_OK;
895 int written_into_ssl = 0;
Julien Boeufb222b4d2015-01-15 17:01:39 -0800896 size_t output_bytes_size = *unprotected_bytes_size;
897 size_t output_bytes_offset = 0;
Noah Eisen4d20a662018-02-09 09:34:04 -0800898 tsi_ssl_frame_protector* impl =
899 reinterpret_cast<tsi_ssl_frame_protector*>(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800900
901 /* First, try to read remaining data from ssl. */
Craig Tillera82950e2015-09-22 12:33:20 -0700902 result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
903 if (result != TSI_OK) return result;
904 if (*unprotected_bytes_size == output_bytes_size) {
905 /* We have read everything we could and cannot process any more input. */
906 *protected_frames_bytes_size = 0;
907 return TSI_OK;
908 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800909 output_bytes_offset = *unprotected_bytes_size;
910 unprotected_bytes += output_bytes_offset;
911 *unprotected_bytes_size = output_bytes_size - output_bytes_offset;
912
913 /* Then, try to write some data to ssl. */
Craig Tillera82950e2015-09-22 12:33:20 -0700914 GPR_ASSERT(*protected_frames_bytes_size <= INT_MAX);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -0800915 written_into_ssl = BIO_write(impl->network_io, protected_frames_bytes,
Noah Eisenbe82e642018-02-09 09:16:55 -0800916 static_cast<int>(*protected_frames_bytes_size));
Craig Tillera82950e2015-09-22 12:33:20 -0700917 if (written_into_ssl < 0) {
918 gpr_log(GPR_ERROR, "Sending protected frame to ssl failed with %d",
919 written_into_ssl);
920 return TSI_INTERNAL_ERROR;
921 }
Noah Eisenbe82e642018-02-09 09:16:55 -0800922 *protected_frames_bytes_size = static_cast<size_t>(written_into_ssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800923
924 /* Now try to read some data again. */
Craig Tillera82950e2015-09-22 12:33:20 -0700925 result = do_ssl_read(impl->ssl, unprotected_bytes, unprotected_bytes_size);
926 if (result == TSI_OK) {
927 /* Don't forget to output the total number of bytes read. */
928 *unprotected_bytes_size += output_bytes_offset;
929 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800930 return result;
931}
932
Craig Tillerbaa14a92017-11-03 09:09:36 -0700933static void ssl_protector_destroy(tsi_frame_protector* self) {
Noah Eisen4d20a662018-02-09 09:34:04 -0800934 tsi_ssl_frame_protector* impl =
935 reinterpret_cast<tsi_ssl_frame_protector*>(self);
Craig Tiller4782d922017-11-10 09:53:21 -0800936 if (impl->buffer != nullptr) gpr_free(impl->buffer);
937 if (impl->ssl != nullptr) SSL_free(impl->ssl);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -0800938 if (impl->network_io != nullptr) BIO_free(impl->network_io);
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +0100939 gpr_free(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800940}
941
942static const tsi_frame_protector_vtable frame_protector_vtable = {
Craig Tillerbaa14a92017-11-03 09:09:36 -0700943 ssl_protector_protect,
944 ssl_protector_protect_flush,
945 ssl_protector_unprotect,
Craig Tillera82950e2015-09-22 12:33:20 -0700946 ssl_protector_destroy,
Craig Tillerd6c98df2015-08-18 09:33:44 -0700947};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800948
Justin Burke49841352017-08-31 17:42:54 -0700949/* --- tsi_server_handshaker_factory methods implementation. --- */
950
951static void tsi_ssl_handshaker_factory_destroy(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700952 tsi_ssl_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -0800953 if (self == nullptr) return;
Justin Burke49841352017-08-31 17:42:54 -0700954
Craig Tiller4782d922017-11-10 09:53:21 -0800955 if (self->vtable != nullptr && self->vtable->destroy != nullptr) {
Justin Burke49841352017-08-31 17:42:54 -0700956 self->vtable->destroy(self);
957 }
958 /* Note, we don't free(self) here because this object is always directly
959 * embedded in another object. If tsi_ssl_handshaker_factory_init allocates
960 * any memory, it should be free'd here. */
961}
962
Craig Tillerbaa14a92017-11-03 09:09:36 -0700963static tsi_ssl_handshaker_factory* tsi_ssl_handshaker_factory_ref(
964 tsi_ssl_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -0800965 if (self == nullptr) return nullptr;
Justin Burke49841352017-08-31 17:42:54 -0700966 gpr_refn(&self->refcount, 1);
967 return self;
968}
969
Craig Tillerbaa14a92017-11-03 09:09:36 -0700970static void tsi_ssl_handshaker_factory_unref(tsi_ssl_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -0800971 if (self == nullptr) return;
Justin Burke49841352017-08-31 17:42:54 -0700972
973 if (gpr_unref(&self->refcount)) {
974 tsi_ssl_handshaker_factory_destroy(self);
975 }
976}
977
Craig Tiller4782d922017-11-10 09:53:21 -0800978static tsi_ssl_handshaker_factory_vtable handshaker_factory_vtable = {nullptr};
Justin Burke49841352017-08-31 17:42:54 -0700979
980/* Initializes a tsi_ssl_handshaker_factory object. Caller is responsible for
981 * allocating memory for the factory. */
982static void tsi_ssl_handshaker_factory_init(
Craig Tillerbaa14a92017-11-03 09:09:36 -0700983 tsi_ssl_handshaker_factory* factory) {
Craig Tiller4782d922017-11-10 09:53:21 -0800984 GPR_ASSERT(factory != nullptr);
Justin Burke49841352017-08-31 17:42:54 -0700985
986 factory->vtable = &handshaker_factory_vtable;
987 gpr_ref_init(&factory->refcount, 1);
988}
989
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800990/* --- tsi_handshaker methods implementation. ---*/
991
Craig Tillerbaa14a92017-11-03 09:09:36 -0700992static tsi_result ssl_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self,
993 unsigned char* bytes,
994 size_t* bytes_size) {
Noah Eisenbe82e642018-02-09 09:16:55 -0800995 tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800996 int bytes_read_from_ssl = 0;
Craig Tiller4782d922017-11-10 09:53:21 -0800997 if (bytes == nullptr || bytes_size == nullptr || *bytes_size == 0 ||
Craig Tillera82950e2015-09-22 12:33:20 -0700998 *bytes_size > INT_MAX) {
999 return TSI_INVALID_ARGUMENT;
1000 }
1001 GPR_ASSERT(*bytes_size <= INT_MAX);
Noah Eisen4d20a662018-02-09 09:34:04 -08001002 bytes_read_from_ssl =
1003 BIO_read(impl->network_io, bytes, static_cast<int>(*bytes_size));
Craig Tillera82950e2015-09-22 12:33:20 -07001004 if (bytes_read_from_ssl < 0) {
1005 *bytes_size = 0;
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001006 if (!BIO_should_retry(impl->network_io)) {
Craig Tillera82950e2015-09-22 12:33:20 -07001007 impl->result = TSI_INTERNAL_ERROR;
1008 return impl->result;
1009 } else {
1010 return TSI_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001011 }
Craig Tillera82950e2015-09-22 12:33:20 -07001012 }
Noah Eisenbe82e642018-02-09 09:16:55 -08001013 *bytes_size = static_cast<size_t>(bytes_read_from_ssl);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001014 return BIO_pending(impl->network_io) == 0 ? TSI_OK : TSI_INCOMPLETE_DATA;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001015}
1016
Craig Tillerbaa14a92017-11-03 09:09:36 -07001017static tsi_result ssl_handshaker_get_result(tsi_handshaker* self) {
Noah Eisenbe82e642018-02-09 09:16:55 -08001018 tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
Craig Tillera82950e2015-09-22 12:33:20 -07001019 if ((impl->result == TSI_HANDSHAKE_IN_PROGRESS) &&
1020 SSL_is_init_finished(impl->ssl)) {
1021 impl->result = TSI_OK;
1022 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001023 return impl->result;
1024}
1025
Craig Tillera82950e2015-09-22 12:33:20 -07001026static tsi_result ssl_handshaker_process_bytes_from_peer(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001027 tsi_handshaker* self, const unsigned char* bytes, size_t* bytes_size) {
Noah Eisenbe82e642018-02-09 09:16:55 -08001028 tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001029 int bytes_written_into_ssl_size = 0;
Craig Tiller4782d922017-11-10 09:53:21 -08001030 if (bytes == nullptr || bytes_size == nullptr || *bytes_size > INT_MAX) {
Craig Tillera82950e2015-09-22 12:33:20 -07001031 return TSI_INVALID_ARGUMENT;
1032 }
1033 GPR_ASSERT(*bytes_size <= INT_MAX);
1034 bytes_written_into_ssl_size =
Noah Eisenbe82e642018-02-09 09:16:55 -08001035 BIO_write(impl->network_io, bytes, static_cast<int>(*bytes_size));
Craig Tillera82950e2015-09-22 12:33:20 -07001036 if (bytes_written_into_ssl_size < 0) {
1037 gpr_log(GPR_ERROR, "Could not write to memory BIO.");
1038 impl->result = TSI_INTERNAL_ERROR;
1039 return impl->result;
1040 }
Noah Eisenbe82e642018-02-09 09:16:55 -08001041 *bytes_size = static_cast<size_t>(bytes_written_into_ssl_size);
Craig Tiller45724b32015-09-22 10:42:19 -07001042
Craig Tillera82950e2015-09-22 12:33:20 -07001043 if (!tsi_handshaker_is_in_progress(self)) {
1044 impl->result = TSI_OK;
1045 return impl->result;
1046 } else {
1047 /* Get ready to get some bytes from SSL. */
1048 int ssl_result = SSL_do_handshake(impl->ssl);
1049 ssl_result = SSL_get_error(impl->ssl, ssl_result);
1050 switch (ssl_result) {
1051 case SSL_ERROR_WANT_READ:
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001052 if (BIO_pending(impl->network_io) == 0) {
Craig Tillera82950e2015-09-22 12:33:20 -07001053 /* We need more data. */
1054 return TSI_INCOMPLETE_DATA;
1055 } else {
1056 return TSI_OK;
1057 }
1058 case SSL_ERROR_NONE:
1059 return TSI_OK;
1060 default: {
1061 char err_str[256];
1062 ERR_error_string_n(ERR_get_error(), err_str, sizeof(err_str));
1063 gpr_log(GPR_ERROR, "Handshake failed with fatal error %s: %s.",
1064 ssl_error_string(ssl_result), err_str);
1065 impl->result = TSI_PROTOCOL_FAILURE;
1066 return impl->result;
1067 }
Craig Tiller45724b32015-09-22 10:42:19 -07001068 }
Craig Tillera82950e2015-09-22 12:33:20 -07001069 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001070}
1071
Craig Tillerbaa14a92017-11-03 09:09:36 -07001072static tsi_result ssl_handshaker_extract_peer(tsi_handshaker* self,
1073 tsi_peer* peer) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001074 tsi_result result = TSI_OK;
Craig Tiller4782d922017-11-10 09:53:21 -08001075 const unsigned char* alpn_selected = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001076 unsigned int alpn_selected_len;
Noah Eisenbe82e642018-02-09 09:16:55 -08001077 tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
Craig Tillerbaa14a92017-11-03 09:09:36 -07001078 X509* peer_cert = SSL_get_peer_certificate(impl->ssl);
Craig Tiller4782d922017-11-10 09:53:21 -08001079 if (peer_cert != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001080 result = peer_from_x509(peer_cert, 1, peer);
1081 X509_free(peer_cert);
1082 if (result != TSI_OK) return result;
1083 }
Julien Boeufd1531322015-06-18 11:05:39 +02001084#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001085 SSL_get0_alpn_selected(impl->ssl, &alpn_selected, &alpn_selected_len);
Julien Boeufd1531322015-06-18 11:05:39 +02001086#endif /* TSI_OPENSSL_ALPN_SUPPORT */
Craig Tiller4782d922017-11-10 09:53:21 -08001087 if (alpn_selected == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001088 /* Try npn. */
1089 SSL_get0_next_proto_negotiated(impl->ssl, &alpn_selected,
1090 &alpn_selected_len);
1091 }
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001092
1093 // 1 is for session reused property.
1094 size_t new_property_count = peer->property_count + 1;
1095 if (alpn_selected != nullptr) new_property_count++;
1096 tsi_peer_property* new_properties = static_cast<tsi_peer_property*>(
1097 gpr_zalloc(sizeof(*new_properties) * new_property_count));
1098 for (size_t i = 0; i < peer->property_count; i++) {
1099 new_properties[i] = peer->properties[i];
1100 }
1101 if (peer->properties != nullptr) gpr_free(peer->properties);
1102 peer->properties = new_properties;
1103
Craig Tiller4782d922017-11-10 09:53:21 -08001104 if (alpn_selected != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001105 result = tsi_construct_string_peer_property(
Noah Eisen4d20a662018-02-09 09:34:04 -08001106 TSI_SSL_ALPN_SELECTED_PROTOCOL,
1107 reinterpret_cast<const char*>(alpn_selected), alpn_selected_len,
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001108 &peer->properties[peer->property_count]);
1109 if (result != TSI_OK) return result;
Craig Tillera82950e2015-09-22 12:33:20 -07001110 peer->property_count++;
Craig Tillera82950e2015-09-22 12:33:20 -07001111 }
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001112
1113 const char* session_reused = SSL_session_reused(impl->ssl) ? "true" : "false";
1114 result = tsi_construct_string_peer_property(
1115 TSI_SSL_SESSION_REUSED_PEER_PROPERTY, session_reused,
1116 strlen(session_reused) + 1, &peer->properties[peer->property_count]);
1117 if (result != TSI_OK) return result;
1118 peer->property_count++;
1119
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001120 return result;
1121}
1122
Craig Tillera82950e2015-09-22 12:33:20 -07001123static tsi_result ssl_handshaker_create_frame_protector(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001124 tsi_handshaker* self, size_t* max_output_protected_frame_size,
1125 tsi_frame_protector** protector) {
Craig Tillera82950e2015-09-22 12:33:20 -07001126 size_t actual_max_output_protected_frame_size =
1127 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
Noah Eisenbe82e642018-02-09 09:16:55 -08001128 tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
Craig Tillerbaa14a92017-11-03 09:09:36 -07001129 tsi_ssl_frame_protector* protector_impl =
Noah Eisen4d20a662018-02-09 09:34:04 -08001130 static_cast<tsi_ssl_frame_protector*>(
1131 gpr_zalloc(sizeof(*protector_impl)));
Craig Tiller45724b32015-09-22 10:42:19 -07001132
Craig Tiller4782d922017-11-10 09:53:21 -08001133 if (max_output_protected_frame_size != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001134 if (*max_output_protected_frame_size >
1135 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND) {
1136 *max_output_protected_frame_size =
1137 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_UPPER_BOUND;
1138 } else if (*max_output_protected_frame_size <
1139 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND) {
1140 *max_output_protected_frame_size =
1141 TSI_SSL_MAX_PROTECTED_FRAME_SIZE_LOWER_BOUND;
Craig Tiller45724b32015-09-22 10:42:19 -07001142 }
Craig Tillera82950e2015-09-22 12:33:20 -07001143 actual_max_output_protected_frame_size = *max_output_protected_frame_size;
1144 }
1145 protector_impl->buffer_size =
1146 actual_max_output_protected_frame_size - TSI_SSL_MAX_PROTECTION_OVERHEAD;
Yash Tibrewalacd46e52017-09-20 11:28:25 -07001147 protector_impl->buffer =
Noah Eisenbe82e642018-02-09 09:16:55 -08001148 static_cast<unsigned char*>(gpr_malloc(protector_impl->buffer_size));
Craig Tiller4782d922017-11-10 09:53:21 -08001149 if (protector_impl->buffer == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001150 gpr_log(GPR_ERROR,
1151 "Could not allocated buffer for tsi_ssl_frame_protector.");
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +01001152 gpr_free(protector_impl);
Craig Tillera82950e2015-09-22 12:33:20 -07001153 return TSI_INTERNAL_ERROR;
1154 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001155
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001156 /* Transfer ownership of ssl and network_io to the frame protector. It is OK
1157 * as the caller cannot call anything else but destroy on the handshaker
1158 * after this call. */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001159 protector_impl->ssl = impl->ssl;
Craig Tiller4782d922017-11-10 09:53:21 -08001160 impl->ssl = nullptr;
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001161 protector_impl->network_io = impl->network_io;
1162 impl->network_io = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001163
1164 protector_impl->base.vtable = &frame_protector_vtable;
1165 *protector = &protector_impl->base;
1166 return TSI_OK;
1167}
1168
Craig Tillerbaa14a92017-11-03 09:09:36 -07001169static void ssl_handshaker_destroy(tsi_handshaker* self) {
Noah Eisenbe82e642018-02-09 09:16:55 -08001170 tsi_ssl_handshaker* impl = reinterpret_cast<tsi_ssl_handshaker*>(self);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001171 SSL_free(impl->ssl);
1172 BIO_free(impl->network_io);
Justin Burke49841352017-08-31 17:42:54 -07001173 tsi_ssl_handshaker_factory_unref(impl->factory_ref);
Nicolas "Pixel" Noble7c9a1542016-03-26 01:33:34 +01001174 gpr_free(impl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001175}
1176
1177static const tsi_handshaker_vtable handshaker_vtable = {
Craig Tillera82950e2015-09-22 12:33:20 -07001178 ssl_handshaker_get_bytes_to_send_to_peer,
Craig Tillerf40df232016-03-25 13:38:14 -07001179 ssl_handshaker_process_bytes_from_peer,
1180 ssl_handshaker_get_result,
1181 ssl_handshaker_extract_peer,
1182 ssl_handshaker_create_frame_protector,
Craig Tillera82950e2015-09-22 12:33:20 -07001183 ssl_handshaker_destroy,
Craig Tiller4782d922017-11-10 09:53:21 -08001184 nullptr,
Craig Tillerd6c98df2015-08-18 09:33:44 -07001185};
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001186
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001187/* --- tsi_ssl_handshaker_factory common methods. --- */
1188
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001189static void tsi_ssl_handshaker_resume_session(
1190 SSL* ssl, tsi::SslSessionLRUCache* session_cache) {
1191 const char* server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
1192 if (server_name == nullptr) {
1193 return;
1194 }
1195 tsi::SslSessionPtr session = session_cache->Get(server_name);
1196 if (session != nullptr) {
1197 // SSL_set_session internally increments reference counter.
1198 SSL_set_session(ssl, session.get());
1199 }
1200}
1201
Craig Tillerbaa14a92017-11-03 09:09:36 -07001202static tsi_result create_tsi_ssl_handshaker(SSL_CTX* ctx, int is_client,
1203 const char* server_name_indication,
1204 tsi_ssl_handshaker_factory* factory,
1205 tsi_handshaker** handshaker) {
1206 SSL* ssl = SSL_new(ctx);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001207 BIO* network_io = nullptr;
1208 BIO* ssl_io = nullptr;
Craig Tiller4782d922017-11-10 09:53:21 -08001209 tsi_ssl_handshaker* impl = nullptr;
1210 *handshaker = nullptr;
1211 if (ctx == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001212 gpr_log(GPR_ERROR, "SSL Context is null. Should never happen.");
1213 return TSI_INTERNAL_ERROR;
1214 }
Craig Tiller4782d922017-11-10 09:53:21 -08001215 if (ssl == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001216 return TSI_OUT_OF_RESOURCES;
1217 }
1218 SSL_set_info_callback(ssl, ssl_info_callback);
1219
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001220 if (!BIO_new_bio_pair(&network_io, 0, &ssl_io, 0)) {
1221 gpr_log(GPR_ERROR, "BIO_new_bio_pair failed.");
Craig Tillera82950e2015-09-22 12:33:20 -07001222 SSL_free(ssl);
Craig Tillera82950e2015-09-22 12:33:20 -07001223 return TSI_OUT_OF_RESOURCES;
1224 }
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001225 SSL_set_bio(ssl, ssl_io, ssl_io);
Craig Tillera82950e2015-09-22 12:33:20 -07001226 if (is_client) {
1227 int ssl_result;
1228 SSL_set_connect_state(ssl);
Craig Tiller4782d922017-11-10 09:53:21 -08001229 if (server_name_indication != nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001230 if (!SSL_set_tlsext_host_name(ssl, server_name_indication)) {
1231 gpr_log(GPR_ERROR, "Invalid server name indication %s.",
1232 server_name_indication);
1233 SSL_free(ssl);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001234 BIO_free(network_io);
Craig Tillera82950e2015-09-22 12:33:20 -07001235 return TSI_INTERNAL_ERROR;
1236 }
1237 }
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001238 tsi_ssl_client_handshaker_factory* client_factory =
1239 reinterpret_cast<tsi_ssl_client_handshaker_factory*>(factory);
1240 if (client_factory->session_cache != nullptr) {
1241 tsi_ssl_handshaker_resume_session(ssl,
1242 client_factory->session_cache.get());
1243 }
Craig Tillera82950e2015-09-22 12:33:20 -07001244 ssl_result = SSL_do_handshake(ssl);
1245 ssl_result = SSL_get_error(ssl, ssl_result);
1246 if (ssl_result != SSL_ERROR_WANT_READ) {
1247 gpr_log(GPR_ERROR,
1248 "Unexpected error received from first SSL_do_handshake call: %s",
1249 ssl_error_string(ssl_result));
1250 SSL_free(ssl);
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001251 BIO_free(network_io);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001252 return TSI_INTERNAL_ERROR;
1253 }
Craig Tillera82950e2015-09-22 12:33:20 -07001254 } else {
1255 SSL_set_accept_state(ssl);
1256 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001257
Noah Eisenbe82e642018-02-09 09:16:55 -08001258 impl = static_cast<tsi_ssl_handshaker*>(gpr_zalloc(sizeof(*impl)));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001259 impl->ssl = ssl;
Ruslan Nigmatullin17226402018-01-17 18:45:53 -08001260 impl->network_io = network_io;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001261 impl->result = TSI_HANDSHAKE_IN_PROGRESS;
1262 impl->base.vtable = &handshaker_vtable;
Justin Burke49841352017-08-31 17:42:54 -07001263 impl->factory_ref = tsi_ssl_handshaker_factory_ref(factory);
1264
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001265 *handshaker = &impl->base;
1266 return TSI_OK;
1267}
1268
Craig Tillerbaa14a92017-11-03 09:09:36 -07001269static int select_protocol_list(const unsigned char** out,
1270 unsigned char* outlen,
1271 const unsigned char* client_list,
Craig Tillera82950e2015-09-22 12:33:20 -07001272 size_t client_list_len,
Craig Tillerbaa14a92017-11-03 09:09:36 -07001273 const unsigned char* server_list,
Craig Tillera82950e2015-09-22 12:33:20 -07001274 size_t server_list_len) {
Craig Tillerbaa14a92017-11-03 09:09:36 -07001275 const unsigned char* client_current = client_list;
Noah Eisen4d20a662018-02-09 09:34:04 -08001276 while (static_cast<unsigned int>(client_current - client_list) <
1277 client_list_len) {
Craig Tillera82950e2015-09-22 12:33:20 -07001278 unsigned char client_current_len = *(client_current++);
Craig Tillerbaa14a92017-11-03 09:09:36 -07001279 const unsigned char* server_current = server_list;
Craig Tillera82950e2015-09-22 12:33:20 -07001280 while ((server_current >= server_list) &&
Noah Eisen4d20a662018-02-09 09:34:04 -08001281 static_cast<uintptr_t>(server_current - server_list) <
1282 server_list_len) {
Craig Tillera82950e2015-09-22 12:33:20 -07001283 unsigned char server_current_len = *(server_current++);
1284 if ((client_current_len == server_current_len) &&
1285 !memcmp(client_current, server_current, server_current_len)) {
1286 *out = server_current;
1287 *outlen = server_current_len;
1288 return SSL_TLSEXT_ERR_OK;
1289 }
1290 server_current += server_current_len;
Julien Boeufd1531322015-06-18 11:05:39 +02001291 }
Craig Tillera82950e2015-09-22 12:33:20 -07001292 client_current += client_current_len;
1293 }
Julien Boeufd1531322015-06-18 11:05:39 +02001294 return SSL_TLSEXT_ERR_NOACK;
1295}
1296
Julien Boeuf935d02e2017-04-09 00:07:09 -07001297/* --- tsi_ssl_client_handshaker_factory methods implementation. --- */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001298
Julien Boeuf935d02e2017-04-09 00:07:09 -07001299tsi_result tsi_ssl_client_handshaker_factory_create_handshaker(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001300 tsi_ssl_client_handshaker_factory* self, const char* server_name_indication,
1301 tsi_handshaker** handshaker) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001302 return create_tsi_ssl_handshaker(self->ssl_context, 1, server_name_indication,
Justin Burke49841352017-08-31 17:42:54 -07001303 &self->base, handshaker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001304}
1305
Justin Burke49841352017-08-31 17:42:54 -07001306void tsi_ssl_client_handshaker_factory_unref(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001307 tsi_ssl_client_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -08001308 if (self == nullptr) return;
Justin Burke49841352017-08-31 17:42:54 -07001309 tsi_ssl_handshaker_factory_unref(&self->base);
1310}
1311
1312static void tsi_ssl_client_handshaker_factory_destroy(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001313 tsi_ssl_handshaker_factory* factory) {
Craig Tiller4782d922017-11-10 09:53:21 -08001314 if (factory == nullptr) return;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001315 tsi_ssl_client_handshaker_factory* self =
Noah Eisenbe82e642018-02-09 09:16:55 -08001316 reinterpret_cast<tsi_ssl_client_handshaker_factory*>(factory);
Craig Tiller4782d922017-11-10 09:53:21 -08001317 if (self->ssl_context != nullptr) SSL_CTX_free(self->ssl_context);
1318 if (self->alpn_protocol_list != nullptr) gpr_free(self->alpn_protocol_list);
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001319 self->session_cache.reset();
Julien Boeuf935d02e2017-04-09 00:07:09 -07001320 gpr_free(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001321}
1322
Craig Tillerbaa14a92017-11-03 09:09:36 -07001323static int client_handshaker_factory_npn_callback(SSL* ssl, unsigned char** out,
1324 unsigned char* outlen,
1325 const unsigned char* in,
Craig Tillera82950e2015-09-22 12:33:20 -07001326 unsigned int inlen,
Craig Tillerbaa14a92017-11-03 09:09:36 -07001327 void* arg) {
1328 tsi_ssl_client_handshaker_factory* factory =
Noah Eisenbe82e642018-02-09 09:16:55 -08001329 static_cast<tsi_ssl_client_handshaker_factory*>(arg);
Craig Tillerbaa14a92017-11-03 09:09:36 -07001330 return select_protocol_list((const unsigned char**)out, outlen,
Craig Tillera82950e2015-09-22 12:33:20 -07001331 factory->alpn_protocol_list,
1332 factory->alpn_protocol_list_length, in, inlen);
Julien Boeufd1531322015-06-18 11:05:39 +02001333}
1334
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001335/* --- tsi_ssl_server_handshaker_factory methods implementation. --- */
1336
Julien Boeuf935d02e2017-04-09 00:07:09 -07001337tsi_result tsi_ssl_server_handshaker_factory_create_handshaker(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001338 tsi_ssl_server_handshaker_factory* self, tsi_handshaker** handshaker) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001339 if (self->ssl_context_count == 0) return TSI_INVALID_ARGUMENT;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001340 /* Create the handshaker with the first context. We will switch if needed
1341 because of SNI in ssl_server_handshaker_factory_servername_callback. */
Craig Tillerbe98d242017-11-10 15:26:57 -08001342 return create_tsi_ssl_handshaker(self->ssl_contexts[0], 0, nullptr,
1343 &self->base, handshaker);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001344}
1345
Justin Burke49841352017-08-31 17:42:54 -07001346void tsi_ssl_server_handshaker_factory_unref(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001347 tsi_ssl_server_handshaker_factory* self) {
Craig Tiller4782d922017-11-10 09:53:21 -08001348 if (self == nullptr) return;
Justin Burke49841352017-08-31 17:42:54 -07001349 tsi_ssl_handshaker_factory_unref(&self->base);
1350}
1351
1352static void tsi_ssl_server_handshaker_factory_destroy(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001353 tsi_ssl_handshaker_factory* factory) {
Craig Tiller4782d922017-11-10 09:53:21 -08001354 if (factory == nullptr) return;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001355 tsi_ssl_server_handshaker_factory* self =
Noah Eisenbe82e642018-02-09 09:16:55 -08001356 reinterpret_cast<tsi_ssl_server_handshaker_factory*>(factory);
Julien Boeufb222b4d2015-01-15 17:01:39 -08001357 size_t i;
Julien Boeuf935d02e2017-04-09 00:07:09 -07001358 for (i = 0; i < self->ssl_context_count; i++) {
Craig Tiller4782d922017-11-10 09:53:21 -08001359 if (self->ssl_contexts[i] != nullptr) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001360 SSL_CTX_free(self->ssl_contexts[i]);
1361 tsi_peer_destruct(&self->ssl_context_x509_subject_names[i]);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001362 }
Craig Tillera82950e2015-09-22 12:33:20 -07001363 }
Craig Tiller4782d922017-11-10 09:53:21 -08001364 if (self->ssl_contexts != nullptr) gpr_free(self->ssl_contexts);
1365 if (self->ssl_context_x509_subject_names != nullptr) {
Julien Boeuf935d02e2017-04-09 00:07:09 -07001366 gpr_free(self->ssl_context_x509_subject_names);
Craig Tillera82950e2015-09-22 12:33:20 -07001367 }
Craig Tiller4782d922017-11-10 09:53:21 -08001368 if (self->alpn_protocol_list != nullptr) gpr_free(self->alpn_protocol_list);
Julien Boeuf935d02e2017-04-09 00:07:09 -07001369 gpr_free(self);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001370}
1371
Craig Tillerbaa14a92017-11-03 09:09:36 -07001372static int does_entry_match_name(const char* entry, size_t entry_length,
1373 const char* name) {
1374 const char* dot;
Craig Tiller4782d922017-11-10 09:53:21 -08001375 const char* name_subdomain = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -07001376 size_t name_length = strlen(name);
Julien Boeuf9fff77e2015-02-24 16:50:35 -08001377 size_t name_subdomain_length;
Craig Tillera82950e2015-09-22 12:33:20 -07001378 if (entry_length == 0) return 0;
Julien Boeuf9fff77e2015-02-24 16:50:35 -08001379
1380 /* Take care of '.' terminations. */
Craig Tillera82950e2015-09-22 12:33:20 -07001381 if (name[name_length - 1] == '.') {
1382 name_length--;
1383 }
1384 if (entry[entry_length - 1] == '.') {
1385 entry_length--;
1386 if (entry_length == 0) return 0;
1387 }
Julien Boeuf9fff77e2015-02-24 16:50:35 -08001388
Craig Tillera82950e2015-09-22 12:33:20 -07001389 if ((name_length == entry_length) &&
1390 strncmp(name, entry, entry_length) == 0) {
1391 return 1; /* Perfect match. */
1392 }
1393 if (entry[0] != '*') return 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001394
1395 /* Wildchar subdomain matching. */
Craig Tillera82950e2015-09-22 12:33:20 -07001396 if (entry_length < 3 || entry[1] != '.') { /* At least *.x */
1397 gpr_log(GPR_ERROR, "Invalid wildchar entry.");
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001398 return 0;
Craig Tillera82950e2015-09-22 12:33:20 -07001399 }
1400 name_subdomain = strchr(name, '.');
Craig Tiller4782d922017-11-10 09:53:21 -08001401 if (name_subdomain == nullptr) return 0;
Craig Tillera82950e2015-09-22 12:33:20 -07001402 name_subdomain_length = strlen(name_subdomain);
1403 if (name_subdomain_length < 2) return 0;
1404 name_subdomain++; /* Starts after the dot. */
Julien Boeuf0170a6c2015-02-24 18:08:01 -08001405 name_subdomain_length--;
Craig Tillera82950e2015-09-22 12:33:20 -07001406 entry += 2; /* Remove *. */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001407 entry_length -= 2;
Craig Tillera82950e2015-09-22 12:33:20 -07001408 dot = strchr(name_subdomain, '.');
Craig Tiller4782d922017-11-10 09:53:21 -08001409 if ((dot == nullptr) || (dot == &name_subdomain[name_subdomain_length - 1])) {
Craig Tillera82950e2015-09-22 12:33:20 -07001410 gpr_log(GPR_ERROR, "Invalid toplevel subdomain: %s", name_subdomain);
1411 return 0;
1412 }
1413 if (name_subdomain[name_subdomain_length - 1] == '.') {
1414 name_subdomain_length--;
1415 }
1416 return ((entry_length > 0) && (name_subdomain_length == entry_length) &&
1417 strncmp(entry, name_subdomain, entry_length) == 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001418}
1419
Craig Tillerbaa14a92017-11-03 09:09:36 -07001420static int ssl_server_handshaker_factory_servername_callback(SSL* ssl, int* ap,
1421 void* arg) {
1422 tsi_ssl_server_handshaker_factory* impl =
Noah Eisenbe82e642018-02-09 09:16:55 -08001423 static_cast<tsi_ssl_server_handshaker_factory*>(arg);
Julien Boeufb222b4d2015-01-15 17:01:39 -08001424 size_t i = 0;
Craig Tillerbaa14a92017-11-03 09:09:36 -07001425 const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
Craig Tiller4782d922017-11-10 09:53:21 -08001426 if (servername == nullptr || strlen(servername) == 0) {
Craig Tillera82950e2015-09-22 12:33:20 -07001427 return SSL_TLSEXT_ERR_NOACK;
1428 }
Craig Tiller45724b32015-09-22 10:42:19 -07001429
Craig Tillera82950e2015-09-22 12:33:20 -07001430 for (i = 0; i < impl->ssl_context_count; i++) {
1431 if (tsi_ssl_peer_matches_name(&impl->ssl_context_x509_subject_names[i],
1432 servername)) {
1433 SSL_set_SSL_CTX(ssl, impl->ssl_contexts[i]);
1434 return SSL_TLSEXT_ERR_OK;
Craig Tiller45724b32015-09-22 10:42:19 -07001435 }
Craig Tillera82950e2015-09-22 12:33:20 -07001436 }
1437 gpr_log(GPR_ERROR, "No match found for server name: %s.", servername);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001438 return SSL_TLSEXT_ERR_ALERT_WARNING;
1439}
1440
Julien Boeufd1531322015-06-18 11:05:39 +02001441#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001442static int server_handshaker_factory_alpn_callback(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001443 SSL* ssl, const unsigned char** out, unsigned char* outlen,
1444 const unsigned char* in, unsigned int inlen, void* arg) {
1445 tsi_ssl_server_handshaker_factory* factory =
Noah Eisenbe82e642018-02-09 09:16:55 -08001446 static_cast<tsi_ssl_server_handshaker_factory*>(arg);
Craig Tillera82950e2015-09-22 12:33:20 -07001447 return select_protocol_list(out, outlen, in, inlen,
1448 factory->alpn_protocol_list,
1449 factory->alpn_protocol_list_length);
Julien Boeufd1531322015-06-18 11:05:39 +02001450}
1451#endif /* TSI_OPENSSL_ALPN_SUPPORT */
1452
Craig Tillera82950e2015-09-22 12:33:20 -07001453static int server_handshaker_factory_npn_advertised_callback(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001454 SSL* ssl, const unsigned char** out, unsigned int* outlen, void* arg) {
1455 tsi_ssl_server_handshaker_factory* factory =
Noah Eisenbe82e642018-02-09 09:16:55 -08001456 static_cast<tsi_ssl_server_handshaker_factory*>(arg);
Julien Boeufd1531322015-06-18 11:05:39 +02001457 *out = factory->alpn_protocol_list;
Craig Tillera82950e2015-09-22 12:33:20 -07001458 GPR_ASSERT(factory->alpn_protocol_list_length <= UINT_MAX);
Noah Eisenbe82e642018-02-09 09:16:55 -08001459 *outlen = static_cast<unsigned int>(factory->alpn_protocol_list_length);
Julien Boeufd1531322015-06-18 11:05:39 +02001460 return SSL_TLSEXT_ERR_OK;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001461}
1462
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001463/// This callback is called when new \a session is established and ready to
1464/// be cached. This session can be reused for new connections to similar
1465/// servers at later point of time.
1466/// It's intended to be used with SSL_CTX_sess_set_new_cb function.
1467///
1468/// It returns 1 if callback takes ownership over \a session and 0 otherwise.
1469static int server_handshaker_factory_new_session_callback(
1470 SSL* ssl, SSL_SESSION* session) {
1471 SSL_CTX* ssl_context = SSL_get_SSL_CTX(ssl);
1472 if (ssl_context == nullptr) {
1473 return 0;
1474 }
1475 void* arg = SSL_CTX_get_ex_data(ssl_context, g_ssl_ctx_ex_factory_index);
1476 tsi_ssl_client_handshaker_factory* factory =
1477 static_cast<tsi_ssl_client_handshaker_factory*>(arg);
1478 const char* server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
1479 if (server_name == nullptr) {
1480 return 0;
1481 }
1482 factory->session_cache->Put(server_name, tsi::SslSessionPtr(session));
1483 // Return 1 to indicate transfered ownership over the given session.
1484 return 1;
1485}
1486
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001487/* --- tsi_ssl_handshaker_factory constructors. --- */
1488
Justin Burke49841352017-08-31 17:42:54 -07001489static tsi_ssl_handshaker_factory_vtable client_handshaker_factory_vtable = {
1490 tsi_ssl_client_handshaker_factory_destroy};
1491
Craig Tillera82950e2015-09-22 12:33:20 -07001492tsi_result tsi_create_ssl_client_handshaker_factory(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001493 const tsi_ssl_pem_key_cert_pair* pem_key_cert_pair,
1494 const char* pem_root_certs, const char* cipher_suites,
1495 const char** alpn_protocols, uint16_t num_alpn_protocols,
1496 tsi_ssl_client_handshaker_factory** factory) {
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001497 tsi_ssl_client_handshaker_options options;
1498 memset(&options, 0, sizeof(options));
1499 options.pem_key_cert_pair = pem_key_cert_pair;
1500 options.pem_root_certs = pem_root_certs;
1501 options.cipher_suites = cipher_suites;
1502 options.alpn_protocols = alpn_protocols;
1503 options.num_alpn_protocols = num_alpn_protocols;
1504 return tsi_create_ssl_client_handshaker_factory_with_options(&options,
1505 factory);
1506}
1507
1508tsi_result tsi_create_ssl_client_handshaker_factory_with_options(
1509 const tsi_ssl_client_handshaker_options* options,
1510 tsi_ssl_client_handshaker_factory** factory) {
Craig Tiller4782d922017-11-10 09:53:21 -08001511 SSL_CTX* ssl_context = nullptr;
1512 tsi_ssl_client_handshaker_factory* impl = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001513 tsi_result result = TSI_OK;
1514
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001515 gpr_once_init(&g_init_openssl_once, init_openssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001516
Craig Tiller4782d922017-11-10 09:53:21 -08001517 if (factory == nullptr) return TSI_INVALID_ARGUMENT;
1518 *factory = nullptr;
jiangtaoli2016144f5552018-03-23 11:28:48 -07001519 if (options->pem_root_certs == nullptr && options->root_store == nullptr) {
1520 return TSI_INVALID_ARGUMENT;
1521 }
Craig Tillera82950e2015-09-22 12:33:20 -07001522
1523 ssl_context = SSL_CTX_new(TLSv1_2_method());
Craig Tiller4782d922017-11-10 09:53:21 -08001524 if (ssl_context == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001525 gpr_log(GPR_ERROR, "Could not create ssl context.");
Craig Tiller45724b32015-09-22 10:42:19 -07001526 return TSI_INVALID_ARGUMENT;
Craig Tillera82950e2015-09-22 12:33:20 -07001527 }
Julien Boeufd1531322015-06-18 11:05:39 +02001528
Noah Eisen4d20a662018-02-09 09:34:04 -08001529 impl = static_cast<tsi_ssl_client_handshaker_factory*>(
1530 gpr_zalloc(sizeof(*impl)));
Justin Burke49841352017-08-31 17:42:54 -07001531 tsi_ssl_handshaker_factory_init(&impl->base);
1532 impl->base.vtable = &client_handshaker_factory_vtable;
Julien Boeufd1531322015-06-18 11:05:39 +02001533 impl->ssl_context = ssl_context;
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001534 if (options->session_cache != nullptr) {
1535 // Unref is called manually on factory destruction.
1536 impl->session_cache =
1537 reinterpret_cast<tsi::SslSessionLRUCache*>(options->session_cache)
1538 ->Ref();
1539 SSL_CTX_set_ex_data(ssl_context, g_ssl_ctx_ex_factory_index, impl);
1540 SSL_CTX_sess_set_new_cb(ssl_context,
1541 server_handshaker_factory_new_session_callback);
1542 SSL_CTX_set_session_cache_mode(ssl_context, SSL_SESS_CACHE_CLIENT);
1543 }
1544
Craig Tillera82950e2015-09-22 12:33:20 -07001545 do {
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001546 result = populate_ssl_context(ssl_context, options->pem_key_cert_pair,
1547 options->cipher_suites);
Craig Tillera82950e2015-09-22 12:33:20 -07001548 if (result != TSI_OK) break;
jiangtaoli2016144f5552018-03-23 11:28:48 -07001549
1550#if OPENSSL_VERSION_NUMBER >= 0x10100000
1551 // X509_STORE_up_ref is only available since OpenSSL 1.1.
1552 if (options->root_store != nullptr) {
1553 X509_STORE_up_ref(options->root_store->store);
1554 SSL_CTX_set_cert_store(ssl_context, options->root_store->store);
1555 }
1556#endif
1557 if (OPENSSL_VERSION_NUMBER < 0x10100000 || options->root_store == nullptr) {
1558 result = ssl_ctx_load_verification_certs(
1559 ssl_context, options->pem_root_certs, strlen(options->pem_root_certs),
1560 nullptr);
1561 if (result != TSI_OK) {
1562 gpr_log(GPR_ERROR, "Cannot load server root certificates.");
1563 break;
1564 }
Craig Tillera82950e2015-09-22 12:33:20 -07001565 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001566
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001567 if (options->num_alpn_protocols != 0) {
1568 result = build_alpn_protocol_name_list(
1569 options->alpn_protocols, options->num_alpn_protocols,
1570 &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
Craig Tillera82950e2015-09-22 12:33:20 -07001571 if (result != TSI_OK) {
1572 gpr_log(GPR_ERROR, "Building alpn list failed with error %s.",
1573 tsi_result_to_string(result));
1574 break;
1575 }
Julien Boeufd1531322015-06-18 11:05:39 +02001576#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001577 GPR_ASSERT(impl->alpn_protocol_list_length < UINT_MAX);
1578 if (SSL_CTX_set_alpn_protos(
1579 ssl_context, impl->alpn_protocol_list,
Noah Eisenbe82e642018-02-09 09:16:55 -08001580 static_cast<unsigned int>(impl->alpn_protocol_list_length))) {
Craig Tillera82950e2015-09-22 12:33:20 -07001581 gpr_log(GPR_ERROR, "Could not set alpn protocol list to context.");
1582 result = TSI_INVALID_ARGUMENT;
1583 break;
1584 }
Julien Boeufd1531322015-06-18 11:05:39 +02001585#endif /* TSI_OPENSSL_ALPN_SUPPORT */
Craig Tillera82950e2015-09-22 12:33:20 -07001586 SSL_CTX_set_next_proto_select_cb(
1587 ssl_context, client_handshaker_factory_npn_callback, impl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001588 }
Craig Tillera82950e2015-09-22 12:33:20 -07001589 } while (0);
1590 if (result != TSI_OK) {
Justin Burke49841352017-08-31 17:42:54 -07001591 tsi_ssl_handshaker_factory_unref(&impl->base);
Craig Tillera82950e2015-09-22 12:33:20 -07001592 return result;
1593 }
Craig Tiller4782d922017-11-10 09:53:21 -08001594 SSL_CTX_set_verify(ssl_context, SSL_VERIFY_PEER, nullptr);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001595 /* TODO(jboeuf): Add revocation verification. */
1596
Julien Boeuf935d02e2017-04-09 00:07:09 -07001597 *factory = impl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001598 return TSI_OK;
1599}
1600
Justin Burke49841352017-08-31 17:42:54 -07001601static tsi_ssl_handshaker_factory_vtable server_handshaker_factory_vtable = {
1602 tsi_ssl_server_handshaker_factory_destroy};
1603
Craig Tillera82950e2015-09-22 12:33:20 -07001604tsi_result tsi_create_ssl_server_handshaker_factory(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001605 const tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs,
1606 size_t num_key_cert_pairs, const char* pem_client_root_certs,
1607 int force_client_auth, const char* cipher_suites,
1608 const char** alpn_protocols, uint16_t num_alpn_protocols,
1609 tsi_ssl_server_handshaker_factory** factory) {
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001610 return tsi_create_ssl_server_handshaker_factory_ex(
Julien Boeufb71ef652017-04-12 21:44:49 -07001611 pem_key_cert_pairs, num_key_cert_pairs, pem_client_root_certs,
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001612 force_client_auth ? TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY
1613 : TSI_DONT_REQUEST_CLIENT_CERTIFICATE,
Julien Boeufb71ef652017-04-12 21:44:49 -07001614 cipher_suites, alpn_protocols, num_alpn_protocols, factory);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001615}
1616
1617tsi_result tsi_create_ssl_server_handshaker_factory_ex(
Craig Tillerbaa14a92017-11-03 09:09:36 -07001618 const tsi_ssl_pem_key_cert_pair* pem_key_cert_pairs,
1619 size_t num_key_cert_pairs, const char* pem_client_root_certs,
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001620 tsi_client_certificate_request_type client_certificate_request,
Craig Tillerbaa14a92017-11-03 09:09:36 -07001621 const char* cipher_suites, const char** alpn_protocols,
1622 uint16_t num_alpn_protocols, tsi_ssl_server_handshaker_factory** factory) {
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001623 tsi_ssl_server_handshaker_options options;
1624 memset(&options, 0, sizeof(options));
1625 options.pem_key_cert_pairs = pem_key_cert_pairs;
1626 options.num_key_cert_pairs = num_key_cert_pairs;
1627 options.pem_client_root_certs = pem_client_root_certs;
1628 options.client_certificate_request = client_certificate_request;
1629 options.cipher_suites = cipher_suites;
1630 options.alpn_protocols = alpn_protocols;
1631 options.num_alpn_protocols = num_alpn_protocols;
1632 return tsi_create_ssl_server_handshaker_factory_with_options(&options,
1633 factory);
1634}
1635
1636tsi_result tsi_create_ssl_server_handshaker_factory_with_options(
1637 const tsi_ssl_server_handshaker_options* options,
1638 tsi_ssl_server_handshaker_factory** factory) {
Craig Tiller4782d922017-11-10 09:53:21 -08001639 tsi_ssl_server_handshaker_factory* impl = nullptr;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001640 tsi_result result = TSI_OK;
Julien Boeufb222b4d2015-01-15 17:01:39 -08001641 size_t i = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001642
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001643 gpr_once_init(&g_init_openssl_once, init_openssl);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001644
Craig Tiller4782d922017-11-10 09:53:21 -08001645 if (factory == nullptr) return TSI_INVALID_ARGUMENT;
1646 *factory = nullptr;
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001647 if (options->num_key_cert_pairs == 0 ||
1648 options->pem_key_cert_pairs == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001649 return TSI_INVALID_ARGUMENT;
1650 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001651
Noah Eisen4d20a662018-02-09 09:34:04 -08001652 impl = static_cast<tsi_ssl_server_handshaker_factory*>(
1653 gpr_zalloc(sizeof(*impl)));
Justin Burke49841352017-08-31 17:42:54 -07001654 tsi_ssl_handshaker_factory_init(&impl->base);
1655 impl->base.vtable = &server_handshaker_factory_vtable;
1656
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001657 impl->ssl_contexts = static_cast<SSL_CTX**>(
1658 gpr_zalloc(options->num_key_cert_pairs * sizeof(SSL_CTX*)));
1659 impl->ssl_context_x509_subject_names = static_cast<tsi_peer*>(
1660 gpr_zalloc(options->num_key_cert_pairs * sizeof(tsi_peer)));
Craig Tiller4782d922017-11-10 09:53:21 -08001661 if (impl->ssl_contexts == nullptr ||
1662 impl->ssl_context_x509_subject_names == nullptr) {
Justin Burke49841352017-08-31 17:42:54 -07001663 tsi_ssl_handshaker_factory_unref(&impl->base);
Craig Tillera82950e2015-09-22 12:33:20 -07001664 return TSI_OUT_OF_RESOURCES;
1665 }
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001666 impl->ssl_context_count = options->num_key_cert_pairs;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001667
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001668 if (options->num_alpn_protocols > 0) {
1669 result = build_alpn_protocol_name_list(
1670 options->alpn_protocols, options->num_alpn_protocols,
1671 &impl->alpn_protocol_list, &impl->alpn_protocol_list_length);
Craig Tillera82950e2015-09-22 12:33:20 -07001672 if (result != TSI_OK) {
Justin Burke49841352017-08-31 17:42:54 -07001673 tsi_ssl_handshaker_factory_unref(&impl->base);
Craig Tillera82950e2015-09-22 12:33:20 -07001674 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001675 }
Craig Tillera82950e2015-09-22 12:33:20 -07001676 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001677
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001678 for (i = 0; i < options->num_key_cert_pairs; i++) {
Craig Tillera82950e2015-09-22 12:33:20 -07001679 do {
1680 impl->ssl_contexts[i] = SSL_CTX_new(TLSv1_2_method());
Craig Tiller4782d922017-11-10 09:53:21 -08001681 if (impl->ssl_contexts[i] == nullptr) {
Craig Tillera82950e2015-09-22 12:33:20 -07001682 gpr_log(GPR_ERROR, "Could not create ssl context.");
1683 result = TSI_OUT_OF_RESOURCES;
1684 break;
1685 }
Julien Boeufb71ef652017-04-12 21:44:49 -07001686 result = populate_ssl_context(impl->ssl_contexts[i],
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001687 &options->pem_key_cert_pairs[i],
1688 options->cipher_suites);
Craig Tillera82950e2015-09-22 12:33:20 -07001689 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001690
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001691 // TODO(elessar): Provide ability to disable session ticket keys.
1692
1693 // Allow client cache sessions (it's needed for OpenSSL only).
1694 int set_sid_ctx_result = SSL_CTX_set_session_id_context(
1695 impl->ssl_contexts[i], kSslSessionIdContext,
1696 GPR_ARRAY_SIZE(kSslSessionIdContext));
1697 if (set_sid_ctx_result == 0) {
1698 gpr_log(GPR_ERROR, "Failed to set session id context.");
1699 result = TSI_INTERNAL_ERROR;
1700 break;
1701 }
1702
1703 if (options->session_ticket_key != nullptr) {
1704 if (SSL_CTX_set_tlsext_ticket_keys(
1705 impl->ssl_contexts[i],
1706 const_cast<char*>(options->session_ticket_key),
1707 options->session_ticket_key_size) == 0) {
1708 gpr_log(GPR_ERROR, "Invalid STEK size.");
1709 result = TSI_INVALID_ARGUMENT;
1710 break;
1711 }
1712 }
1713
1714 if (options->pem_client_root_certs != nullptr) {
Craig Tiller4782d922017-11-10 09:53:21 -08001715 STACK_OF(X509_NAME)* root_names = nullptr;
Craig Tillera82950e2015-09-22 12:33:20 -07001716 result = ssl_ctx_load_verification_certs(
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001717 impl->ssl_contexts[i], options->pem_client_root_certs,
1718 strlen(options->pem_client_root_certs), &root_names);
Craig Tillera82950e2015-09-22 12:33:20 -07001719 if (result != TSI_OK) {
1720 gpr_log(GPR_ERROR, "Invalid verification certs.");
1721 break;
1722 }
1723 SSL_CTX_set_client_CA_list(impl->ssl_contexts[i], root_names);
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001724 switch (options->client_certificate_request) {
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001725 case TSI_DONT_REQUEST_CLIENT_CERTIFICATE:
Craig Tiller4782d922017-11-10 09:53:21 -08001726 SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_NONE, nullptr);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001727 break;
1728 case TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
1729 SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER,
1730 NullVerifyCallback);
1731 break;
1732 case TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY:
Craig Tiller4782d922017-11-10 09:53:21 -08001733 SSL_CTX_set_verify(impl->ssl_contexts[i], SSL_VERIFY_PEER, nullptr);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001734 break;
1735 case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY:
1736 SSL_CTX_set_verify(
1737 impl->ssl_contexts[i],
1738 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
1739 NullVerifyCallback);
1740 break;
1741 case TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY:
1742 SSL_CTX_set_verify(
1743 impl->ssl_contexts[i],
Craig Tiller4782d922017-11-10 09:53:21 -08001744 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
Deepak Lukosedba4c5f2016-03-25 12:54:25 -07001745 break;
1746 }
Craig Tillera82950e2015-09-22 12:33:20 -07001747 /* TODO(jboeuf): Add revocation verification. */
1748 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001749
Craig Tillera82950e2015-09-22 12:33:20 -07001750 result = extract_x509_subject_names_from_pem_cert(
Ruslan Nigmatullin7ae37332018-02-21 16:44:35 -08001751 options->pem_key_cert_pairs[i].cert_chain,
Craig Tillera82950e2015-09-22 12:33:20 -07001752 &impl->ssl_context_x509_subject_names[i]);
1753 if (result != TSI_OK) break;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001754
Craig Tillera82950e2015-09-22 12:33:20 -07001755 SSL_CTX_set_tlsext_servername_callback(
1756 impl->ssl_contexts[i],
1757 ssl_server_handshaker_factory_servername_callback);
1758 SSL_CTX_set_tlsext_servername_arg(impl->ssl_contexts[i], impl);
Julien Boeufd1531322015-06-18 11:05:39 +02001759#if TSI_OPENSSL_ALPN_SUPPORT
Craig Tillera82950e2015-09-22 12:33:20 -07001760 SSL_CTX_set_alpn_select_cb(impl->ssl_contexts[i],
1761 server_handshaker_factory_alpn_callback, impl);
Julien Boeufd1531322015-06-18 11:05:39 +02001762#endif /* TSI_OPENSSL_ALPN_SUPPORT */
Craig Tillera82950e2015-09-22 12:33:20 -07001763 SSL_CTX_set_next_protos_advertised_cb(
1764 impl->ssl_contexts[i],
1765 server_handshaker_factory_npn_advertised_callback, impl);
1766 } while (0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001767
Craig Tillera82950e2015-09-22 12:33:20 -07001768 if (result != TSI_OK) {
Justin Burke49841352017-08-31 17:42:54 -07001769 tsi_ssl_handshaker_factory_unref(&impl->base);
Craig Tillera82950e2015-09-22 12:33:20 -07001770 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001771 }
Craig Tillera82950e2015-09-22 12:33:20 -07001772 }
Justin Burke49841352017-08-31 17:42:54 -07001773
Julien Boeuf935d02e2017-04-09 00:07:09 -07001774 *factory = impl;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001775 return TSI_OK;
1776}
1777
1778/* --- tsi_ssl utils. --- */
1779
Craig Tillerbaa14a92017-11-03 09:09:36 -07001780int tsi_ssl_peer_matches_name(const tsi_peer* peer, const char* name) {
Julien Boeufb222b4d2015-01-15 17:01:39 -08001781 size_t i = 0;
Julien Boeuf597a4f22015-02-23 15:57:14 -08001782 size_t san_count = 0;
Craig Tiller4782d922017-11-10 09:53:21 -08001783 const tsi_peer_property* cn_property = nullptr;
Paul Querna47d841d2016-03-10 11:19:17 -08001784 int like_ip = looks_like_ip_address(name);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001785
Julien Boeuf597a4f22015-02-23 15:57:14 -08001786 /* Check the SAN first. */
Craig Tillera82950e2015-09-22 12:33:20 -07001787 for (i = 0; i < peer->property_count; i++) {
Craig Tillerbaa14a92017-11-03 09:09:36 -07001788 const tsi_peer_property* property = &peer->properties[i];
Craig Tiller4782d922017-11-10 09:53:21 -08001789 if (property->name == nullptr) continue;
Craig Tillera82950e2015-09-22 12:33:20 -07001790 if (strcmp(property->name,
1791 TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == 0) {
1792 san_count++;
Paul Querna47d841d2016-03-10 11:19:17 -08001793
1794 if (!like_ip && does_entry_match_name(property->value.data,
1795 property->value.length, name)) {
1796 return 1;
1797 } else if (like_ip &&
1798 strncmp(name, property->value.data, property->value.length) ==
1799 0 &&
1800 strlen(name) == property->value.length) {
1801 /* IP Addresses are exact matches only. */
Craig Tillera82950e2015-09-22 12:33:20 -07001802 return 1;
1803 }
1804 } else if (strcmp(property->name,
1805 TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY) == 0) {
1806 cn_property = property;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001807 }
Craig Tillera82950e2015-09-22 12:33:20 -07001808 }
Julien Boeuf597a4f22015-02-23 15:57:14 -08001809
Paul Querna47d841d2016-03-10 11:19:17 -08001810 /* If there's no SAN, try the CN, but only if its not like an IP Address */
Craig Tiller4782d922017-11-10 09:53:21 -08001811 if (san_count == 0 && cn_property != nullptr && !like_ip) {
Craig Tillera82950e2015-09-22 12:33:20 -07001812 if (does_entry_match_name(cn_property->value.data,
1813 cn_property->value.length, name)) {
1814 return 1;
Julien Boeuf597a4f22015-02-23 15:57:14 -08001815 }
Craig Tillera82950e2015-09-22 12:33:20 -07001816 }
Julien Boeuf597a4f22015-02-23 15:57:14 -08001817
Craig Tillera82950e2015-09-22 12:33:20 -07001818 return 0; /* Not found. */
Craig Tiller190d3602015-02-18 09:23:38 -08001819}
Justin Burke49841352017-08-31 17:42:54 -07001820
1821/* --- Testing support. --- */
Craig Tillerbaa14a92017-11-03 09:09:36 -07001822const tsi_ssl_handshaker_factory_vtable* tsi_ssl_handshaker_factory_swap_vtable(
1823 tsi_ssl_handshaker_factory* factory,
1824 tsi_ssl_handshaker_factory_vtable* new_vtable) {
Craig Tiller4782d922017-11-10 09:53:21 -08001825 GPR_ASSERT(factory != nullptr);
1826 GPR_ASSERT(factory->vtable != nullptr);
Justin Burke49841352017-08-31 17:42:54 -07001827
Craig Tillerbaa14a92017-11-03 09:09:36 -07001828 const tsi_ssl_handshaker_factory_vtable* orig_vtable = factory->vtable;
Justin Burke49841352017-08-31 17:42:54 -07001829 factory->vtable = new_vtable;
1830 return orig_vtable;
1831}