1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2019 Andy Green <andy@warmcat.com> 5d4afb5ceSopenharmony_ci * 6d4afb5ceSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy 7d4afb5ceSopenharmony_ci * of this software and associated documentation files (the "Software"), to 8d4afb5ceSopenharmony_ci * deal in the Software without restriction, including without limitation the 9d4afb5ceSopenharmony_ci * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10d4afb5ceSopenharmony_ci * sell copies of the Software, and to permit persons to whom the Software is 11d4afb5ceSopenharmony_ci * furnished to do so, subject to the following conditions: 12d4afb5ceSopenharmony_ci * 13d4afb5ceSopenharmony_ci * The above copyright notice and this permission notice shall be included in 14d4afb5ceSopenharmony_ci * all copies or substantial portions of the Software. 15d4afb5ceSopenharmony_ci * 16d4afb5ceSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17d4afb5ceSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18d4afb5ceSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19d4afb5ceSopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20d4afb5ceSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21d4afb5ceSopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22d4afb5ceSopenharmony_ci * IN THE SOFTWARE. 23d4afb5ceSopenharmony_ci */ 24d4afb5ceSopenharmony_ci 25d4afb5ceSopenharmony_ci#include "lws_config.h" 26d4afb5ceSopenharmony_ci#ifdef LWS_HAVE_X509_VERIFY_PARAM_set1_host 27d4afb5ceSopenharmony_ci/* Before glibc 2.10, strnlen required _GNU_SOURCE */ 28d4afb5ceSopenharmony_ci#if !defined(_GNU_SOURCE) 29d4afb5ceSopenharmony_ci#define _GNU_SOURCE 30d4afb5ceSopenharmony_ci#endif 31d4afb5ceSopenharmony_ci#endif 32d4afb5ceSopenharmony_ci#include <string.h> 33d4afb5ceSopenharmony_ci 34d4afb5ceSopenharmony_ci#include "private-lib-core.h" 35d4afb5ceSopenharmony_ci#include "private-lib-tls-openssl.h" 36d4afb5ceSopenharmony_ci 37d4afb5ceSopenharmony_cistatic const int MAX_CLIENT_SSL_CA_NUMBER = 10; 38d4afb5ceSopenharmony_ci 39d4afb5ceSopenharmony_ci/* 40d4afb5ceSopenharmony_ci * Care: many openssl apis return 1 for success. These are translated to the 41d4afb5ceSopenharmony_ci * lws convention of 0 for success. 42d4afb5ceSopenharmony_ci */ 43d4afb5ceSopenharmony_ci 44d4afb5ceSopenharmony_ciint lws_openssl_describe_cipher(struct lws *wsi); 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ciextern int openssl_websocket_private_data_index, 47d4afb5ceSopenharmony_ci openssl_SSL_CTX_private_data_index; 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 50d4afb5ceSopenharmony_ci 51d4afb5ceSopenharmony_ci#if 0 52d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST) 53d4afb5ceSopenharmony_ci 54d4afb5ceSopenharmony_ci/* 55d4afb5ceSopenharmony_ci * Completion of sync or async JIT trust lookup 56d4afb5ceSopenharmony_ci */ 57d4afb5ceSopenharmony_ci 58d4afb5ceSopenharmony_ciint 59d4afb5ceSopenharmony_cilws_tls_jit_trust_got_cert_cb(void *got_opaque, const uint8_t *der, 60d4afb5ceSopenharmony_ci size_t der_len) 61d4afb5ceSopenharmony_ci{ 62d4afb5ceSopenharmony_ci X509 *x = d2i_X509(NULL, &der, (long)der_len); 63d4afb5ceSopenharmony_ci /** !!! this is not safe for async atm */ 64d4afb5ceSopenharmony_ci struct lws *wsi = (struct lws *)got_opaque; 65d4afb5ceSopenharmony_ci X509_STORE *xs; 66d4afb5ceSopenharmony_ci int ret = 0; 67d4afb5ceSopenharmony_ci 68d4afb5ceSopenharmony_ci if (!x) { 69d4afb5ceSopenharmony_ci lwsl_err("%s: failed\n", __func__); 70d4afb5ceSopenharmony_ci return 1; 71d4afb5ceSopenharmony_ci } 72d4afb5ceSopenharmony_ci 73d4afb5ceSopenharmony_ci xs = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(wsi->tls.ssl)); 74d4afb5ceSopenharmony_ci if (xs) { 75d4afb5ceSopenharmony_ci if (X509_STORE_add_cert(xs, x) != 1) { 76d4afb5ceSopenharmony_ci lwsl_warn("%s: unable to set trusted CA\n", __func__); 77d4afb5ceSopenharmony_ci ret = 1; 78d4afb5ceSopenharmony_ci } else 79d4afb5ceSopenharmony_ci lwsl_notice("%s: added trusted CA to CTX for next time\n", 80d4afb5ceSopenharmony_ci __func__); 81d4afb5ceSopenharmony_ci } else 82d4afb5ceSopenharmony_ci lwsl_warn("%s: couldn't get cert store\n", __func__); 83d4afb5ceSopenharmony_ci 84d4afb5ceSopenharmony_ci X509_free(x); 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_ci return ret; 87d4afb5ceSopenharmony_ci} 88d4afb5ceSopenharmony_ci#endif 89d4afb5ceSopenharmony_ci#endif 90d4afb5ceSopenharmony_ci 91d4afb5ceSopenharmony_cistatic int 92d4afb5ceSopenharmony_ciOpenSSL_client_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) 93d4afb5ceSopenharmony_ci{ 94d4afb5ceSopenharmony_ci SSL *ssl; 95d4afb5ceSopenharmony_ci int n, err = 0; 96d4afb5ceSopenharmony_ci struct lws *wsi; 97d4afb5ceSopenharmony_ci 98d4afb5ceSopenharmony_ci /* keep old behaviour accepting self-signed server certs */ 99d4afb5ceSopenharmony_ci if (!preverify_ok) { 100d4afb5ceSopenharmony_ci err = X509_STORE_CTX_get_error(x509_ctx); 101d4afb5ceSopenharmony_ci 102d4afb5ceSopenharmony_ci if (err != X509_V_OK) { 103d4afb5ceSopenharmony_ci ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 104d4afb5ceSopenharmony_ci SSL_get_ex_data_X509_STORE_CTX_idx()); 105d4afb5ceSopenharmony_ci wsi = SSL_get_ex_data(ssl, 106d4afb5ceSopenharmony_ci openssl_websocket_private_data_index); 107d4afb5ceSopenharmony_ci if (!wsi) { 108d4afb5ceSopenharmony_ci lwsl_err("%s: can't get wsi from ssl privdata\n", 109d4afb5ceSopenharmony_ci __func__); 110d4afb5ceSopenharmony_ci 111d4afb5ceSopenharmony_ci return 0; 112d4afb5ceSopenharmony_ci } 113d4afb5ceSopenharmony_ci 114d4afb5ceSopenharmony_ci if ((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || 115d4afb5ceSopenharmony_ci err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) && 116d4afb5ceSopenharmony_ci wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED) { 117d4afb5ceSopenharmony_ci lwsl_notice("accepting self-signed " 118d4afb5ceSopenharmony_ci "certificate (verify_callback)\n"); 119d4afb5ceSopenharmony_ci X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); 120d4afb5ceSopenharmony_ci return 1; // ok 121d4afb5ceSopenharmony_ci } else if ((err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY || 122d4afb5ceSopenharmony_ci err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) && 123d4afb5ceSopenharmony_ci wsi->tls.use_ssl & LCCSCF_ALLOW_INSECURE) { 124d4afb5ceSopenharmony_ci lwsl_notice("accepting non-trusted certificate\n"); 125d4afb5ceSopenharmony_ci X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); 126d4afb5ceSopenharmony_ci return 1; /* ok */ 127d4afb5ceSopenharmony_ci } else if ((err == X509_V_ERR_CERT_NOT_YET_VALID || 128d4afb5ceSopenharmony_ci err == X509_V_ERR_CERT_HAS_EXPIRED) && 129d4afb5ceSopenharmony_ci wsi->tls.use_ssl & LCCSCF_ALLOW_EXPIRED) { 130d4afb5ceSopenharmony_ci if (err == X509_V_ERR_CERT_NOT_YET_VALID) 131d4afb5ceSopenharmony_ci lwsl_notice("accepting not yet valid " 132d4afb5ceSopenharmony_ci "certificate (verify_" 133d4afb5ceSopenharmony_ci "callback)\n"); 134d4afb5ceSopenharmony_ci else if (err == X509_V_ERR_CERT_HAS_EXPIRED) 135d4afb5ceSopenharmony_ci lwsl_notice("accepting expired " 136d4afb5ceSopenharmony_ci "certificate (verify_" 137d4afb5ceSopenharmony_ci "callback)\n"); 138d4afb5ceSopenharmony_ci X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); 139d4afb5ceSopenharmony_ci return 1; // ok 140d4afb5ceSopenharmony_ci } 141d4afb5ceSopenharmony_ci } 142d4afb5ceSopenharmony_ci } 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 145d4afb5ceSopenharmony_ci SSL_get_ex_data_X509_STORE_CTX_idx()); 146d4afb5ceSopenharmony_ci wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index); 147d4afb5ceSopenharmony_ci if (!wsi) { 148d4afb5ceSopenharmony_ci lwsl_err("%s: can't get wsi from ssl privdata\n", __func__); 149d4afb5ceSopenharmony_ci 150d4afb5ceSopenharmony_ci return 0; 151d4afb5ceSopenharmony_ci } 152d4afb5ceSopenharmony_ci 153d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST) 154d4afb5ceSopenharmony_ci if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) { 155d4afb5ceSopenharmony_ci union lws_tls_cert_info_results ci; 156d4afb5ceSopenharmony_ci STACK_OF(X509) *x509_stack; 157d4afb5ceSopenharmony_ci 158d4afb5ceSopenharmony_ci x509_stack = X509_STORE_CTX_get1_chain(x509_ctx); 159d4afb5ceSopenharmony_ci if (x509_stack) { 160d4afb5ceSopenharmony_ci 161d4afb5ceSopenharmony_ci for (n = 0; n < OPENSSL_sk_num((const OPENSSL_STACK *)x509_stack) && 162d4afb5ceSopenharmony_ci wsi->tls.kid_chain.count != 163d4afb5ceSopenharmony_ci LWS_ARRAY_SIZE(wsi->tls.kid_chain.akid); n++) { 164d4afb5ceSopenharmony_ci X509 *x509 = OPENSSL_sk_value((const OPENSSL_STACK *)x509_stack, n); 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_ci if (!lws_tls_openssl_cert_info(x509, 167d4afb5ceSopenharmony_ci LWS_TLS_CERT_INFO_SUBJECT_KEY_ID, 168d4afb5ceSopenharmony_ci &ci, 0)) 169d4afb5ceSopenharmony_ci lws_tls_kid_copy(&ci, 170d4afb5ceSopenharmony_ci &wsi->tls.kid_chain.skid[ 171d4afb5ceSopenharmony_ci wsi->tls.kid_chain.count]); 172d4afb5ceSopenharmony_ci 173d4afb5ceSopenharmony_ci if (!lws_tls_openssl_cert_info(x509, 174d4afb5ceSopenharmony_ci LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID, 175d4afb5ceSopenharmony_ci &ci, 0)) 176d4afb5ceSopenharmony_ci lws_tls_kid_copy(&ci, 177d4afb5ceSopenharmony_ci &wsi->tls.kid_chain.akid[ 178d4afb5ceSopenharmony_ci wsi->tls.kid_chain.count]); 179d4afb5ceSopenharmony_ci 180d4afb5ceSopenharmony_ci wsi->tls.kid_chain.count++; 181d4afb5ceSopenharmony_ci } 182d4afb5ceSopenharmony_ci 183d4afb5ceSopenharmony_ci sk_X509_pop_free(x509_stack, X509_free); 184d4afb5ceSopenharmony_ci } 185d4afb5ceSopenharmony_ci 186d4afb5ceSopenharmony_ci lws_tls_jit_trust_sort_kids(wsi, &wsi->tls.kid_chain); 187d4afb5ceSopenharmony_ci } 188d4afb5ceSopenharmony_ci#endif 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci n = lws_get_context_protocol(wsi->a.context, 0).callback(wsi, 191d4afb5ceSopenharmony_ci LWS_CALLBACK_OPENSSL_PERFORM_SERVER_CERT_VERIFICATION, 192d4afb5ceSopenharmony_ci x509_ctx, ssl, (unsigned int)preverify_ok); 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci /* keep old behaviour if something wrong with server certs */ 195d4afb5ceSopenharmony_ci /* if ssl error is overruled in callback and cert is ok, 196d4afb5ceSopenharmony_ci * X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); must be set and 197d4afb5ceSopenharmony_ci * return value is 0 from callback */ 198d4afb5ceSopenharmony_ci if (!preverify_ok) { 199d4afb5ceSopenharmony_ci int err = X509_STORE_CTX_get_error(x509_ctx); 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_ci if (err != X509_V_OK) { 202d4afb5ceSopenharmony_ci /* cert validation error was not handled in callback */ 203d4afb5ceSopenharmony_ci int depth = X509_STORE_CTX_get_error_depth(x509_ctx); 204d4afb5ceSopenharmony_ci const char *msg = X509_verify_cert_error_string(err); 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci lws_strncpy(wsi->tls.err_helper, msg, 207d4afb5ceSopenharmony_ci sizeof(wsi->tls.err_helper)); 208d4afb5ceSopenharmony_ci 209d4afb5ceSopenharmony_ci lwsl_err("SSL error: %s (preverify_ok=%d;err=%d;" 210d4afb5ceSopenharmony_ci "depth=%d)\n", msg, preverify_ok, err, depth); 211d4afb5ceSopenharmony_ci 212d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS) 213d4afb5ceSopenharmony_ci { 214d4afb5ceSopenharmony_ci char buckname[64]; 215d4afb5ceSopenharmony_ci 216d4afb5ceSopenharmony_ci lws_snprintf(buckname, sizeof(buckname), 217d4afb5ceSopenharmony_ci "tls=\"%s\"", msg); 218d4afb5ceSopenharmony_ci lws_metrics_hist_bump_describe_wsi(wsi, 219d4afb5ceSopenharmony_ci lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures), 220d4afb5ceSopenharmony_ci buckname); 221d4afb5ceSopenharmony_ci } 222d4afb5ceSopenharmony_ci#endif 223d4afb5ceSopenharmony_ci 224d4afb5ceSopenharmony_ci return preverify_ok; // not ok 225d4afb5ceSopenharmony_ci } 226d4afb5ceSopenharmony_ci } 227d4afb5ceSopenharmony_ci /* 228d4afb5ceSopenharmony_ci * convert callback return code from 0 = OK to verify callback 229d4afb5ceSopenharmony_ci * return value 1 = OK 230d4afb5ceSopenharmony_ci */ 231d4afb5ceSopenharmony_ci return !n; 232d4afb5ceSopenharmony_ci} 233d4afb5ceSopenharmony_ci#endif 234d4afb5ceSopenharmony_ci 235d4afb5ceSopenharmony_ciint 236d4afb5ceSopenharmony_cilws_ssl_client_bio_create(struct lws *wsi) 237d4afb5ceSopenharmony_ci{ 238d4afb5ceSopenharmony_ci char hostname[128], *p; 239d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \ 240d4afb5ceSopenharmony_ci defined(LWS_HAVE_SSL_get0_alpn_selected) 241d4afb5ceSopenharmony_ci uint8_t openssl_alpn[40]; 242d4afb5ceSopenharmony_ci const char *alpn_comma = wsi->a.context->tls.alpn_default; 243d4afb5ceSopenharmony_ci int n; 244d4afb5ceSopenharmony_ci#endif 245d4afb5ceSopenharmony_ci 246d4afb5ceSopenharmony_ci if (wsi->stash) { 247d4afb5ceSopenharmony_ci lws_strncpy(hostname, wsi->stash->cis[CIS_HOST], sizeof(hostname)); 248d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \ 249d4afb5ceSopenharmony_ci defined(LWS_HAVE_SSL_get0_alpn_selected) 250d4afb5ceSopenharmony_ci alpn_comma = wsi->stash->cis[CIS_ALPN]; 251d4afb5ceSopenharmony_ci#endif 252d4afb5ceSopenharmony_ci } else { 253d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 254d4afb5ceSopenharmony_ci if (lws_hdr_copy(wsi, hostname, sizeof(hostname), 255d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_HOST) <= 0) 256d4afb5ceSopenharmony_ci#endif 257d4afb5ceSopenharmony_ci { 258d4afb5ceSopenharmony_ci lwsl_err("%s: Unable to get hostname\n", __func__); 259d4afb5ceSopenharmony_ci 260d4afb5ceSopenharmony_ci return -1; 261d4afb5ceSopenharmony_ci } 262d4afb5ceSopenharmony_ci } 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci /* 265d4afb5ceSopenharmony_ci * remove any :port part on the hostname... necessary for network 266d4afb5ceSopenharmony_ci * connection but typical certificates do not contain it 267d4afb5ceSopenharmony_ci */ 268d4afb5ceSopenharmony_ci p = hostname; 269d4afb5ceSopenharmony_ci while (*p) { 270d4afb5ceSopenharmony_ci if (*p == ':') { 271d4afb5ceSopenharmony_ci *p = '\0'; 272d4afb5ceSopenharmony_ci break; 273d4afb5ceSopenharmony_ci } 274d4afb5ceSopenharmony_ci p++; 275d4afb5ceSopenharmony_ci } 276d4afb5ceSopenharmony_ci 277d4afb5ceSopenharmony_ci wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_client_ctx); 278d4afb5ceSopenharmony_ci if (!wsi->tls.ssl) { 279d4afb5ceSopenharmony_ci const char *es = ERR_error_string( 280d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 281d4afb5ceSopenharmony_ci (uint32_t) 282d4afb5ceSopenharmony_ci#else 283d4afb5ceSopenharmony_ci (unsigned long) 284d4afb5ceSopenharmony_ci#endif 285d4afb5ceSopenharmony_ci lws_ssl_get_error(wsi, 0), NULL); 286d4afb5ceSopenharmony_ci lwsl_err("SSL_new failed: %s\n", es); 287d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 288d4afb5ceSopenharmony_ci return -1; 289d4afb5ceSopenharmony_ci } 290d4afb5ceSopenharmony_ci 291d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS) 292d4afb5ceSopenharmony_ci if (!(wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)) 293d4afb5ceSopenharmony_ci lws_tls_reuse_session(wsi); 294d4afb5ceSopenharmony_ci#endif 295d4afb5ceSopenharmony_ci 296d4afb5ceSopenharmony_ci#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK) 297d4afb5ceSopenharmony_ci if (wsi->a.vhost->tls.ssl_info_event_mask) 298d4afb5ceSopenharmony_ci SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback); 299d4afb5ceSopenharmony_ci#endif 300d4afb5ceSopenharmony_ci 301d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_X509_VERIFY_PARAM_set1_host) 302d4afb5ceSopenharmony_ci if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) { 303d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 304d4afb5ceSopenharmony_ci 305d4afb5ceSopenharmony_ci X509_VERIFY_PARAM *param = SSL_get0_param(wsi->tls.ssl); 306d4afb5ceSopenharmony_ci 307d4afb5ceSopenharmony_ci /* Enable automatic hostname checks */ 308d4afb5ceSopenharmony_ci X509_VERIFY_PARAM_set_hostflags(param, 309d4afb5ceSopenharmony_ci X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); 310d4afb5ceSopenharmony_ci /* Handle the case where the hostname is an IP address */ 311d4afb5ceSopenharmony_ci if (!X509_VERIFY_PARAM_set1_ip_asc(param, hostname)) 312d4afb5ceSopenharmony_ci X509_VERIFY_PARAM_set1_host(param, hostname, 313d4afb5ceSopenharmony_ci strnlen(hostname, sizeof(hostname))); 314d4afb5ceSopenharmony_ci#endif 315d4afb5ceSopenharmony_ci 316d4afb5ceSopenharmony_ci } 317d4afb5ceSopenharmony_ci#else 318d4afb5ceSopenharmony_ci if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) { 319d4afb5ceSopenharmony_ci lwsl_err("%s: your tls lib is too old to have " 320d4afb5ceSopenharmony_ci "X509_VERIFY_PARAM_set1_host, failing all client tls\n", 321d4afb5ceSopenharmony_ci __func__); 322d4afb5ceSopenharmony_ci return -1; 323d4afb5ceSopenharmony_ci } 324d4afb5ceSopenharmony_ci#endif 325d4afb5ceSopenharmony_ci 326d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 327d4afb5ceSopenharmony_ci#ifndef USE_OLD_CYASSL 328d4afb5ceSopenharmony_ci /* OpenSSL_client_verify_callback will be called @ SSL_connect() */ 329d4afb5ceSopenharmony_ci SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER, 330d4afb5ceSopenharmony_ci OpenSSL_client_verify_callback); 331d4afb5ceSopenharmony_ci#endif 332d4afb5ceSopenharmony_ci#endif 333d4afb5ceSopenharmony_ci 334d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 335d4afb5ceSopenharmony_ci SSL_set_mode(wsi->tls.ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); 336d4afb5ceSopenharmony_ci#endif 337d4afb5ceSopenharmony_ci /* 338d4afb5ceSopenharmony_ci * use server name indication (SNI), if supported, 339d4afb5ceSopenharmony_ci * when establishing connection 340d4afb5ceSopenharmony_ci */ 341d4afb5ceSopenharmony_ci#ifdef USE_WOLFSSL 342d4afb5ceSopenharmony_ci#ifdef USE_OLD_CYASSL 343d4afb5ceSopenharmony_ci#ifdef CYASSL_SNI_HOST_NAME 344d4afb5ceSopenharmony_ci CyaSSL_UseSNI(wsi->tls.ssl, CYASSL_SNI_HOST_NAME, hostname, 345d4afb5ceSopenharmony_ci strlen(hostname)); 346d4afb5ceSopenharmony_ci#endif 347d4afb5ceSopenharmony_ci#else 348d4afb5ceSopenharmony_ci#if defined(WOLFSSL_SNI_HOST_NAME) || defined(HAVE_SNI) 349d4afb5ceSopenharmony_ci wolfSSL_UseSNI(wsi->tls.ssl, WOLFSSL_SNI_HOST_NAME, hostname, 350d4afb5ceSopenharmony_ci (unsigned short)strlen(hostname)); 351d4afb5ceSopenharmony_ci#endif 352d4afb5ceSopenharmony_ci#endif 353d4afb5ceSopenharmony_ci#else 354d4afb5ceSopenharmony_ci#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME 355d4afb5ceSopenharmony_ci SSL_set_tlsext_host_name(wsi->tls.ssl, hostname); 356d4afb5ceSopenharmony_ci#endif 357d4afb5ceSopenharmony_ci#endif 358d4afb5ceSopenharmony_ci 359d4afb5ceSopenharmony_ci#ifdef USE_WOLFSSL 360d4afb5ceSopenharmony_ci /* 361d4afb5ceSopenharmony_ci * wolfSSL/CyaSSL does certificate verification differently 362d4afb5ceSopenharmony_ci * from OpenSSL. 363d4afb5ceSopenharmony_ci * If we should ignore the certificate, we need to set 364d4afb5ceSopenharmony_ci * this before SSL_new and SSL_connect is called. 365d4afb5ceSopenharmony_ci * Otherwise the connect will simply fail with error code -155 366d4afb5ceSopenharmony_ci */ 367d4afb5ceSopenharmony_ci#ifdef USE_OLD_CYASSL 368d4afb5ceSopenharmony_ci if (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED) 369d4afb5ceSopenharmony_ci CyaSSL_set_verify(wsi->tls.ssl, SSL_VERIFY_NONE, NULL); 370d4afb5ceSopenharmony_ci#else 371d4afb5ceSopenharmony_ci if (wsi->tls.use_ssl & LCCSCF_ALLOW_SELFSIGNED) 372d4afb5ceSopenharmony_ci wolfSSL_set_verify(wsi->tls.ssl, SSL_VERIFY_NONE, NULL); 373d4afb5ceSopenharmony_ci#endif 374d4afb5ceSopenharmony_ci#endif /* USE_WOLFSSL */ 375d4afb5ceSopenharmony_ci 376d4afb5ceSopenharmony_ci wsi->tls.client_bio = BIO_new_socket((int)(lws_intptr_t)wsi->desc.sockfd, 377d4afb5ceSopenharmony_ci BIO_NOCLOSE); 378d4afb5ceSopenharmony_ci SSL_set_bio(wsi->tls.ssl, wsi->tls.client_bio, wsi->tls.client_bio); 379d4afb5ceSopenharmony_ci 380d4afb5ceSopenharmony_ci#ifdef USE_WOLFSSL 381d4afb5ceSopenharmony_ci#ifdef USE_OLD_CYASSL 382d4afb5ceSopenharmony_ci CyaSSL_set_using_nonblock(wsi->tls.ssl, 1); 383d4afb5ceSopenharmony_ci#else 384d4afb5ceSopenharmony_ci wolfSSL_set_using_nonblock(wsi->tls.ssl, 1); 385d4afb5ceSopenharmony_ci#endif 386d4afb5ceSopenharmony_ci#else 387d4afb5ceSopenharmony_ci BIO_set_nbio(wsi->tls.client_bio, 1); /* nonblocking */ 388d4afb5ceSopenharmony_ci#endif 389d4afb5ceSopenharmony_ci 390d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \ 391d4afb5ceSopenharmony_ci defined(LWS_HAVE_SSL_get0_alpn_selected) 392d4afb5ceSopenharmony_ci if (wsi->a.vhost->tls.alpn) 393d4afb5ceSopenharmony_ci alpn_comma = wsi->a.vhost->tls.alpn; 394d4afb5ceSopenharmony_ci if (wsi->stash) 395d4afb5ceSopenharmony_ci alpn_comma = wsi->stash->cis[CIS_ALPN]; 396d4afb5ceSopenharmony_ci#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) 397d4afb5ceSopenharmony_ci if (lws_hdr_copy(wsi, hostname, sizeof(hostname), 398d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_ALPN) > 0) 399d4afb5ceSopenharmony_ci alpn_comma = hostname; 400d4afb5ceSopenharmony_ci#endif 401d4afb5ceSopenharmony_ci 402d4afb5ceSopenharmony_ci lwsl_info("%s client conn using alpn list '%s'\n", wsi->role_ops->name, alpn_comma); 403d4afb5ceSopenharmony_ci 404d4afb5ceSopenharmony_ci n = lws_alpn_comma_to_openssl(alpn_comma, openssl_alpn, 405d4afb5ceSopenharmony_ci sizeof(openssl_alpn) - 1); 406d4afb5ceSopenharmony_ci 407d4afb5ceSopenharmony_ci SSL_set_alpn_protos(wsi->tls.ssl, openssl_alpn, (unsigned int)n); 408d4afb5ceSopenharmony_ci#endif 409d4afb5ceSopenharmony_ci 410d4afb5ceSopenharmony_ci SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index, 411d4afb5ceSopenharmony_ci wsi); 412d4afb5ceSopenharmony_ci 413d4afb5ceSopenharmony_ci if (wsi->sys_tls_client_cert) { 414d4afb5ceSopenharmony_ci lws_system_blob_t *b = lws_system_get_blob(wsi->a.context, 415d4afb5ceSopenharmony_ci LWS_SYSBLOB_TYPE_CLIENT_CERT_DER, 416d4afb5ceSopenharmony_ci wsi->sys_tls_client_cert - 1); 417d4afb5ceSopenharmony_ci const uint8_t *data; 418d4afb5ceSopenharmony_ci size_t size; 419d4afb5ceSopenharmony_ci 420d4afb5ceSopenharmony_ci if (!b) 421d4afb5ceSopenharmony_ci goto no_client_cert; 422d4afb5ceSopenharmony_ci 423d4afb5ceSopenharmony_ci /* 424d4afb5ceSopenharmony_ci * Set up the per-connection client cert 425d4afb5ceSopenharmony_ci */ 426d4afb5ceSopenharmony_ci 427d4afb5ceSopenharmony_ci size = lws_system_blob_get_size(b); 428d4afb5ceSopenharmony_ci if (!size) 429d4afb5ceSopenharmony_ci goto no_client_cert; 430d4afb5ceSopenharmony_ci 431d4afb5ceSopenharmony_ci if (lws_system_blob_get_single_ptr(b, &data)) 432d4afb5ceSopenharmony_ci goto no_client_cert; 433d4afb5ceSopenharmony_ci 434d4afb5ceSopenharmony_ci if (SSL_use_certificate_ASN1(wsi->tls.ssl, 435d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL) 436d4afb5ceSopenharmony_ci (unsigned char *) 437d4afb5ceSopenharmony_ci#endif 438d4afb5ceSopenharmony_ci data, 439d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 440d4afb5ceSopenharmony_ci (size_t) 441d4afb5ceSopenharmony_ci#else 442d4afb5ceSopenharmony_ci (int) 443d4afb5ceSopenharmony_ci#endif 444d4afb5ceSopenharmony_ci size) != 1) { 445d4afb5ceSopenharmony_ci lwsl_err("%s: use_certificate failed\n", __func__); 446d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 447d4afb5ceSopenharmony_ci goto no_client_cert; 448d4afb5ceSopenharmony_ci } 449d4afb5ceSopenharmony_ci 450d4afb5ceSopenharmony_ci b = lws_system_get_blob(wsi->a.context, 451d4afb5ceSopenharmony_ci LWS_SYSBLOB_TYPE_CLIENT_KEY_DER, 452d4afb5ceSopenharmony_ci wsi->sys_tls_client_cert - 1); 453d4afb5ceSopenharmony_ci if (!b) 454d4afb5ceSopenharmony_ci goto no_client_cert; 455d4afb5ceSopenharmony_ci 456d4afb5ceSopenharmony_ci size = lws_system_blob_get_size(b); 457d4afb5ceSopenharmony_ci if (!size) 458d4afb5ceSopenharmony_ci goto no_client_cert; 459d4afb5ceSopenharmony_ci 460d4afb5ceSopenharmony_ci if (lws_system_blob_get_single_ptr(b, &data)) 461d4afb5ceSopenharmony_ci goto no_client_cert; 462d4afb5ceSopenharmony_ci 463d4afb5ceSopenharmony_ci if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, wsi->tls.ssl, 464d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL) 465d4afb5ceSopenharmony_ci (unsigned char *) 466d4afb5ceSopenharmony_ci#endif 467d4afb5ceSopenharmony_ci 468d4afb5ceSopenharmony_ci data, 469d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 470d4afb5ceSopenharmony_ci (size_t) 471d4afb5ceSopenharmony_ci#else 472d4afb5ceSopenharmony_ci (int) 473d4afb5ceSopenharmony_ci#endif 474d4afb5ceSopenharmony_ci size) != 1 && 475d4afb5ceSopenharmony_ci SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, wsi->tls.ssl, 476d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL) 477d4afb5ceSopenharmony_ci (unsigned char *) 478d4afb5ceSopenharmony_ci#endif 479d4afb5ceSopenharmony_ci data, 480d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 481d4afb5ceSopenharmony_ci (size_t) 482d4afb5ceSopenharmony_ci#else 483d4afb5ceSopenharmony_ci (int) 484d4afb5ceSopenharmony_ci#endif 485d4afb5ceSopenharmony_ci size) != 1) { 486d4afb5ceSopenharmony_ci lwsl_err("%s: use_privkey failed\n", __func__); 487d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 488d4afb5ceSopenharmony_ci goto no_client_cert; 489d4afb5ceSopenharmony_ci } 490d4afb5ceSopenharmony_ci 491d4afb5ceSopenharmony_ci if (SSL_check_private_key(wsi->tls.ssl) != 1) { 492d4afb5ceSopenharmony_ci lwsl_err("Private SSL key doesn't match cert\n"); 493d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 494d4afb5ceSopenharmony_ci return 1; 495d4afb5ceSopenharmony_ci } 496d4afb5ceSopenharmony_ci 497d4afb5ceSopenharmony_ci lwsl_notice("%s: set system client cert %u\n", __func__, 498d4afb5ceSopenharmony_ci wsi->sys_tls_client_cert - 1); 499d4afb5ceSopenharmony_ci } 500d4afb5ceSopenharmony_ci 501d4afb5ceSopenharmony_ci return 0; 502d4afb5ceSopenharmony_ci 503d4afb5ceSopenharmony_cino_client_cert: 504d4afb5ceSopenharmony_ci lwsl_err("%s: unable to set up system client cert %d\n", __func__, 505d4afb5ceSopenharmony_ci wsi->sys_tls_client_cert - 1); 506d4afb5ceSopenharmony_ci 507d4afb5ceSopenharmony_ci return 1; 508d4afb5ceSopenharmony_ci} 509d4afb5ceSopenharmony_ci 510d4afb5ceSopenharmony_cienum lws_ssl_capable_status 511d4afb5ceSopenharmony_cilws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen) 512d4afb5ceSopenharmony_ci{ 513d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \ 514d4afb5ceSopenharmony_ci defined(LWS_HAVE_SSL_get0_alpn_selected) 515d4afb5ceSopenharmony_ci const unsigned char *prot; 516d4afb5ceSopenharmony_ci char a[32]; 517d4afb5ceSopenharmony_ci unsigned int len; 518d4afb5ceSopenharmony_ci#endif 519d4afb5ceSopenharmony_ci int m, n, en; 520d4afb5ceSopenharmony_ci unsigned long l; 521d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS) && defined(LWS_HAVE_SSL_SESSION_set_time) 522d4afb5ceSopenharmony_ci SSL_SESSION *sess; 523d4afb5ceSopenharmony_ci#endif 524d4afb5ceSopenharmony_ci errno = 0; 525d4afb5ceSopenharmony_ci ERR_clear_error(); 526d4afb5ceSopenharmony_ci wsi->tls.err_helper[0] = '\0'; 527d4afb5ceSopenharmony_ci n = SSL_connect(wsi->tls.ssl); 528d4afb5ceSopenharmony_ci en = errno; 529d4afb5ceSopenharmony_ci 530d4afb5ceSopenharmony_ci m = lws_ssl_get_error(wsi, n); 531d4afb5ceSopenharmony_ci 532d4afb5ceSopenharmony_ci if (m == SSL_ERROR_SYSCALL 533d4afb5ceSopenharmony_ci#if defined(WIN32) 534d4afb5ceSopenharmony_ci && en 535d4afb5ceSopenharmony_ci#endif 536d4afb5ceSopenharmony_ci ) { 537d4afb5ceSopenharmony_ci#if defined(WIN32) || (_LWS_ENABLED_LOGS & LLL_INFO) 538d4afb5ceSopenharmony_ci lwsl_info("%s: n %d, m %d, errno %d\n", __func__, n, m, en); 539d4afb5ceSopenharmony_ci#endif 540d4afb5ceSopenharmony_ci lws_snprintf(errbuf, elen, "connect SYSCALL %d", en); 541d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_ERROR; 542d4afb5ceSopenharmony_ci } 543d4afb5ceSopenharmony_ci 544d4afb5ceSopenharmony_ci if (m == SSL_ERROR_SSL) { 545d4afb5ceSopenharmony_ci l = ERR_get_error(); 546d4afb5ceSopenharmony_ci n = lws_snprintf(errbuf, elen, "tls: %s", wsi->tls.err_helper); 547d4afb5ceSopenharmony_ci if (!wsi->tls.err_helper[0]) 548d4afb5ceSopenharmony_ci ERR_error_string_n((unsigned int)l, errbuf + n, (elen - (unsigned int)n)); 549d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_ERROR; 550d4afb5ceSopenharmony_ci } 551d4afb5ceSopenharmony_ci 552d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS) 553d4afb5ceSopenharmony_ci if (SSL_session_reused(wsi->tls.ssl)) { 554d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_SESSION_set_time) 555d4afb5ceSopenharmony_ci sess = SSL_get_session(wsi->tls.ssl); 556d4afb5ceSopenharmony_ci if (sess) /* should always be true */ 557d4afb5ceSopenharmony_ci#if defined(OPENSSL_IS_BORINGSSL) 558d4afb5ceSopenharmony_ci SSL_SESSION_set_time(sess, (uint64_t)time(NULL)); /* extend session lifetime */ 559d4afb5ceSopenharmony_ci#else 560d4afb5ceSopenharmony_ci SSL_SESSION_set_time(sess, (long)time(NULL)); /* extend session lifetime */ 561d4afb5ceSopenharmony_ci#endif 562d4afb5ceSopenharmony_ci#endif 563d4afb5ceSopenharmony_ci } 564d4afb5ceSopenharmony_ci#endif 565d4afb5ceSopenharmony_ci 566d4afb5ceSopenharmony_ci if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) 567d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_MORE_SERVICE_READ; 568d4afb5ceSopenharmony_ci 569d4afb5ceSopenharmony_ci if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) 570d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE; 571d4afb5ceSopenharmony_ci 572d4afb5ceSopenharmony_ci if (n == 1 || m == SSL_ERROR_SYSCALL) { 573d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_set_alpn_protos) && \ 574d4afb5ceSopenharmony_ci defined(LWS_HAVE_SSL_get0_alpn_selected) 575d4afb5ceSopenharmony_ci SSL_get0_alpn_selected(wsi->tls.ssl, &prot, &len); 576d4afb5ceSopenharmony_ci 577d4afb5ceSopenharmony_ci if (len >= sizeof(a)) 578d4afb5ceSopenharmony_ci len = sizeof(a) - 1; 579d4afb5ceSopenharmony_ci memcpy(a, (const char *)prot, len); 580d4afb5ceSopenharmony_ci a[len] = '\0'; 581d4afb5ceSopenharmony_ci 582d4afb5ceSopenharmony_ci lws_role_call_alpn_negotiated(wsi, (const char *)a); 583d4afb5ceSopenharmony_ci#endif 584d4afb5ceSopenharmony_ci#if defined(LWS_TLS_SYNTHESIZE_CB) 585d4afb5ceSopenharmony_ci lws_sul_schedule(wsi->a.context, wsi->tsi, 586d4afb5ceSopenharmony_ci &wsi->tls.sul_cb_synth, 587d4afb5ceSopenharmony_ci lws_sess_cache_synth_cb, 500 * LWS_US_PER_MS); 588d4afb5ceSopenharmony_ci#endif 589d4afb5ceSopenharmony_ci 590d4afb5ceSopenharmony_ci lwsl_info("client connect OK\n"); 591d4afb5ceSopenharmony_ci lws_openssl_describe_cipher(wsi); 592d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_DONE; 593d4afb5ceSopenharmony_ci } 594d4afb5ceSopenharmony_ci 595d4afb5ceSopenharmony_ci if (!n) /* we don't know what he wants, but he says to retry */ 596d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_MORE_SERVICE; 597d4afb5ceSopenharmony_ci 598d4afb5ceSopenharmony_ci lws_snprintf(errbuf, elen, "connect unk %d", m); 599d4afb5ceSopenharmony_ci 600d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_ERROR; 601d4afb5ceSopenharmony_ci} 602d4afb5ceSopenharmony_ci 603d4afb5ceSopenharmony_ciint 604d4afb5ceSopenharmony_cilws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, size_t ebuf_len) 605d4afb5ceSopenharmony_ci{ 606d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 607d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 608d4afb5ceSopenharmony_ci char *p = (char *)&pt->serv_buf[0]; 609d4afb5ceSopenharmony_ci const char *es, *type = ""; 610d4afb5ceSopenharmony_ci unsigned int avoid = 0; 611d4afb5ceSopenharmony_ci char *sb = p; 612d4afb5ceSopenharmony_ci long n; 613d4afb5ceSopenharmony_ci 614d4afb5ceSopenharmony_ci errno = 0; 615d4afb5ceSopenharmony_ci ERR_clear_error(); 616d4afb5ceSopenharmony_ci n = SSL_get_verify_result(wsi->tls.ssl); 617d4afb5ceSopenharmony_ci 618d4afb5ceSopenharmony_ci switch (n) { 619d4afb5ceSopenharmony_ci case X509_V_OK: 620d4afb5ceSopenharmony_ci return 0; 621d4afb5ceSopenharmony_ci 622d4afb5ceSopenharmony_ci case X509_V_ERR_HOSTNAME_MISMATCH: 623d4afb5ceSopenharmony_ci type = "tls=hostname"; 624d4afb5ceSopenharmony_ci avoid = LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK; 625d4afb5ceSopenharmony_ci break; 626d4afb5ceSopenharmony_ci 627d4afb5ceSopenharmony_ci case X509_V_ERR_INVALID_CA: 628d4afb5ceSopenharmony_ci case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: 629d4afb5ceSopenharmony_ci case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: 630d4afb5ceSopenharmony_ci type = "tls=invalidca"; 631d4afb5ceSopenharmony_ci avoid = LCCSCF_ALLOW_SELFSIGNED; 632d4afb5ceSopenharmony_ci break; 633d4afb5ceSopenharmony_ci 634d4afb5ceSopenharmony_ci case X509_V_ERR_CERT_NOT_YET_VALID: 635d4afb5ceSopenharmony_ci type = "tls=notyetvalid"; 636d4afb5ceSopenharmony_ci avoid = LCCSCF_ALLOW_EXPIRED; 637d4afb5ceSopenharmony_ci break; 638d4afb5ceSopenharmony_ci 639d4afb5ceSopenharmony_ci case X509_V_ERR_CERT_HAS_EXPIRED: 640d4afb5ceSopenharmony_ci type = "tls=expired"; 641d4afb5ceSopenharmony_ci avoid = LCCSCF_ALLOW_EXPIRED; 642d4afb5ceSopenharmony_ci break; 643d4afb5ceSopenharmony_ci } 644d4afb5ceSopenharmony_ci 645d4afb5ceSopenharmony_ci lwsl_info("%s: cert problem: %s\n", __func__, type); 646d4afb5ceSopenharmony_ci 647d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS) 648d4afb5ceSopenharmony_ci lws_metrics_hist_bump_describe_wsi(wsi, 649d4afb5ceSopenharmony_ci lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures), type); 650d4afb5ceSopenharmony_ci#endif 651d4afb5ceSopenharmony_ci 652d4afb5ceSopenharmony_ci if (wsi->tls.use_ssl & avoid) { 653d4afb5ceSopenharmony_ci lwsl_info("%s: allowing anyway\n", __func__); 654d4afb5ceSopenharmony_ci 655d4afb5ceSopenharmony_ci return 0; 656d4afb5ceSopenharmony_ci } 657d4afb5ceSopenharmony_ci 658d4afb5ceSopenharmony_ci es = ERR_error_string( 659d4afb5ceSopenharmony_ci #if defined(LWS_WITH_BORINGSSL) 660d4afb5ceSopenharmony_ci (uint32_t) 661d4afb5ceSopenharmony_ci #else 662d4afb5ceSopenharmony_ci (unsigned long) 663d4afb5ceSopenharmony_ci #endif 664d4afb5ceSopenharmony_ci n, sb); 665d4afb5ceSopenharmony_ci lws_snprintf(ebuf, ebuf_len, 666d4afb5ceSopenharmony_ci "server's cert didn't look good, %s X509_V_ERR = %ld: %s\n", 667d4afb5ceSopenharmony_ci type, n, es); 668d4afb5ceSopenharmony_ci lwsl_info("%s\n", ebuf); 669d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 670d4afb5ceSopenharmony_ci 671d4afb5ceSopenharmony_ci return -1; 672d4afb5ceSopenharmony_ci 673d4afb5ceSopenharmony_ci#else /* USE_WOLFSSL */ 674d4afb5ceSopenharmony_ci return 0; 675d4afb5ceSopenharmony_ci#endif 676d4afb5ceSopenharmony_ci} 677d4afb5ceSopenharmony_ci 678d4afb5ceSopenharmony_ciint 679d4afb5ceSopenharmony_cilws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh, 680d4afb5ceSopenharmony_ci const uint8_t *der, size_t der_len) 681d4afb5ceSopenharmony_ci{ 682d4afb5ceSopenharmony_ci X509_STORE *st; 683d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL) 684d4afb5ceSopenharmony_ci X509 *x = d2i_X509(NULL, &der, (int)der_len); 685d4afb5ceSopenharmony_ci#else 686d4afb5ceSopenharmony_ci X509 *x = d2i_X509(NULL, &der, (long)der_len); 687d4afb5ceSopenharmony_ci#endif 688d4afb5ceSopenharmony_ci int n; 689d4afb5ceSopenharmony_ci 690d4afb5ceSopenharmony_ci if (!x) { 691d4afb5ceSopenharmony_ci lwsl_err("%s: Failed to load DER\n", __func__); 692d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 693d4afb5ceSopenharmony_ci return 1; 694d4afb5ceSopenharmony_ci } 695d4afb5ceSopenharmony_ci 696d4afb5ceSopenharmony_ci st = SSL_CTX_get_cert_store(vh->tls.ssl_client_ctx); 697d4afb5ceSopenharmony_ci if (!st) { 698d4afb5ceSopenharmony_ci lwsl_err("%s: failed to get cert store\n", __func__); 699d4afb5ceSopenharmony_ci X509_free(x); 700d4afb5ceSopenharmony_ci return 1; 701d4afb5ceSopenharmony_ci } 702d4afb5ceSopenharmony_ci 703d4afb5ceSopenharmony_ci n = X509_STORE_add_cert(st, x); 704d4afb5ceSopenharmony_ci if (n != 1) 705d4afb5ceSopenharmony_ci lwsl_err("%s: failed to add cert\n", __func__); 706d4afb5ceSopenharmony_ci 707d4afb5ceSopenharmony_ci X509_free(x); 708d4afb5ceSopenharmony_ci 709d4afb5ceSopenharmony_ci return n != 1; 710d4afb5ceSopenharmony_ci} 711d4afb5ceSopenharmony_ci 712d4afb5ceSopenharmony_ciint 713d4afb5ceSopenharmony_cilws_tls_client_create_vhost_context(struct lws_vhost *vh, 714d4afb5ceSopenharmony_ci const struct lws_context_creation_info *info, 715d4afb5ceSopenharmony_ci const char *cipher_list, 716d4afb5ceSopenharmony_ci const char *ca_filepath, 717d4afb5ceSopenharmony_ci const void *ca_mem, 718d4afb5ceSopenharmony_ci unsigned int ca_mem_len, 719d4afb5ceSopenharmony_ci const char *cert_filepath, 720d4afb5ceSopenharmony_ci const void *cert_mem, 721d4afb5ceSopenharmony_ci unsigned int cert_mem_len, 722d4afb5ceSopenharmony_ci const char *private_key_filepath, 723d4afb5ceSopenharmony_ci const void *key_mem, 724d4afb5ceSopenharmony_ci unsigned int key_mem_len 725d4afb5ceSopenharmony_ci ) 726d4afb5ceSopenharmony_ci{ 727d4afb5ceSopenharmony_ci struct lws_tls_client_reuse *tcr; 728d4afb5ceSopenharmony_ci X509_STORE *x509_store; 729d4afb5ceSopenharmony_ci unsigned long error; 730d4afb5ceSopenharmony_ci SSL_METHOD *method; 731d4afb5ceSopenharmony_ci EVP_MD_CTX *mdctx; 732d4afb5ceSopenharmony_ci unsigned int len; 733d4afb5ceSopenharmony_ci uint8_t hash[32]; 734d4afb5ceSopenharmony_ci X509 *client_CA; 735d4afb5ceSopenharmony_ci char c; 736d4afb5ceSopenharmony_ci int n; 737d4afb5ceSopenharmony_ci 738d4afb5ceSopenharmony_ci /* basic openssl init already happened in context init */ 739d4afb5ceSopenharmony_ci 740d4afb5ceSopenharmony_ci /* choose the most recent spin of the api */ 741d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_TLS_CLIENT_METHOD) 742d4afb5ceSopenharmony_ci method = (SSL_METHOD *)TLS_client_method(); 743d4afb5ceSopenharmony_ci#elif defined(LWS_HAVE_TLSV1_2_CLIENT_METHOD) 744d4afb5ceSopenharmony_ci method = (SSL_METHOD *)TLSv1_2_client_method(); 745d4afb5ceSopenharmony_ci#else 746d4afb5ceSopenharmony_ci method = (SSL_METHOD *)SSLv23_client_method(); 747d4afb5ceSopenharmony_ci#endif 748d4afb5ceSopenharmony_ci 749d4afb5ceSopenharmony_ci if (!method) { 750d4afb5ceSopenharmony_ci const char *es; 751d4afb5ceSopenharmony_ci 752d4afb5ceSopenharmony_ci error = ERR_get_error(); 753d4afb5ceSopenharmony_ci es = ERR_error_string( 754d4afb5ceSopenharmony_ci #if defined(LWS_WITH_BORINGSSL) 755d4afb5ceSopenharmony_ci (uint32_t) 756d4afb5ceSopenharmony_ci #else 757d4afb5ceSopenharmony_ci (unsigned long) 758d4afb5ceSopenharmony_ci #endif 759d4afb5ceSopenharmony_ci error, (char *)vh->context->pt[0].serv_buf); 760d4afb5ceSopenharmony_ci lwsl_err("problem creating ssl method %lu: %s\n", 761d4afb5ceSopenharmony_ci error, es); 762d4afb5ceSopenharmony_ci return 1; 763d4afb5ceSopenharmony_ci } 764d4afb5ceSopenharmony_ci 765d4afb5ceSopenharmony_ci /* 766d4afb5ceSopenharmony_ci * OpenSSL client contexts are quite expensive, because they bring in 767d4afb5ceSopenharmony_ci * the system certificate bundle for each one. So if you have multiple 768d4afb5ceSopenharmony_ci * vhosts, each with a client context, it can add up to several 769d4afb5ceSopenharmony_ci * megabytes of heap. In the case the client contexts are configured 770d4afb5ceSopenharmony_ci * identically, they could perfectly well have shared just the one. 771d4afb5ceSopenharmony_ci * 772d4afb5ceSopenharmony_ci * For that reason, use a hash to fingerprint the context configuration 773d4afb5ceSopenharmony_ci * and prefer to reuse an existing one with the same fingerprint if 774d4afb5ceSopenharmony_ci * possible. 775d4afb5ceSopenharmony_ci */ 776d4afb5ceSopenharmony_ci 777d4afb5ceSopenharmony_ci mdctx = EVP_MD_CTX_create(); 778d4afb5ceSopenharmony_ci if (!mdctx) 779d4afb5ceSopenharmony_ci return 1; 780d4afb5ceSopenharmony_ci 781d4afb5ceSopenharmony_ci if (EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL) != 1) { 782d4afb5ceSopenharmony_ci EVP_MD_CTX_destroy(mdctx); 783d4afb5ceSopenharmony_ci 784d4afb5ceSopenharmony_ci return 1; 785d4afb5ceSopenharmony_ci } 786d4afb5ceSopenharmony_ci 787d4afb5ceSopenharmony_ci if (info->ssl_client_options_set) 788d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, &info->ssl_client_options_set, 789d4afb5ceSopenharmony_ci sizeof(info->ssl_client_options_set)); 790d4afb5ceSopenharmony_ci 791d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL) 792d4afb5ceSopenharmony_ci if (info->ssl_client_options_clear) 793d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, &info->ssl_client_options_clear, 794d4afb5ceSopenharmony_ci sizeof(info->ssl_client_options_clear)); 795d4afb5ceSopenharmony_ci#endif 796d4afb5ceSopenharmony_ci 797d4afb5ceSopenharmony_ci if (cipher_list) 798d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, cipher_list, strlen(cipher_list)); 799d4afb5ceSopenharmony_ci 800d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_set_ciphersuites) 801d4afb5ceSopenharmony_ci if (info->client_tls_1_3_plus_cipher_list) 802d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, info->client_tls_1_3_plus_cipher_list, 803d4afb5ceSopenharmony_ci strlen(info->client_tls_1_3_plus_cipher_list)); 804d4afb5ceSopenharmony_ci#endif 805d4afb5ceSopenharmony_ci 806d4afb5ceSopenharmony_ci if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS)) { 807d4afb5ceSopenharmony_ci c = 1; 808d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, &c, 1); 809d4afb5ceSopenharmony_ci } 810d4afb5ceSopenharmony_ci 811d4afb5ceSopenharmony_ci if (ca_filepath) 812d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, ca_filepath, strlen(ca_filepath)); 813d4afb5ceSopenharmony_ci 814d4afb5ceSopenharmony_ci if (cert_filepath) 815d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, cert_filepath, strlen(cert_filepath)); 816d4afb5ceSopenharmony_ci 817d4afb5ceSopenharmony_ci if (private_key_filepath) 818d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, private_key_filepath, 819d4afb5ceSopenharmony_ci strlen(private_key_filepath)); 820d4afb5ceSopenharmony_ci if (ca_mem && ca_mem_len) 821d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, ca_mem, ca_mem_len); 822d4afb5ceSopenharmony_ci 823d4afb5ceSopenharmony_ci if (cert_mem && cert_mem_len) 824d4afb5ceSopenharmony_ci EVP_DigestUpdate(mdctx, cert_mem, cert_mem_len); 825d4afb5ceSopenharmony_ci 826d4afb5ceSopenharmony_ci len = sizeof(hash); 827d4afb5ceSopenharmony_ci EVP_DigestFinal_ex(mdctx, hash, &len); 828d4afb5ceSopenharmony_ci EVP_MD_CTX_destroy(mdctx); 829d4afb5ceSopenharmony_ci 830d4afb5ceSopenharmony_ci /* look for existing client context with same config already */ 831d4afb5ceSopenharmony_ci 832d4afb5ceSopenharmony_ci lws_start_foreach_dll_safe(struct lws_dll2 *, p, tp, 833d4afb5ceSopenharmony_ci lws_dll2_get_head(&vh->context->tls.cc_owner)) { 834d4afb5ceSopenharmony_ci tcr = lws_container_of(p, struct lws_tls_client_reuse, cc_list); 835d4afb5ceSopenharmony_ci 836d4afb5ceSopenharmony_ci if (!memcmp(hash, tcr->hash, len)) { 837d4afb5ceSopenharmony_ci 838d4afb5ceSopenharmony_ci /* it's a match */ 839d4afb5ceSopenharmony_ci 840d4afb5ceSopenharmony_ci tcr->refcount++; 841d4afb5ceSopenharmony_ci vh->tls.ssl_client_ctx = tcr->ssl_client_ctx; 842d4afb5ceSopenharmony_ci vh->tls.tcr = tcr; 843d4afb5ceSopenharmony_ci 844d4afb5ceSopenharmony_ci lwsl_info("%s: vh %s: reusing client ctx %d: use %d\n", 845d4afb5ceSopenharmony_ci __func__, vh->name, tcr->index, 846d4afb5ceSopenharmony_ci tcr->refcount); 847d4afb5ceSopenharmony_ci 848d4afb5ceSopenharmony_ci return 0; 849d4afb5ceSopenharmony_ci } 850d4afb5ceSopenharmony_ci } lws_end_foreach_dll_safe(p, tp); 851d4afb5ceSopenharmony_ci 852d4afb5ceSopenharmony_ci /* no existing one the same... create new client SSL_CTX */ 853d4afb5ceSopenharmony_ci 854d4afb5ceSopenharmony_ci errno = 0; 855d4afb5ceSopenharmony_ci ERR_clear_error(); 856d4afb5ceSopenharmony_ci vh->tls.ssl_client_ctx = SSL_CTX_new(method); 857d4afb5ceSopenharmony_ci if (!vh->tls.ssl_client_ctx) { 858d4afb5ceSopenharmony_ci const char *es; 859d4afb5ceSopenharmony_ci 860d4afb5ceSopenharmony_ci error = ERR_get_error(); 861d4afb5ceSopenharmony_ci es = ERR_error_string( 862d4afb5ceSopenharmony_ci #if defined(LWS_WITH_BORINGSSL) 863d4afb5ceSopenharmony_ci (uint32_t) 864d4afb5ceSopenharmony_ci #else 865d4afb5ceSopenharmony_ci (unsigned long) 866d4afb5ceSopenharmony_ci #endif 867d4afb5ceSopenharmony_ci error, (char *)vh->context->pt[0].serv_buf); 868d4afb5ceSopenharmony_ci lwsl_err("problem creating ssl context %lu: %s\n", 869d4afb5ceSopenharmony_ci error, es); 870d4afb5ceSopenharmony_ci return 1; 871d4afb5ceSopenharmony_ci } 872d4afb5ceSopenharmony_ci 873d4afb5ceSopenharmony_ci SSL_CTX_set_ex_data(vh->tls.ssl_client_ctx, 874d4afb5ceSopenharmony_ci openssl_SSL_CTX_private_data_index, 875d4afb5ceSopenharmony_ci (char *)vh->context); 876d4afb5ceSopenharmony_ci 877d4afb5ceSopenharmony_ci lws_plat_vhost_tls_client_ctx_init(vh); 878d4afb5ceSopenharmony_ci 879d4afb5ceSopenharmony_ci tcr = lws_zalloc(sizeof(*tcr), "client ctx tcr"); 880d4afb5ceSopenharmony_ci if (!tcr) { 881d4afb5ceSopenharmony_ci SSL_CTX_free(vh->tls.ssl_client_ctx); 882d4afb5ceSopenharmony_ci return 1; 883d4afb5ceSopenharmony_ci } 884d4afb5ceSopenharmony_ci 885d4afb5ceSopenharmony_ci tcr->ssl_client_ctx = vh->tls.ssl_client_ctx; 886d4afb5ceSopenharmony_ci tcr->refcount = 1; 887d4afb5ceSopenharmony_ci memcpy(tcr->hash, hash, len); 888d4afb5ceSopenharmony_ci tcr->index = vh->context->tls.count_client_contexts++; 889d4afb5ceSopenharmony_ci lws_dll2_add_head(&tcr->cc_list, &vh->context->tls.cc_owner); 890d4afb5ceSopenharmony_ci 891d4afb5ceSopenharmony_ci lwsl_info("%s: vh %s: created new client ctx %d\n", __func__, 892d4afb5ceSopenharmony_ci vh->name, tcr->index); 893d4afb5ceSopenharmony_ci 894d4afb5ceSopenharmony_ci /* bind the tcr to the client context */ 895d4afb5ceSopenharmony_ci 896d4afb5ceSopenharmony_ci vh->tls.tcr = tcr; 897d4afb5ceSopenharmony_ci 898d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS) 899d4afb5ceSopenharmony_ci vh->tls_session_cache_max = info->tls_session_cache_max ? 900d4afb5ceSopenharmony_ci info->tls_session_cache_max : 10; 901d4afb5ceSopenharmony_ci lws_tls_session_cache(vh, info->tls_session_timeout); 902d4afb5ceSopenharmony_ci#endif 903d4afb5ceSopenharmony_ci 904d4afb5ceSopenharmony_ci#ifdef SSL_OP_NO_COMPRESSION 905d4afb5ceSopenharmony_ci SSL_CTX_set_options(vh->tls.ssl_client_ctx, SSL_OP_NO_COMPRESSION); 906d4afb5ceSopenharmony_ci#endif 907d4afb5ceSopenharmony_ci 908d4afb5ceSopenharmony_ci SSL_CTX_set_options(vh->tls.ssl_client_ctx, 909d4afb5ceSopenharmony_ci SSL_OP_CIPHER_SERVER_PREFERENCE); 910d4afb5ceSopenharmony_ci 911d4afb5ceSopenharmony_ci SSL_CTX_set_mode(vh->tls.ssl_client_ctx, 912d4afb5ceSopenharmony_ci SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | 913d4afb5ceSopenharmony_ci SSL_MODE_RELEASE_BUFFERS); 914d4afb5ceSopenharmony_ci 915d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 916d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 917d4afb5ceSopenharmony_ci uint32_t 918d4afb5ceSopenharmony_ci#else 919d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \ 920d4afb5ceSopenharmony_ci !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ 921d4afb5ceSopenharmony_ci unsigned long 922d4afb5ceSopenharmony_ci#else 923d4afb5ceSopenharmony_ci long 924d4afb5ceSopenharmony_ci#endif 925d4afb5ceSopenharmony_ci#endif 926d4afb5ceSopenharmony_ci#else 927d4afb5ceSopenharmony_ci long 928d4afb5ceSopenharmony_ci#endif 929d4afb5ceSopenharmony_ci ssl_client_options_set_value = 930d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 931d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 932d4afb5ceSopenharmony_ci (uint32_t) 933d4afb5ceSopenharmony_ci#else 934d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \ 935d4afb5ceSopenharmony_ci !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ 936d4afb5ceSopenharmony_ci (unsigned long) 937d4afb5ceSopenharmony_ci#else 938d4afb5ceSopenharmony_ci (long) 939d4afb5ceSopenharmony_ci#endif 940d4afb5ceSopenharmony_ci#endif 941d4afb5ceSopenharmony_ci#endif 942d4afb5ceSopenharmony_ci info->ssl_client_options_set; 943d4afb5ceSopenharmony_ci 944d4afb5ceSopenharmony_ci if (info->ssl_client_options_set) 945d4afb5ceSopenharmony_ci SSL_CTX_set_options(vh->tls.ssl_client_ctx, ssl_client_options_set_value); 946d4afb5ceSopenharmony_ci 947d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL) 948d4afb5ceSopenharmony_ci 949d4afb5ceSopenharmony_ci /* SSL_clear_options introduced in 0.9.8m */ 950d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 951d4afb5ceSopenharmony_ci uint32_t 952d4afb5ceSopenharmony_ci#else 953d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \ 954d4afb5ceSopenharmony_ci !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ 955d4afb5ceSopenharmony_ci unsigned long 956d4afb5ceSopenharmony_ci#else 957d4afb5ceSopenharmony_ci long 958d4afb5ceSopenharmony_ci#endif 959d4afb5ceSopenharmony_ci#endif 960d4afb5ceSopenharmony_ci 961d4afb5ceSopenharmony_ci ssl_client_options_clear_value = 962d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 963d4afb5ceSopenharmony_ci (uint32_t) 964d4afb5ceSopenharmony_ci#else 965d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && \ 966d4afb5ceSopenharmony_ci !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ 967d4afb5ceSopenharmony_ci (unsigned long) 968d4afb5ceSopenharmony_ci#else 969d4afb5ceSopenharmony_ci (long) 970d4afb5ceSopenharmony_ci#endif 971d4afb5ceSopenharmony_ci#endif 972d4afb5ceSopenharmony_ci info->ssl_client_options_clear; 973d4afb5ceSopenharmony_ci 974d4afb5ceSopenharmony_ci if (info->ssl_client_options_clear) 975d4afb5ceSopenharmony_ci SSL_CTX_clear_options(vh->tls.ssl_client_ctx, ssl_client_options_clear_value); 976d4afb5ceSopenharmony_ci#endif 977d4afb5ceSopenharmony_ci 978d4afb5ceSopenharmony_ci if (cipher_list) 979d4afb5ceSopenharmony_ci SSL_CTX_set_cipher_list(vh->tls.ssl_client_ctx, cipher_list); 980d4afb5ceSopenharmony_ci 981d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_set_ciphersuites) 982d4afb5ceSopenharmony_ci if (info->client_tls_1_3_plus_cipher_list) 983d4afb5ceSopenharmony_ci SSL_CTX_set_ciphersuites(vh->tls.ssl_client_ctx, 984d4afb5ceSopenharmony_ci info->client_tls_1_3_plus_cipher_list); 985d4afb5ceSopenharmony_ci#endif 986d4afb5ceSopenharmony_ci 987d4afb5ceSopenharmony_ci#ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS 988d4afb5ceSopenharmony_ci if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS)) 989d4afb5ceSopenharmony_ci /* loads OS default CA certs */ 990d4afb5ceSopenharmony_ci SSL_CTX_set_default_verify_paths(vh->tls.ssl_client_ctx); 991d4afb5ceSopenharmony_ci#endif 992d4afb5ceSopenharmony_ci 993d4afb5ceSopenharmony_ci /* openssl init for cert verification (for client sockets) */ 994d4afb5ceSopenharmony_ci if (!ca_mem || !ca_mem_len) { 995d4afb5ceSopenharmony_ci for (int i = 0; i < MAX_CLIENT_SSL_CA_NUMBER; i++) { 996d4afb5ceSopenharmony_ci if ((info->client_ssl_ca_dirs[i] != NULL) && 997d4afb5ceSopenharmony_ci (!SSL_CTX_load_verify_locations(vh->tls.ssl_client_ctx, NULL, info->client_ssl_ca_dirs[i]))) { 998d4afb5ceSopenharmony_ci lwsl_err( 999d4afb5ceSopenharmony_ci "Unable to load SSL Client certs from %s " 1000d4afb5ceSopenharmony_ci "(set by info->client_ssl_ca_dirs[%d]) -- " 1001d4afb5ceSopenharmony_ci "client ssl isn't going to work\n", 1002d4afb5ceSopenharmony_ci info->client_ssl_ca_dirs[i], i); 1003d4afb5ceSopenharmony_ci } 1004d4afb5ceSopenharmony_ci } 1005d4afb5ceSopenharmony_ci } 1006d4afb5ceSopenharmony_ci 1007d4afb5ceSopenharmony_ci if (!ca_filepath && (!ca_mem || !ca_mem_len)) { 1008d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_load_verify_dir) 1009d4afb5ceSopenharmony_ci if (!SSL_CTX_load_verify_dir( 1010d4afb5ceSopenharmony_ci vh->tls.ssl_client_ctx, LWS_OPENSSL_CLIENT_CERTS)) 1011d4afb5ceSopenharmony_ci#else 1012d4afb5ceSopenharmony_ci if (!SSL_CTX_load_verify_locations( 1013d4afb5ceSopenharmony_ci vh->tls.ssl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS)) 1014d4afb5ceSopenharmony_ci#endif 1015d4afb5ceSopenharmony_ci lwsl_err("Unable to load SSL Client certs from %s " 1016d4afb5ceSopenharmony_ci "(set by LWS_OPENSSL_CLIENT_CERTS) -- " 1017d4afb5ceSopenharmony_ci "client ssl isn't going to work\n", 1018d4afb5ceSopenharmony_ci LWS_OPENSSL_CLIENT_CERTS); 1019d4afb5ceSopenharmony_ci } else if (ca_filepath) { 1020d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_load_verify_file) 1021d4afb5ceSopenharmony_ci if (!SSL_CTX_load_verify_file( 1022d4afb5ceSopenharmony_ci vh->tls.ssl_client_ctx, ca_filepath)) { 1023d4afb5ceSopenharmony_ci#else 1024d4afb5ceSopenharmony_ci if (!SSL_CTX_load_verify_locations( 1025d4afb5ceSopenharmony_ci vh->tls.ssl_client_ctx, ca_filepath, NULL)) { 1026d4afb5ceSopenharmony_ci#endif 1027d4afb5ceSopenharmony_ci lwsl_err( 1028d4afb5ceSopenharmony_ci "Unable to load SSL Client certs " 1029d4afb5ceSopenharmony_ci "file from %s -- client ssl isn't " 1030d4afb5ceSopenharmony_ci "going to work\n", ca_filepath); 1031d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 1032d4afb5ceSopenharmony_ci } 1033d4afb5ceSopenharmony_ci else 1034d4afb5ceSopenharmony_ci lwsl_info("loaded ssl_ca_filepath\n"); 1035d4afb5ceSopenharmony_ci } else { 1036d4afb5ceSopenharmony_ci 1037d4afb5ceSopenharmony_ci lws_filepos_t amount = 0; 1038d4afb5ceSopenharmony_ci const uint8_t *up; 1039d4afb5ceSopenharmony_ci uint8_t *up1; 1040d4afb5ceSopenharmony_ci 1041d4afb5ceSopenharmony_ci if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, ca_mem, 1042d4afb5ceSopenharmony_ci ca_mem_len, &up1, &amount)) { 1043d4afb5ceSopenharmony_ci lwsl_err("%s: Unable to decode x.509 mem\n", __func__); 1044d4afb5ceSopenharmony_ci lwsl_hexdump_notice(ca_mem, ca_mem_len); 1045d4afb5ceSopenharmony_ci return 1; 1046d4afb5ceSopenharmony_ci } 1047d4afb5ceSopenharmony_ci 1048d4afb5ceSopenharmony_ci up = up1; 1049d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL) 1050d4afb5ceSopenharmony_ci client_CA = d2i_X509(NULL, &up, (int)amount); 1051d4afb5ceSopenharmony_ci#else 1052d4afb5ceSopenharmony_ci client_CA = d2i_X509(NULL, &up, (long)amount); 1053d4afb5ceSopenharmony_ci#endif 1054d4afb5ceSopenharmony_ci if (!client_CA) { 1055d4afb5ceSopenharmony_ci lwsl_err("%s: d2i_X509 failed\n", __func__); 1056d4afb5ceSopenharmony_ci lwsl_hexdump_notice(up1, (size_t)amount); 1057d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 1058d4afb5ceSopenharmony_ci } else { 1059d4afb5ceSopenharmony_ci x509_store = X509_STORE_new(); 1060d4afb5ceSopenharmony_ci if (!X509_STORE_add_cert(x509_store, client_CA)) { 1061d4afb5ceSopenharmony_ci X509_STORE_free(x509_store); 1062d4afb5ceSopenharmony_ci lwsl_err("Unable to load SSL Client certs from " 1063d4afb5ceSopenharmony_ci "ssl_ca_mem -- client ssl isn't going to " 1064d4afb5ceSopenharmony_ci "work\n"); 1065d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 1066d4afb5ceSopenharmony_ci } else { 1067d4afb5ceSopenharmony_ci /* it doesn't increment x509_store ref counter */ 1068d4afb5ceSopenharmony_ci SSL_CTX_set_cert_store(vh->tls.ssl_client_ctx, 1069d4afb5ceSopenharmony_ci x509_store); 1070d4afb5ceSopenharmony_ci lwsl_info("loaded ssl_ca_mem\n"); 1071d4afb5ceSopenharmony_ci } 1072d4afb5ceSopenharmony_ci } 1073d4afb5ceSopenharmony_ci if (client_CA) 1074d4afb5ceSopenharmony_ci X509_free(client_CA); 1075d4afb5ceSopenharmony_ci lws_free(up1); 1076d4afb5ceSopenharmony_ci // lws_tls_client_vhost_extra_cert_mem(vh, ca_mem, ca_mem_len); 1077d4afb5ceSopenharmony_ci } 1078d4afb5ceSopenharmony_ci 1079d4afb5ceSopenharmony_ci /* 1080d4afb5ceSopenharmony_ci * callback allowing user code to load extra verification certs 1081d4afb5ceSopenharmony_ci * helping the client to verify server identity 1082d4afb5ceSopenharmony_ci */ 1083d4afb5ceSopenharmony_ci 1084d4afb5ceSopenharmony_ci /* support for client-side certificate authentication */ 1085d4afb5ceSopenharmony_ci 1086d4afb5ceSopenharmony_ci if (cert_filepath) { 1087d4afb5ceSopenharmony_ci if (lws_tls_use_any_upgrade_check_extant(cert_filepath) != 1088d4afb5ceSopenharmony_ci LWS_TLS_EXTANT_YES && 1089d4afb5ceSopenharmony_ci (info->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) 1090d4afb5ceSopenharmony_ci return 0; 1091d4afb5ceSopenharmony_ci 1092d4afb5ceSopenharmony_ci lwsl_notice("%s: doing cert filepath %s\n", __func__, 1093d4afb5ceSopenharmony_ci cert_filepath); 1094d4afb5ceSopenharmony_ci n = SSL_CTX_use_certificate_chain_file(vh->tls.ssl_client_ctx, 1095d4afb5ceSopenharmony_ci cert_filepath); 1096d4afb5ceSopenharmony_ci if (n < 1) { 1097d4afb5ceSopenharmony_ci lwsl_err("problem %d getting cert '%s'\n", n, 1098d4afb5ceSopenharmony_ci cert_filepath); 1099d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 1100d4afb5ceSopenharmony_ci return 1; 1101d4afb5ceSopenharmony_ci } 1102d4afb5ceSopenharmony_ci lwsl_info("Loaded client cert %s\n", cert_filepath); 1103d4afb5ceSopenharmony_ci 1104d4afb5ceSopenharmony_ci } else if (cert_mem && cert_mem_len) { 1105d4afb5ceSopenharmony_ci lws_filepos_t flen; 1106d4afb5ceSopenharmony_ci uint8_t *p; 1107d4afb5ceSopenharmony_ci 1108d4afb5ceSopenharmony_ci if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, cert_mem, 1109d4afb5ceSopenharmony_ci cert_mem_len, &p, &flen)) { 1110d4afb5ceSopenharmony_ci lwsl_err("%s: couldn't read cert file\n", __func__); 1111d4afb5ceSopenharmony_ci 1112d4afb5ceSopenharmony_ci return 1; 1113d4afb5ceSopenharmony_ci } 1114d4afb5ceSopenharmony_ci 1115d4afb5ceSopenharmony_ci n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx, 1116d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 1117d4afb5ceSopenharmony_ci (size_t) 1118d4afb5ceSopenharmony_ci#else 1119d4afb5ceSopenharmony_ci (int) 1120d4afb5ceSopenharmony_ci#endif 1121d4afb5ceSopenharmony_ci flen, p); 1122d4afb5ceSopenharmony_ci 1123d4afb5ceSopenharmony_ci if (n < 1) { 1124d4afb5ceSopenharmony_ci lwsl_err("%s: problem interpreting client cert\n", __func__); 1125d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 1126d4afb5ceSopenharmony_ci } 1127d4afb5ceSopenharmony_ci 1128d4afb5ceSopenharmony_ci lws_free_set_NULL(p); 1129d4afb5ceSopenharmony_ci 1130d4afb5ceSopenharmony_ci if (n != 1) 1131d4afb5ceSopenharmony_ci return 1; 1132d4afb5ceSopenharmony_ci 1133d4afb5ceSopenharmony_ci } 1134d4afb5ceSopenharmony_ci if (private_key_filepath) { 1135d4afb5ceSopenharmony_ci lwsl_info("%s: using private key filepath\n", __func__); 1136d4afb5ceSopenharmony_ci lws_ssl_bind_passphrase(vh->tls.ssl_client_ctx, 1, info); 1137d4afb5ceSopenharmony_ci /* set the private key from KeyFile */ 1138d4afb5ceSopenharmony_ci if (SSL_CTX_use_PrivateKey_file(vh->tls.ssl_client_ctx, 1139d4afb5ceSopenharmony_ci private_key_filepath, SSL_FILETYPE_PEM) != 1) { 1140d4afb5ceSopenharmony_ci lwsl_err("use_PrivateKey_file '%s'\n", 1141d4afb5ceSopenharmony_ci private_key_filepath); 1142d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 1143d4afb5ceSopenharmony_ci return 1; 1144d4afb5ceSopenharmony_ci } 1145d4afb5ceSopenharmony_ci lwsl_info("Loaded client cert private key %s\n", 1146d4afb5ceSopenharmony_ci private_key_filepath); 1147d4afb5ceSopenharmony_ci 1148d4afb5ceSopenharmony_ci /* verify private key */ 1149d4afb5ceSopenharmony_ci if (!SSL_CTX_check_private_key(vh->tls.ssl_client_ctx)) { 1150d4afb5ceSopenharmony_ci lwsl_err("Private SSL key doesn't match cert\n"); 1151d4afb5ceSopenharmony_ci return 1; 1152d4afb5ceSopenharmony_ci } 1153d4afb5ceSopenharmony_ci } 1154d4afb5ceSopenharmony_ci else if (key_mem && key_mem_len) { 1155d4afb5ceSopenharmony_ci 1156d4afb5ceSopenharmony_ci lws_filepos_t flen; 1157d4afb5ceSopenharmony_ci uint8_t *p; 1158d4afb5ceSopenharmony_ci 1159d4afb5ceSopenharmony_ci if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, key_mem, 1160d4afb5ceSopenharmony_ci key_mem_len, &p, &flen)) { 1161d4afb5ceSopenharmony_ci lwsl_err("%s: couldn't use mem cert\n", __func__); 1162d4afb5ceSopenharmony_ci 1163d4afb5ceSopenharmony_ci return 1; 1164d4afb5ceSopenharmony_ci } 1165d4afb5ceSopenharmony_ci 1166d4afb5ceSopenharmony_ci n = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, vh->tls.ssl_client_ctx, p, 1167d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 1168d4afb5ceSopenharmony_ci (size_t) 1169d4afb5ceSopenharmony_ci#else 1170d4afb5ceSopenharmony_ci (long)(lws_intptr_t) 1171d4afb5ceSopenharmony_ci#endif 1172d4afb5ceSopenharmony_ci flen); 1173d4afb5ceSopenharmony_ci if (n != 1) 1174d4afb5ceSopenharmony_ci n = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC, 1175d4afb5ceSopenharmony_ci vh->tls.ssl_client_ctx, p, 1176d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 1177d4afb5ceSopenharmony_ci (size_t) 1178d4afb5ceSopenharmony_ci#else 1179d4afb5ceSopenharmony_ci (long)(lws_intptr_t) 1180d4afb5ceSopenharmony_ci#endif 1181d4afb5ceSopenharmony_ci flen); 1182d4afb5ceSopenharmony_ci 1183d4afb5ceSopenharmony_ci lws_free_set_NULL(p); 1184d4afb5ceSopenharmony_ci 1185d4afb5ceSopenharmony_ci if (n != 1) { 1186d4afb5ceSopenharmony_ci lwsl_err("%s: unable to use key_mem\n", __func__); 1187d4afb5ceSopenharmony_ci 1188d4afb5ceSopenharmony_ci return 1; 1189d4afb5ceSopenharmony_ci } 1190d4afb5ceSopenharmony_ci } 1191d4afb5ceSopenharmony_ci 1192d4afb5ceSopenharmony_ci return 0; 1193d4afb5ceSopenharmony_ci} 1194d4afb5ceSopenharmony_ci 1195d4afb5ceSopenharmony_ci 1196