• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 #include <string.h>
25 
26 #include "private-lib-core.h"
27 #include "private-lib-tls-openssl.h"
28 
29 /*
30  * Care: many openssl apis return 1 for success.  These are translated to the
31  * lws convention of 0 for success.
32  */
33 
34 int lws_openssl_describe_cipher(struct lws *wsi);
35 
36 extern int openssl_websocket_private_data_index,
37     openssl_SSL_CTX_private_data_index;
38 
39 #if !defined(USE_WOLFSSL)
40 
41 static int
OpenSSL_client_verify_callback(int preverify_ok,X509_STORE_CTX * x509_ctx)42 OpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
43 {
44 	SSL *ssl;
45 	int n;
46 	struct lws *wsi;
47 
48 	/* keep old behaviour accepting self-signed server certs */
49 	if (!preverify_ok) {
50 		int err = X509_STORE_CTX_get_error(x509_ctx);
51 
52 		if (err != X509_V_OK) {
53 			ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
54 					SSL_get_ex_data_X509_STORE_CTX_idx());
55 			wsi = SSL_get_ex_data(ssl,
56 					openssl_websocket_private_data_index);
57 			if (!wsi) {
58 				lwsl_err("%s: can't get wsi from ssl privdata\n",
59 					 __func__);
60 
61 				return 0;
62 			}
63 
64 			if ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
65 			     err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
66 			     wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED) {
67 				lwsl_notice("accepting self-signed "
68 					    "certificate (verify_callback)\n");
69 				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
70 				return 1;	// ok
71 		} else if ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ||
72 			    err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) &&
73 			    wsi->tls.use_ssl & LCCSCF_ALLOW_INSECURE) {
74 				lwsl_notice("accepting non-trusted certificate\n");
75 				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
76 				return 1;  /* ok */
77 			} else if ((err == X509_V_ERR_CERT_NOT_YET_VALID ||
78 				    err == X509_V_ERR_CERT_HAS_EXPIRED) &&
79 				    wsi->tls.use_ssl & LCCSCF_ALLOW_EXPIRED) {
80 				if (err == X509_V_ERR_CERT_NOT_YET_VALID)
81 					lwsl_notice("accepting not yet valid "
82 						    "certificate (verify_"
83 						    "callback)\n");
84 				else if (err == X509_V_ERR_CERT_HAS_EXPIRED)
85 					lwsl_notice("accepting expired "
86 						    "certificate (verify_"
87 						    "callback)\n");
88 				X509_STORE_CTX_set_error(x509_ctx, X509_V_OK);
89 				return 1;	// ok
90 			}
91 		}
92 	}
93 
94 	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
95 					 SSL_get_ex_data_X509_STORE_CTX_idx());
96 	wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index);
97 	if (!wsi) {
98 		lwsl_err("%s: can't get wsi from ssl privdata\n",  __func__);
99 
100 		return 0;
101 	}
102 
103 	n = lws_get_context_protocol(wsi->context, 0).callback(wsi,
104 			LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION,
105 			x509_ctx, ssl, preverify_ok);
106 
107 	/* keep old behaviour if something wrong with server certs */
108 	/* if ssl error is overruled in callback and cert is ok,
109 	 * X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); must be set and
110 	 * return value is 0 from callback */
111 	if (!preverify_ok) {
112 		int err = X509_STORE_CTX_get_error(x509_ctx);
113 
114 		if (err != X509_V_OK) {
115 			/* cert validation error was not handled in callback */
116 			int depth = X509_STORE_CTX_get_error_depth(x509_ctx);
117 			const char *msg = X509_verify_cert_error_string(err);
118 
119 			lwsl_err("SSL error: %s (preverify_ok=%d;err=%d;"
120 				 "depth=%d)\n", msg, preverify_ok, err, depth);
121 
122 			return preverify_ok;	// not ok
123 		}
124 	}
125 	/*
126 	 * convert callback return code from 0 = OK to verify callback
127 	 * return value 1 = OK
128 	 */
129 	return !n;
130 }
131 #endif
132 
133 
134 int
lws_ssl_client_bio_create(struct lws * wsi)135 lws_ssl_client_bio_create(struct lws *wsi)
136 {
137 	char hostname[128], *p;
138 #if defined(LWS_HAVE_SSL_set_alpn_protos) && \
139     defined(LWS_HAVE_SSL_get0_alpn_selected)
140 	uint8_t openssl_alpn[40];
141 	const char *alpn_comma = wsi->context->tls.alpn_default;
142 	int n;
143 #endif
144 
145 	if (wsi->stash) {
146 		lws_strncpy(hostname, wsi->stash->cis[CIS_HOST], sizeof(hostname));
147 #if defined(LWS_HAVE_SSL_set_alpn_protos) && \
148     defined(LWS_HAVE_SSL_get0_alpn_selected)
149 		alpn_comma = wsi->stash->cis[CIS_ALPN];
150 #endif
151 	} else {
152 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
153 		if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
154 				 _WSI_TOKEN_CLIENT_HOST) <= 0)
155 #endif
156 		{
157 			lwsl_err("%s: Unable to get hostname\n", __func__);
158 
159 			return -1;
160 		}
161 	}
162 
163 	/*
164 	 * remove any :port part on the hostname... necessary for network
165 	 * connection but typical certificates do not contain it
166 	 */
167 	p = hostname;
168 	while (*p) {
169 		if (*p == ':') {
170 			*p = '\0';
171 			break;
172 		}
173 		p++;
174 	}
175 
176 	wsi->tls.ssl = SSL_new(wsi->vhost->tls.ssl_client_ctx);
177 	if (!wsi->tls.ssl) {
178 		lwsl_err("SSL_new failed: %s\n",
179 		         ERR_error_string(lws_ssl_get_error(wsi, 0), NULL));
180 		lws_tls_err_describe_clear();
181 		return -1;
182 	}
183 
184 #if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK)
185 	if (wsi->vhost->tls.ssl_info_event_mask)
186 		SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback);
187 #endif
188 
189 #if defined LWS_HAVE_X509_VERIFY_PARAM_set1_host
190 	if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
191 		X509_VERIFY_PARAM *param = SSL_get0_param(wsi->tls.ssl);
192 
193 #if !defined(USE_WOLFSSL)
194 		/* Enable automatic hostname checks */
195 		X509_VERIFY_PARAM_set_hostflags(param,
196 					X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
197 #endif
198 		// Handle the case where the hostname is an IP address.
199 		if (!X509_VERIFY_PARAM_set1_ip_asc(param, hostname)) {
200 #if defined (LWS_WITH_BORINGSSL)
201 			// boringssl does not allow null-terminated string,
202 			// so hostname_len should not be 0
203 			// but exactly the same as len(hostname) excluding null
204 			const int hostname_len = strnlen(hostname, sizeof(hostname));
205 #else
206 			// openssl allows null-terminated string for hostname
207 			// in that case, hostname_len being 0 indicates hostname
208 			// is a null-terminated string
209 			const int hostname_len = 0;
210 #endif
211 			X509_VERIFY_PARAM_set1_host(param, hostname, hostname_len);
212 		}
213 	}
214 #else
215 	if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) {
216 		lwsl_err("%s: your tls lib is too old to have "
217 			 "X509_VERIFY_PARAM_set1_host, failing all client tls\n",
218 			 __func__);
219 		return -1;
220 	}
221 #endif
222 
223 #if !defined(USE_WOLFSSL)
224 #ifndef USE_OLD_CYASSL
225 	/* OpenSSL_client_verify_callback will be called @ SSL_connect() */
226 	SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER,
227 		       OpenSSL_client_verify_callback);
228 #endif
229 #endif
230 
231 #if !defined(USE_WOLFSSL)
232 	SSL_set_mode(wsi->tls.ssl,  SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
233 #endif
234 	/*
235 	 * use server name indication (SNI), if supported,
236 	 * when establishing connection
237 	 */
238 #ifdef USE_WOLFSSL
239 #ifdef USE_OLD_CYASSL
240 #ifdef CYASSL_SNI_HOST_NAME
241 	CyaSSL_UseSNI(wsi->tls.ssl, CYASSL_SNI_HOST_NAME, hostname,
242 		      strlen(hostname));
243 #endif
244 #else
245 #ifdef WOLFSSL_SNI_HOST_NAME
246 	wolfSSL_UseSNI(wsi->tls.ssl, WOLFSSL_SNI_HOST_NAME, hostname,
247 		       strlen(hostname));
248 #endif
249 #endif
250 #else
251 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
252 	SSL_set_tlsext_host_name(wsi->tls.ssl, hostname);
253 #endif
254 #endif
255 
256 #ifdef USE_WOLFSSL
257 	/*
258 	 * wolfSSL/CyaSSL does certificate verification differently
259 	 * from OpenSSL.
260 	 * If we should ignore the certificate, we need to set
261 	 * this before SSL_new and SSL_connect is called.
262 	 * Otherwise the connect will simply fail with error code -155
263 	 */
264 #ifdef USE_OLD_CYASSL
265 	if (wsi->tls.use_ssl == 2)
266 		CyaSSL_set_verify(wsi->tls.ssl, SSL_VERIFY_NONE, NULL);
267 #else
268 	if (wsi->tls.use_ssl == 2)
269 		wolfSSL_set_verify(wsi->tls.ssl, SSL_VERIFY_NONE, NULL);
270 #endif
271 #endif /* USE_WOLFSSL */
272 
273 	wsi->tls.client_bio = BIO_new_socket((int)(long long)wsi->desc.sockfd,
274 					     BIO_NOCLOSE);
275 	SSL_set_bio(wsi->tls.ssl, wsi->tls.client_bio, wsi->tls.client_bio);
276 
277 #ifdef USE_WOLFSSL
278 #ifdef USE_OLD_CYASSL
279 	CyaSSL_set_using_nonblock(wsi->tls.ssl, 1);
280 #else
281 	wolfSSL_set_using_nonblock(wsi->tls.ssl, 1);
282 #endif
283 #else
284 	BIO_set_nbio(wsi->tls.client_bio, 1); /* nonblocking */
285 #endif
286 
287 #if defined(LWS_HAVE_SSL_set_alpn_protos) && \
288     defined(LWS_HAVE_SSL_get0_alpn_selected)
289 	if (wsi->vhost->tls.alpn)
290 		alpn_comma = wsi->vhost->tls.alpn;
291 	if (wsi->stash)
292 		alpn_comma = wsi->stash->cis[CIS_ALPN];
293 #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
294 	if (lws_hdr_copy(wsi, hostname, sizeof(hostname),
295 			 _WSI_TOKEN_CLIENT_ALPN) > 0)
296 		alpn_comma = hostname;
297 #endif
298 
299 	lwsl_info("%s client conn using alpn list '%s'\n", wsi->role_ops->name, alpn_comma);
300 
301 	n = lws_alpn_comma_to_openssl(alpn_comma, openssl_alpn,
302 				      sizeof(openssl_alpn) - 1);
303 
304 	SSL_set_alpn_protos(wsi->tls.ssl, openssl_alpn, n);
305 #endif
306 
307 	SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index,
308 			wsi);
309 
310 	if (wsi->sys_tls_client_cert) {
311 		lws_system_blob_t *b = lws_system_get_blob(wsi->context,
312 					LWS_SYSBLOB_TYPE_CLIENT_CERT_DER,
313 					wsi->sys_tls_client_cert - 1);
314 		const uint8_t *data;
315 		size_t size;
316 
317 		if (!b)
318 			goto no_client_cert;
319 
320 		/*
321 		 * Set up the per-connection client cert
322 		 */
323 
324 		size = lws_system_blob_get_size(b);
325 		if (!size)
326 			goto no_client_cert;
327 
328 		if (lws_system_blob_get_single_ptr(b, &data))
329 			goto no_client_cert;
330 
331 		if (SSL_use_certificate_ASN1(wsi->tls.ssl,
332 #if defined(USE_WOLFSSL)
333 			(unsigned char *)
334 #endif
335 					data, (int)size) != 1) {
336 			lwsl_err("%s: use_certificate failed\n", __func__);
337 			lws_tls_err_describe_clear();
338 			goto no_client_cert;
339 		}
340 
341 		b = lws_system_get_blob(wsi->context,
342 					LWS_SYSBLOB_TYPE_CLIENT_KEY_DER,
343 					wsi->sys_tls_client_cert - 1);
344 		if (!b)
345 			goto no_client_cert;
346 
347 		size = lws_system_blob_get_size(b);
348 		if (!size)
349 			goto no_client_cert;
350 
351 		if (lws_system_blob_get_single_ptr(b, &data))
352 			goto no_client_cert;
353 
354 		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, wsi->tls.ssl,
355 #if defined(USE_WOLFSSL)
356 			(unsigned char *)
357 #endif
358 
359 					    data, (int)size) != 1 &&
360 		    SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, wsi->tls.ssl,
361 #if defined(USE_WOLFSSL)
362 			(unsigned char *)
363 #endif
364 					    data, (int)size) != 1) {
365 			lwsl_err("%s: use_privkey failed\n", __func__);
366 			lws_tls_err_describe_clear();
367 			goto no_client_cert;
368 		}
369 
370 		if (SSL_check_private_key(wsi->tls.ssl) != 1) {
371 			lwsl_err("Private SSL key doesn't match cert\n");
372 			lws_tls_err_describe_clear();
373 			return 1;
374 		}
375 
376 		lwsl_notice("%s: set system client cert %u\n", __func__,
377 				wsi->sys_tls_client_cert - 1);
378 	}
379 
380 	return 0;
381 
382 no_client_cert:
383 	lwsl_err("%s: unable to set up system client cert %d\n", __func__,
384 			wsi->sys_tls_client_cert - 1);
385 
386 	return 1;
387 }
388 
389 enum lws_ssl_capable_status
lws_tls_client_connect(struct lws * wsi)390 lws_tls_client_connect(struct lws *wsi)
391 {
392 #if defined(LWS_HAVE_SSL_set_alpn_protos) && \
393     defined(LWS_HAVE_SSL_get0_alpn_selected)
394 	const unsigned char *prot;
395 	char a[32];
396 	unsigned int len;
397 #endif
398 	int m, n;
399 #if defined(WIN32) || defined(_DEBUG)
400 	int en;
401 #endif
402 
403 	errno = 0;
404 	ERR_clear_error();
405 	n = SSL_connect(wsi->tls.ssl);
406 #if defined(WIN32) || defined(_DEBUG)
407 	en = errno;
408 #endif
409 	m = lws_ssl_get_error(wsi, n);
410 
411 	if (m == SSL_ERROR_SYSCALL
412 #if defined(WIN32)
413 			&& en
414 #endif
415 	) {
416 #if defined(WIN32) || defined(_DEBUG)
417 		lwsl_info("%s: n %d, m %d, errno %d\n", __func__, n, m, en);
418 #endif
419 		return LWS_SSL_CAPABLE_ERROR;
420 	}
421 
422 	if (m == SSL_ERROR_SSL)
423 		return LWS_SSL_CAPABLE_ERROR;
424 
425 	if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl))
426 		return LWS_SSL_CAPABLE_MORE_SERVICE_READ;
427 
428 	if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl))
429 		return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE;
430 
431 	if (n == 1 || m == SSL_ERROR_SYSCALL) {
432 #if defined(LWS_HAVE_SSL_set_alpn_protos) && \
433     defined(LWS_HAVE_SSL_get0_alpn_selected)
434 		SSL_get0_alpn_selected(wsi->tls.ssl, &prot, &len);
435 
436 		if (len >= sizeof(a))
437 			len = sizeof(a) - 1;
438 		memcpy(a, (const char *)prot, len);
439 		a[len] = '\0';
440 
441 		lws_role_call_alpn_negotiated(wsi, (const char *)a);
442 #endif
443 		lwsl_info("client connect OK\n");
444 		lws_openssl_describe_cipher(wsi);
445 		return LWS_SSL_CAPABLE_DONE;
446 	}
447 
448 	if (!n) /* we don't know what he wants, but he says to retry */
449 		return LWS_SSL_CAPABLE_MORE_SERVICE;
450 
451 	return LWS_SSL_CAPABLE_ERROR;
452 }
453 
454 int
lws_tls_client_confirm_peer_cert(struct lws * wsi,char * ebuf,int ebuf_len)455 lws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, int ebuf_len)
456 {
457 #if !defined(USE_WOLFSSL)
458 	struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
459 	char *p = (char *)&pt->serv_buf[0];
460 	char *sb = p;
461 	int n;
462 
463 	errno = 0;
464 	ERR_clear_error();
465 	n = SSL_get_verify_result(wsi->tls.ssl);
466 
467 	lwsl_debug("get_verify says %d\n", n);
468 
469 	if (n == X509_V_OK)
470 		return 0;
471 
472 	if ((n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
473 	     n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) &&
474 	     (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED)) {
475 		lwsl_info("accepting self-signed certificate\n");
476 
477 		return 0;
478 	}
479 	if ((n == X509_V_ERR_CERT_NOT_YET_VALID ||
480 	     n == X509_V_ERR_CERT_HAS_EXPIRED) &&
481 	     (wsi->tls.use_ssl & LCCSCF_ALLOW_EXPIRED)) {
482 		lwsl_info("accepting expired certificate\n");
483 		return 0;
484 	}
485 	if (n == X509_V_ERR_CERT_NOT_YET_VALID) {
486 		lwsl_info("Cert is from the future... "
487 			    "probably our clock... accepting...\n");
488 		return 0;
489 	}
490 	lws_snprintf(ebuf, ebuf_len,
491 		"server's cert didn't look good, X509_V_ERR = %d: %s\n",
492 		 n, ERR_error_string(n, sb));
493 	lwsl_info("%s\n", ebuf);
494 	lws_tls_err_describe_clear();
495 
496 	return -1;
497 
498 #else /* USE_WOLFSSL */
499 	return 0;
500 #endif
501 }
502 
503 int
lws_tls_client_vhost_extra_cert_mem(struct lws_vhost * vh,const uint8_t * der,size_t der_len)504 lws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh,
505                 const uint8_t *der, size_t der_len)
506 {
507 	X509_STORE *st;
508 	X509 *x  = d2i_X509(NULL, &der, (long)der_len);
509 	int n;
510 
511 	if (!x) {
512 		lwsl_err("%s: Failed to load DER\n", __func__);
513 		lws_tls_err_describe_clear();
514 		return 1;
515 	}
516 
517 	st = SSL_CTX_get_cert_store(vh->tls.ssl_client_ctx);
518 	if (!st) {
519 		lwsl_err("%s: failed to get cert store\n", __func__);
520 		X509_free(x);
521 		return 1;
522 	}
523 
524 	n = X509_STORE_add_cert(st, x);
525 	if (n != 1)
526 		lwsl_err("%s: failed to add cert\n", __func__);
527 
528 	X509_free(x);
529 
530 	return n != 1;
531 }
532 
533 int
lws_tls_client_create_vhost_context(struct lws_vhost * vh,const struct lws_context_creation_info * info,const char * cipher_list,const char * ca_filepath,const void * ca_mem,unsigned int ca_mem_len,const char * cert_filepath,const void * cert_mem,unsigned int cert_mem_len,const char * private_key_filepath)534 lws_tls_client_create_vhost_context(struct lws_vhost *vh,
535 				    const struct lws_context_creation_info *info,
536 				    const char *cipher_list,
537 				    const char *ca_filepath,
538 				    const void *ca_mem,
539 				    unsigned int ca_mem_len,
540 				    const char *cert_filepath,
541 				    const void *cert_mem,
542 				    unsigned int cert_mem_len,
543 				    const char *private_key_filepath)
544 {
545 	struct lws_tls_client_reuse *tcr;
546 	X509_STORE *x509_store;
547 	unsigned long error;
548 	SSL_METHOD *method;
549 	EVP_MD_CTX *mdctx;
550 	unsigned int len;
551 	uint8_t hash[32];
552 	X509 *client_CA;
553 	char c;
554 	int n;
555 
556 	/* basic openssl init already happened in context init */
557 
558 	/* choose the most recent spin of the api */
559 #if defined(LWS_HAVE_TLS_CLIENT_METHOD)
560 	method = (SSL_METHOD *)TLS_client_method();
561 #elif defined(LWS_HAVE_TLSV1_2_CLIENT_METHOD)
562 	method = (SSL_METHOD *)TLSv1_2_client_method();
563 #else
564 	method = (SSL_METHOD *)SSLv23_client_method();
565 #endif
566 
567 	if (!method) {
568 		error = ERR_get_error();
569 		lwsl_err("problem creating ssl method %lu: %s\n",
570 			error, ERR_error_string(error,
571 				      (char *)vh->context->pt[0].serv_buf));
572 		return 1;
573 	}
574 
575 	/*
576 	 * OpenSSL client contexts are quite expensive, because they bring in
577 	 * the system certificate bundle for each one.  So if you have multiple
578 	 * vhosts, each with a client context, it can add up to several
579 	 * megabytes of heap.  In the case the client contexts are configured
580 	 * identically, they could perfectly well have shared just the one.
581 	 *
582 	 * For that reason, use a hash to fingerprint the context configuration
583 	 * and prefer to reuse an existing one with the same fingerprint if
584 	 * possible.
585 	 */
586 
587 	 mdctx = EVP_MD_CTX_create();
588 	 if (!mdctx)
589 		 return 1;
590 
591 	if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) {
592 		EVP_MD_CTX_destroy(mdctx);
593 
594 		return 1;
595 	}
596 
597 	if (info->ssl_client_options_set)
598 		EVP_DigestUpdate(mdctx, &info->ssl_client_options_set,
599 				 sizeof(info->ssl_client_options_set));
600 
601 #if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
602 	if (info->ssl_client_options_clear)
603 		EVP_DigestUpdate(mdctx, &info->ssl_client_options_clear,
604 				 sizeof(info->ssl_client_options_clear));
605 #endif
606 
607 	if (cipher_list)
608 		EVP_DigestUpdate(mdctx, cipher_list, strlen(cipher_list));
609 
610 #if defined(LWS_HAVE_SSL_CTX_set_ciphersuites)
611 	if (info->client_tls_1_3_plus_cipher_list)
612 		EVP_DigestUpdate(mdctx, info->client_tls_1_3_plus_cipher_list,
613 				 strlen(info->client_tls_1_3_plus_cipher_list));
614 #endif
615 
616 	if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS)) {
617 		c = 1;
618 		EVP_DigestUpdate(mdctx, &c, 1);
619 	}
620 
621 	if (ca_filepath)
622 		EVP_DigestUpdate(mdctx, ca_filepath, strlen(ca_filepath));
623 
624 	if (cert_filepath)
625 		EVP_DigestUpdate(mdctx, cert_filepath, strlen(cert_filepath));
626 
627 	if (private_key_filepath)
628 		EVP_DigestUpdate(mdctx, private_key_filepath,
629 				 strlen(private_key_filepath));
630 	if (ca_mem && ca_mem_len)
631 		EVP_DigestUpdate(mdctx, ca_mem, ca_mem_len);
632 
633 	if (cert_mem && cert_mem_len)
634 		EVP_DigestUpdate(mdctx, cert_mem, cert_mem_len);
635 
636 	len = sizeof(hash);
637 	EVP_DigestFinal_ex(mdctx, hash, &len);
638 	EVP_MD_CTX_destroy(mdctx);
639 
640 	/* look for existing client context with same config already */
641 
642 	lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp,
643 			 lws_dll2_get_head(&vh->context->tls.cc_owner)) {
644 		tcr = lws_container_of(p, struct lws_tls_client_reuse, cc_list);
645 
646 		if (!memcmp(hash, tcr->hash, len)) {
647 
648 			/* it's a match */
649 
650 			tcr->refcount++;
651 			vh->tls.ssl_client_ctx = tcr->ssl_client_ctx;
652 
653 			lwsl_info("%s: vh %s: reusing client ctx %d: use %d\n",
654 				   __func__, vh->name, tcr->index,
655 				   tcr->refcount);
656 
657 			return 0;
658 		}
659 	} lws_end_foreach_dll_safe(p, tp);
660 
661 	/* no existing one the same... create new client SSL_CTX */
662 
663 	errno = 0;
664 	ERR_clear_error();
665 	vh->tls.ssl_client_ctx = SSL_CTX_new(method);
666 	if (!vh->tls.ssl_client_ctx) {
667 		error = ERR_get_error();
668 		lwsl_err("problem creating ssl context %lu: %s\n",
669 			error, ERR_error_string(error,
670 				      (char *)vh->context->pt[0].serv_buf));
671 		return 1;
672 	}
673 
674 	tcr = lws_zalloc(sizeof(*tcr), "client ctx tcr");
675 	if (!tcr) {
676 		SSL_CTX_free(vh->tls.ssl_client_ctx);
677 		return 1;
678 	}
679 
680 	tcr->ssl_client_ctx = vh->tls.ssl_client_ctx;
681 	tcr->refcount = 1;
682 	memcpy(tcr->hash, hash, len);
683 	tcr->index = vh->context->tls.count_client_contexts++;
684 	lws_dll2_add_head(&tcr->cc_list, &vh->context->tls.cc_owner);
685 
686 	lwsl_info("%s: vh %s: created new client ctx %d\n", __func__,
687 			vh->name, tcr->index);
688 
689 	/* bind the tcr to the client context */
690 
691 	SSL_CTX_set_ex_data(vh->tls.ssl_client_ctx,
692 			    openssl_SSL_CTX_private_data_index,
693 			    (char *)tcr);
694 
695 #ifdef SSL_OP_NO_COMPRESSION
696 	SSL_CTX_set_options(vh->tls.ssl_client_ctx, SSL_OP_NO_COMPRESSION);
697 #endif
698 
699 	SSL_CTX_set_options(vh->tls.ssl_client_ctx,
700 			    SSL_OP_CIPHER_SERVER_PREFERENCE);
701 
702 	SSL_CTX_set_mode(vh->tls.ssl_client_ctx,
703 			 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
704 			 SSL_MODE_RELEASE_BUFFERS);
705 
706 	if (info->ssl_client_options_set)
707 		SSL_CTX_set_options(vh->tls.ssl_client_ctx,
708 				    info->ssl_client_options_set);
709 
710 	/* SSL_clear_options introduced in 0.9.8m */
711 #if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL)
712 	if (info->ssl_client_options_clear)
713 		SSL_CTX_clear_options(vh->tls.ssl_client_ctx,
714 				      info->ssl_client_options_clear);
715 #endif
716 
717 	if (cipher_list)
718 		SSL_CTX_set_cipher_list(vh->tls.ssl_client_ctx, cipher_list);
719 
720 #if defined(LWS_HAVE_SSL_CTX_set_ciphersuites)
721 	if (info->client_tls_1_3_plus_cipher_list)
722 		SSL_CTX_set_ciphersuites(vh->tls.ssl_client_ctx,
723 					 info->client_tls_1_3_plus_cipher_list);
724 #endif
725 
726 #ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS
727 	if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS))
728 		/* loads OS default CA certs */
729 		SSL_CTX_set_default_verify_paths(vh->tls.ssl_client_ctx);
730 #endif
731 
732 	/* openssl init for cert verification (for client sockets) */
733 	if (!ca_filepath && (!ca_mem || !ca_mem_len)) {
734 		if (!SSL_CTX_load_verify_locations(
735 			vh->tls.ssl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS))
736 			lwsl_err("Unable to load SSL Client certs from %s "
737 			    "(set by LWS_OPENSSL_CLIENT_CERTS) -- "
738 			    "client ssl isn't going to work\n",
739 			    LWS_OPENSSL_CLIENT_CERTS);
740 	} else if (ca_filepath) {
741 		if (!SSL_CTX_load_verify_locations(
742 			vh->tls.ssl_client_ctx, ca_filepath, NULL)) {
743 			lwsl_err(
744 				"Unable to load SSL Client certs "
745 				"file from %s -- client ssl isn't "
746 				"going to work\n", ca_filepath);
747 			lws_tls_err_describe_clear();
748 		}
749 		else
750 			lwsl_info("loaded ssl_ca_filepath\n");
751 	} else {
752 
753 		lws_filepos_t amount = 0;
754 		uint8_t *up1;
755 		const uint8_t *up;
756 
757 		if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, ca_mem,
758 						  ca_mem_len, &up1,
759 						  &amount)) {
760 			lwsl_err("%s: Unable to decode x.509 mem\n", __func__);
761 			lwsl_hexdump_notice(ca_mem, ca_mem_len);
762 			return 1;
763 		}
764 
765 		up = up1;
766 		client_CA = d2i_X509(NULL, &up, (long)amount);
767 		if (!client_CA) {
768 			lwsl_err("%s: d2i_X509 failed\n", __func__);
769 			lwsl_hexdump_notice(up1, (size_t)amount);
770 			lws_tls_err_describe_clear();
771 		} else {
772 			x509_store = X509_STORE_new();
773 			if (!X509_STORE_add_cert(x509_store, client_CA)) {
774 				X509_STORE_free(x509_store);
775 				lwsl_err("Unable to load SSL Client certs from "
776 					 "ssl_ca_mem -- client ssl isn't going to "
777 					 "work\n");
778 				lws_tls_err_describe_clear();
779 			} else {
780 				/* it doesn't increment x509_store ref counter */
781 				SSL_CTX_set_cert_store(vh->tls.ssl_client_ctx,
782 						       x509_store);
783 				lwsl_info("loaded ssl_ca_mem\n");
784 			}
785 		}
786 		if (client_CA)
787 			X509_free(client_CA);
788 		lws_free(up1);
789 	//	lws_tls_client_vhost_extra_cert_mem(vh, ca_mem, ca_mem_len);
790 	}
791 
792 	/*
793 	 * callback allowing user code to load extra verification certs
794 	 * helping the client to verify server identity
795 	 */
796 
797 	/* support for client-side certificate authentication */
798 	if (cert_filepath) {
799 		if (lws_tls_use_any_upgrade_check_extant(cert_filepath) !=
800 				LWS_TLS_EXTANT_YES &&
801 		    (info->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT))
802 			return 0;
803 
804 		lwsl_notice("%s: doing cert filepath %s\n", __func__,
805 				cert_filepath);
806 		n = SSL_CTX_use_certificate_chain_file(vh->tls.ssl_client_ctx,
807 						       cert_filepath);
808 		if (n < 1) {
809 			lwsl_err("problem %d getting cert '%s'\n", n,
810 				 cert_filepath);
811 			lws_tls_err_describe_clear();
812 			return 1;
813 		}
814 		lwsl_notice("Loaded client cert %s\n", cert_filepath);
815 	} else if (cert_mem && cert_mem_len) {
816 		n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx,
817 						 cert_mem_len, cert_mem);
818 		if (n < 1) {
819 			lwsl_err("%s: problem interpreting client cert\n",
820 				 __func__);
821 			lws_tls_err_describe_clear();
822 			return 1;
823 		}
824 	}
825 	if (private_key_filepath) {
826 		lwsl_notice("%s: doing private key filepath\n", __func__);
827 		lws_ssl_bind_passphrase(vh->tls.ssl_client_ctx, 1, info);
828 		/* set the private key from KeyFile */
829 		if (SSL_CTX_use_PrivateKey_file(vh->tls.ssl_client_ctx,
830 		    private_key_filepath, SSL_FILETYPE_PEM) != 1) {
831 			lwsl_err("use_PrivateKey_file '%s'\n",
832 				 private_key_filepath);
833 			lws_tls_err_describe_clear();
834 			return 1;
835 		}
836 		lwsl_notice("Loaded client cert private key %s\n",
837 			    private_key_filepath);
838 
839 		/* verify private key */
840 		if (!SSL_CTX_check_private_key(vh->tls.ssl_client_ctx)) {
841 			lwsl_err("Private SSL key doesn't match cert\n");
842 			return 1;
843 		}
844 	}
845 
846 	return 0;
847 }
848 
849 
850