1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 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 "private-lib-core.h" 26d4afb5ceSopenharmony_ci#include "private-lib-tls-mbedtls.h" 27d4afb5ceSopenharmony_ci 28d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST) 29d4afb5ceSopenharmony_ci 30d4afb5ceSopenharmony_ci/* 31d4afb5ceSopenharmony_ci * We get called for each peer certificate that was provided in turn. 32d4afb5ceSopenharmony_ci * 33d4afb5ceSopenharmony_ci * Our job is just to collect the AKID and SKIDs into ssl->kid_chain, and walk 34d4afb5ceSopenharmony_ci * later at verification result time if it failed. 35d4afb5ceSopenharmony_ci * 36d4afb5ceSopenharmony_ci * None of these should be trusted, even if a misconfigured server sends us 37d4afb5ceSopenharmony_ci * his root CA. 38d4afb5ceSopenharmony_ci */ 39d4afb5ceSopenharmony_ci 40d4afb5ceSopenharmony_cistatic int 41d4afb5ceSopenharmony_cilws_mbedtls_client_verify_callback(SSL *ssl, mbedtls_x509_crt *x509) 42d4afb5ceSopenharmony_ci{ 43d4afb5ceSopenharmony_ci union lws_tls_cert_info_results ci; 44d4afb5ceSopenharmony_ci 45d4afb5ceSopenharmony_ci /* we reached the max we can hold? */ 46d4afb5ceSopenharmony_ci 47d4afb5ceSopenharmony_ci if (ssl->kid_chain.count == LWS_ARRAY_SIZE(ssl->kid_chain.akid)) 48d4afb5ceSopenharmony_ci return 0; 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_ci /* if not, stash the SKID and AKID into the next kid slot */ 51d4afb5ceSopenharmony_ci 52d4afb5ceSopenharmony_ci if (!lws_tls_mbedtls_cert_info(x509, LWS_TLS_CERT_INFO_SUBJECT_KEY_ID, 53d4afb5ceSopenharmony_ci &ci, 0)) 54d4afb5ceSopenharmony_ci lws_tls_kid_copy(&ci, 55d4afb5ceSopenharmony_ci &ssl->kid_chain.skid[ssl->kid_chain.count]); 56d4afb5ceSopenharmony_ci 57d4afb5ceSopenharmony_ci if (!lws_tls_mbedtls_cert_info(x509, LWS_TLS_CERT_INFO_AUTHORITY_KEY_ID, 58d4afb5ceSopenharmony_ci &ci, 0)) 59d4afb5ceSopenharmony_ci lws_tls_kid_copy(&ci, 60d4afb5ceSopenharmony_ci &ssl->kid_chain.akid[ssl->kid_chain.count]); 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_ci ssl->kid_chain.count++; 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_ci // lwsl_notice("%s: %u\n", __func__, ssl->kid_chain.count); 65d4afb5ceSopenharmony_ci 66d4afb5ceSopenharmony_ci return 0; 67d4afb5ceSopenharmony_ci} 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci#endif 70d4afb5ceSopenharmony_ci 71d4afb5ceSopenharmony_ciint 72d4afb5ceSopenharmony_cilws_ssl_client_bio_create(struct lws *wsi) 73d4afb5ceSopenharmony_ci{ 74d4afb5ceSopenharmony_ci char hostname[128], *p; 75d4afb5ceSopenharmony_ci const char *alpn_comma = wsi->a.context->tls.alpn_default; 76d4afb5ceSopenharmony_ci struct alpn_ctx protos; 77d4afb5ceSopenharmony_ci int fl = SSL_VERIFY_PEER; 78d4afb5ceSopenharmony_ci 79d4afb5ceSopenharmony_ci if (wsi->stash) 80d4afb5ceSopenharmony_ci lws_strncpy(hostname, wsi->stash->cis[CIS_HOST], sizeof(hostname)); 81d4afb5ceSopenharmony_ci else 82d4afb5ceSopenharmony_ci if (lws_hdr_copy(wsi, hostname, sizeof(hostname), 83d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_HOST) <= 0) { 84d4afb5ceSopenharmony_ci lwsl_err("%s: Unable to get hostname\n", __func__); 85d4afb5ceSopenharmony_ci 86d4afb5ceSopenharmony_ci return -1; 87d4afb5ceSopenharmony_ci } 88d4afb5ceSopenharmony_ci 89d4afb5ceSopenharmony_ci /* 90d4afb5ceSopenharmony_ci * remove any :port part on the hostname... necessary for network 91d4afb5ceSopenharmony_ci * connection but typical certificates do not contain it 92d4afb5ceSopenharmony_ci */ 93d4afb5ceSopenharmony_ci p = hostname; 94d4afb5ceSopenharmony_ci while (*p) { 95d4afb5ceSopenharmony_ci if (*p == ':') { 96d4afb5ceSopenharmony_ci *p = '\0'; 97d4afb5ceSopenharmony_ci break; 98d4afb5ceSopenharmony_ci } 99d4afb5ceSopenharmony_ci p++; 100d4afb5ceSopenharmony_ci } 101d4afb5ceSopenharmony_ci 102d4afb5ceSopenharmony_ci wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_client_ctx); 103d4afb5ceSopenharmony_ci if (!wsi->tls.ssl) { 104d4afb5ceSopenharmony_ci lwsl_info("%s: SSL_new() failed\n", __func__); 105d4afb5ceSopenharmony_ci return -1; 106d4afb5ceSopenharmony_ci } 107d4afb5ceSopenharmony_ci 108d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS) 109d4afb5ceSopenharmony_ci if (!(wsi->a.vhost->options & LWS_SERVER_OPTION_DISABLE_TLS_SESSION_CACHE)) 110d4afb5ceSopenharmony_ci lws_tls_reuse_session(wsi); 111d4afb5ceSopenharmony_ci#endif 112d4afb5ceSopenharmony_ci 113d4afb5ceSopenharmony_ci if (wsi->a.vhost->tls.ssl_info_event_mask) 114d4afb5ceSopenharmony_ci SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback); 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci if (!(wsi->tls.use_ssl & LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK)) { 117d4afb5ceSopenharmony_ci X509_VERIFY_PARAM *param = SSL_get0_param(wsi->tls.ssl); 118d4afb5ceSopenharmony_ci /* Enable automatic hostname checks */ 119d4afb5ceSopenharmony_ci // X509_VERIFY_PARAM_set_hostflags(param, 120d4afb5ceSopenharmony_ci // X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); 121d4afb5ceSopenharmony_ci lwsl_info("%s: setting hostname %s\n", __func__, hostname); 122d4afb5ceSopenharmony_ci if (X509_VERIFY_PARAM_set1_host(param, hostname, 0) != 1) 123d4afb5ceSopenharmony_ci return -1; 124d4afb5ceSopenharmony_ci } 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_ci if (wsi->a.vhost->tls.alpn) 127d4afb5ceSopenharmony_ci alpn_comma = wsi->a.vhost->tls.alpn; 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_ci if (wsi->stash) { 130d4afb5ceSopenharmony_ci lws_strncpy(hostname, wsi->stash->cis[CIS_HOST], 131d4afb5ceSopenharmony_ci sizeof(hostname)); 132d4afb5ceSopenharmony_ci if (wsi->stash->cis[CIS_ALPN]) 133d4afb5ceSopenharmony_ci alpn_comma = wsi->stash->cis[CIS_ALPN]; 134d4afb5ceSopenharmony_ci } else { 135d4afb5ceSopenharmony_ci if (lws_hdr_copy(wsi, hostname, sizeof(hostname), 136d4afb5ceSopenharmony_ci _WSI_TOKEN_CLIENT_ALPN) > 0) 137d4afb5ceSopenharmony_ci alpn_comma = hostname; 138d4afb5ceSopenharmony_ci } 139d4afb5ceSopenharmony_ci 140d4afb5ceSopenharmony_ci protos.len = (uint8_t)lws_alpn_comma_to_openssl(alpn_comma, protos.data, 141d4afb5ceSopenharmony_ci sizeof(protos.data) - 1); 142d4afb5ceSopenharmony_ci 143d4afb5ceSopenharmony_ci lwsl_info("%s: %s: client conn sending ALPN list '%s' (protos.len %d)\n", 144d4afb5ceSopenharmony_ci __func__, lws_wsi_tag(wsi), alpn_comma, protos.len); 145d4afb5ceSopenharmony_ci 146d4afb5ceSopenharmony_ci /* with mbedtls, protos is not pointed to after exit from this call */ 147d4afb5ceSopenharmony_ci SSL_set_alpn_select_cb(wsi->tls.ssl, &protos); 148d4afb5ceSopenharmony_ci 149d4afb5ceSopenharmony_ci if (wsi->flags & LCCSCF_ALLOW_SELFSIGNED) { 150d4afb5ceSopenharmony_ci lwsl_notice("%s: allowing selfsigned\n", __func__); 151d4afb5ceSopenharmony_ci fl = SSL_VERIFY_FAIL_IF_NO_PEER_CERT; 152d4afb5ceSopenharmony_ci } 153d4afb5ceSopenharmony_ci 154d4afb5ceSopenharmony_ci if (wsi->flags & LCCSCF_ALLOW_INSECURE) 155d4afb5ceSopenharmony_ci fl = SSL_VERIFY_NONE; 156d4afb5ceSopenharmony_ci 157d4afb5ceSopenharmony_ci /* 158d4afb5ceSopenharmony_ci * use server name indication (SNI), if supported, 159d4afb5ceSopenharmony_ci * when establishing connection 160d4afb5ceSopenharmony_ci */ 161d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST) 162d4afb5ceSopenharmony_ci SSL_set_verify(wsi->tls.ssl, SSL_VERIFY_PEER, 163d4afb5ceSopenharmony_ci lws_mbedtls_client_verify_callback); 164d4afb5ceSopenharmony_ci (void)fl; 165d4afb5ceSopenharmony_ci#else 166d4afb5ceSopenharmony_ci SSL_set_verify(wsi->tls.ssl, fl, NULL); 167d4afb5ceSopenharmony_ci#endif 168d4afb5ceSopenharmony_ci 169d4afb5ceSopenharmony_ci SSL_set_fd(wsi->tls.ssl, (int)wsi->desc.sockfd); 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_ci if (wsi->sys_tls_client_cert) { 172d4afb5ceSopenharmony_ci lws_system_blob_t *b = lws_system_get_blob(wsi->a.context, 173d4afb5ceSopenharmony_ci LWS_SYSBLOB_TYPE_CLIENT_CERT_DER, 174d4afb5ceSopenharmony_ci wsi->sys_tls_client_cert - 1); 175d4afb5ceSopenharmony_ci const uint8_t *pem_data = NULL; 176d4afb5ceSopenharmony_ci uint8_t *data = NULL; 177d4afb5ceSopenharmony_ci lws_filepos_t flen; 178d4afb5ceSopenharmony_ci size_t size; 179d4afb5ceSopenharmony_ci int err = 0; 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci if (!b) 182d4afb5ceSopenharmony_ci goto no_client_cert; 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci /* 185d4afb5ceSopenharmony_ci * Set up the per-connection client cert 186d4afb5ceSopenharmony_ci */ 187d4afb5ceSopenharmony_ci 188d4afb5ceSopenharmony_ci size = lws_system_blob_get_size(b); 189d4afb5ceSopenharmony_ci if (!size) 190d4afb5ceSopenharmony_ci goto no_client_cert; 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_ci if (lws_system_blob_get_single_ptr(b, &pem_data)) 193d4afb5ceSopenharmony_ci goto no_client_cert; 194d4afb5ceSopenharmony_ci 195d4afb5ceSopenharmony_ci if (lws_tls_alloc_pem_to_der_file(wsi->a.context, NULL, 196d4afb5ceSopenharmony_ci (const char *)pem_data, size, 197d4afb5ceSopenharmony_ci &data, &flen)) 198d4afb5ceSopenharmony_ci goto no_client_cert; 199d4afb5ceSopenharmony_ci size = (size_t) flen; 200d4afb5ceSopenharmony_ci 201d4afb5ceSopenharmony_ci err = SSL_use_certificate_ASN1(wsi->tls.ssl, data, (int)size); 202d4afb5ceSopenharmony_ci lws_free_set_NULL(data); 203d4afb5ceSopenharmony_ci if (err != 1) 204d4afb5ceSopenharmony_ci goto no_client_cert; 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci b = lws_system_get_blob(wsi->a.context, 207d4afb5ceSopenharmony_ci LWS_SYSBLOB_TYPE_CLIENT_KEY_DER, 208d4afb5ceSopenharmony_ci wsi->sys_tls_client_cert - 1); 209d4afb5ceSopenharmony_ci if (!b) 210d4afb5ceSopenharmony_ci goto no_client_cert; 211d4afb5ceSopenharmony_ci size = lws_system_blob_get_size(b); 212d4afb5ceSopenharmony_ci if (!size) 213d4afb5ceSopenharmony_ci goto no_client_cert; 214d4afb5ceSopenharmony_ci 215d4afb5ceSopenharmony_ci if (lws_system_blob_get_single_ptr(b, &pem_data)) 216d4afb5ceSopenharmony_ci goto no_client_cert; 217d4afb5ceSopenharmony_ci 218d4afb5ceSopenharmony_ci if (lws_tls_alloc_pem_to_der_file(wsi->a.context, NULL, 219d4afb5ceSopenharmony_ci (const char *)pem_data, size, 220d4afb5ceSopenharmony_ci &data, &flen)) 221d4afb5ceSopenharmony_ci goto no_client_cert; 222d4afb5ceSopenharmony_ci size = (size_t) flen; 223d4afb5ceSopenharmony_ci 224d4afb5ceSopenharmony_ci err = SSL_use_PrivateKey_ASN1(0, wsi->tls.ssl, data, (int)size); 225d4afb5ceSopenharmony_ci lws_free_set_NULL(data); 226d4afb5ceSopenharmony_ci if (err != 1) 227d4afb5ceSopenharmony_ci goto no_client_cert; 228d4afb5ceSopenharmony_ci 229d4afb5ceSopenharmony_ci /* no wrapper api for check key */ 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci lwsl_notice("%s: set system client cert %u\n", __func__, 232d4afb5ceSopenharmony_ci wsi->sys_tls_client_cert - 1); 233d4afb5ceSopenharmony_ci } 234d4afb5ceSopenharmony_ci 235d4afb5ceSopenharmony_ci return 0; 236d4afb5ceSopenharmony_ci 237d4afb5ceSopenharmony_cino_client_cert: 238d4afb5ceSopenharmony_ci lwsl_err("%s: unable to set up system client cert %d\n", __func__, 239d4afb5ceSopenharmony_ci wsi->sys_tls_client_cert - 1); 240d4afb5ceSopenharmony_ci 241d4afb5ceSopenharmony_ci return 1; 242d4afb5ceSopenharmony_ci} 243d4afb5ceSopenharmony_ci 244d4afb5ceSopenharmony_ciint ERR_get_error(void) 245d4afb5ceSopenharmony_ci{ 246d4afb5ceSopenharmony_ci return 0; 247d4afb5ceSopenharmony_ci} 248d4afb5ceSopenharmony_ci 249d4afb5ceSopenharmony_cienum lws_ssl_capable_status 250d4afb5ceSopenharmony_cilws_tls_client_connect(struct lws *wsi, char *errbuf, size_t elen) 251d4afb5ceSopenharmony_ci{ 252d4afb5ceSopenharmony_ci int m, n = SSL_connect(wsi->tls.ssl), en; 253d4afb5ceSopenharmony_ci 254d4afb5ceSopenharmony_ci if (n == 1) { 255d4afb5ceSopenharmony_ci lws_tls_server_conn_alpn(wsi); 256d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS) 257d4afb5ceSopenharmony_ci lws_tls_session_new_mbedtls(wsi); 258d4afb5ceSopenharmony_ci#endif 259d4afb5ceSopenharmony_ci lwsl_info("%s: client connect OK\n", __func__); 260d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_DONE; 261d4afb5ceSopenharmony_ci } 262d4afb5ceSopenharmony_ci 263d4afb5ceSopenharmony_ci en = (int)LWS_ERRNO; 264d4afb5ceSopenharmony_ci m = SSL_get_error(wsi->tls.ssl, n); 265d4afb5ceSopenharmony_ci 266d4afb5ceSopenharmony_ci if (m == SSL_ERROR_WANT_READ || SSL_want_read(wsi->tls.ssl)) 267d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_MORE_SERVICE_READ; 268d4afb5ceSopenharmony_ci 269d4afb5ceSopenharmony_ci if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) 270d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE; 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_ci if (!n) /* we don't know what he wants, but he says to retry */ 273d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_MORE_SERVICE; 274d4afb5ceSopenharmony_ci 275d4afb5ceSopenharmony_ci if (m == SSL_ERROR_SYSCALL && !en && n >= 0) /* otherwise we miss explicit failures and spin 276d4afb5ceSopenharmony_ci * in hs state 17 until timeout... */ 277d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_MORE_SERVICE; 278d4afb5ceSopenharmony_ci 279d4afb5ceSopenharmony_ci lws_snprintf(errbuf, elen, "mbedtls connect %d %d %d", n, m, en); 280d4afb5ceSopenharmony_ci 281d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_ERROR; 282d4afb5ceSopenharmony_ci} 283d4afb5ceSopenharmony_ci 284d4afb5ceSopenharmony_ciint 285d4afb5ceSopenharmony_cilws_tls_client_confirm_peer_cert(struct lws *wsi, char *ebuf, size_t ebuf_len) 286d4afb5ceSopenharmony_ci{ 287d4afb5ceSopenharmony_ci int n; 288d4afb5ceSopenharmony_ci unsigned int avoid = 0; 289d4afb5ceSopenharmony_ci X509 *peer = SSL_get_peer_certificate(wsi->tls.ssl); 290d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 291d4afb5ceSopenharmony_ci const char *type = ""; 292d4afb5ceSopenharmony_ci char *sb = (char *)&pt->serv_buf[0]; 293d4afb5ceSopenharmony_ci 294d4afb5ceSopenharmony_ci if (!peer) { 295d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS) 296d4afb5ceSopenharmony_ci lws_metrics_hist_bump_describe_wsi(wsi, lws_metrics_priv_to_pub( 297d4afb5ceSopenharmony_ci wsi->a.context->mth_conn_failures), 298d4afb5ceSopenharmony_ci "tls=\"nocert\""); 299d4afb5ceSopenharmony_ci#endif 300d4afb5ceSopenharmony_ci lwsl_info("peer did not provide cert\n"); 301d4afb5ceSopenharmony_ci lws_snprintf(ebuf, ebuf_len, "no peer cert"); 302d4afb5ceSopenharmony_ci 303d4afb5ceSopenharmony_ci return -1; 304d4afb5ceSopenharmony_ci } 305d4afb5ceSopenharmony_ci 306d4afb5ceSopenharmony_ci n = (int)SSL_get_verify_result(wsi->tls.ssl); 307d4afb5ceSopenharmony_ci lwsl_debug("get_verify says %d\n", n); 308d4afb5ceSopenharmony_ci 309d4afb5ceSopenharmony_ci switch (n) { 310d4afb5ceSopenharmony_ci case X509_V_OK: 311d4afb5ceSopenharmony_ci return 0; 312d4afb5ceSopenharmony_ci 313d4afb5ceSopenharmony_ci case X509_V_ERR_HOSTNAME_MISMATCH: 314d4afb5ceSopenharmony_ci type = "hostname"; 315d4afb5ceSopenharmony_ci avoid = LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK; 316d4afb5ceSopenharmony_ci break; 317d4afb5ceSopenharmony_ci 318d4afb5ceSopenharmony_ci case X509_V_ERR_INVALID_CA: 319d4afb5ceSopenharmony_ci type = "invalidca"; 320d4afb5ceSopenharmony_ci avoid = LCCSCF_ALLOW_SELFSIGNED; 321d4afb5ceSopenharmony_ci break; 322d4afb5ceSopenharmony_ci 323d4afb5ceSopenharmony_ci case X509_V_ERR_CERT_NOT_YET_VALID: 324d4afb5ceSopenharmony_ci type = "notyetvalid"; 325d4afb5ceSopenharmony_ci avoid = LCCSCF_ALLOW_EXPIRED; 326d4afb5ceSopenharmony_ci break; 327d4afb5ceSopenharmony_ci 328d4afb5ceSopenharmony_ci case X509_V_ERR_CERT_HAS_EXPIRED: 329d4afb5ceSopenharmony_ci type = "expired"; 330d4afb5ceSopenharmony_ci avoid = LCCSCF_ALLOW_EXPIRED; 331d4afb5ceSopenharmony_ci break; 332d4afb5ceSopenharmony_ci } 333d4afb5ceSopenharmony_ci 334d4afb5ceSopenharmony_ci lwsl_info("%s: cert problem: %s\n", __func__, type); 335d4afb5ceSopenharmony_ci#if defined(LWS_WITH_SYS_METRICS) 336d4afb5ceSopenharmony_ci { 337d4afb5ceSopenharmony_ci char buckname[64]; 338d4afb5ceSopenharmony_ci lws_snprintf(buckname, sizeof(buckname), "tls=\"%s\"", type); 339d4afb5ceSopenharmony_ci lws_metrics_hist_bump_describe_wsi(wsi, 340d4afb5ceSopenharmony_ci lws_metrics_priv_to_pub(wsi->a.context->mth_conn_failures), 341d4afb5ceSopenharmony_ci buckname); 342d4afb5ceSopenharmony_ci } 343d4afb5ceSopenharmony_ci#endif 344d4afb5ceSopenharmony_ci if (wsi->tls.use_ssl & avoid) { 345d4afb5ceSopenharmony_ci lwsl_info("%s: allowing anyway\n", __func__); 346d4afb5ceSopenharmony_ci 347d4afb5ceSopenharmony_ci return 0; 348d4afb5ceSopenharmony_ci } 349d4afb5ceSopenharmony_ci 350d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_JIT_TRUST) 351d4afb5ceSopenharmony_ci if (n == X509_V_ERR_INVALID_CA) 352d4afb5ceSopenharmony_ci lws_tls_jit_trust_sort_kids(wsi, &wsi->tls.ssl->kid_chain); 353d4afb5ceSopenharmony_ci#endif 354d4afb5ceSopenharmony_ci lws_snprintf(ebuf, ebuf_len, 355d4afb5ceSopenharmony_ci "server's cert didn't look good, %s (use_ssl 0x%x) X509_V_ERR = %d: %s\n", 356d4afb5ceSopenharmony_ci type, (unsigned int)wsi->tls.use_ssl, n, 357d4afb5ceSopenharmony_ci ERR_error_string((unsigned long)n, sb)); 358d4afb5ceSopenharmony_ci 359d4afb5ceSopenharmony_ci lwsl_info("%s\n", ebuf); 360d4afb5ceSopenharmony_ci 361d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 362d4afb5ceSopenharmony_ci 363d4afb5ceSopenharmony_ci return -1; 364d4afb5ceSopenharmony_ci} 365d4afb5ceSopenharmony_ci 366d4afb5ceSopenharmony_ciint 367d4afb5ceSopenharmony_cilws_tls_client_create_vhost_context(struct lws_vhost *vh, 368d4afb5ceSopenharmony_ci const struct lws_context_creation_info *info, 369d4afb5ceSopenharmony_ci const char *cipher_list, 370d4afb5ceSopenharmony_ci const char *ca_filepath, 371d4afb5ceSopenharmony_ci const void *ca_mem, 372d4afb5ceSopenharmony_ci unsigned int ca_mem_len, 373d4afb5ceSopenharmony_ci const char *cert_filepath, 374d4afb5ceSopenharmony_ci const void *cert_mem, 375d4afb5ceSopenharmony_ci unsigned int cert_mem_len, 376d4afb5ceSopenharmony_ci const char *private_key_filepath, 377d4afb5ceSopenharmony_ci const void *key_mem, 378d4afb5ceSopenharmony_ci unsigned int key_mem_len 379d4afb5ceSopenharmony_ci ) 380d4afb5ceSopenharmony_ci{ 381d4afb5ceSopenharmony_ci X509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len); 382d4afb5ceSopenharmony_ci SSL_METHOD *method = (SSL_METHOD *)TLS_client_method(); 383d4afb5ceSopenharmony_ci unsigned long error; 384d4afb5ceSopenharmony_ci int n; 385d4afb5ceSopenharmony_ci 386d4afb5ceSopenharmony_ci#if defined(LWS_WITH_TLS_SESSIONS) 387d4afb5ceSopenharmony_ci vh->tls_session_cache_max = info->tls_session_cache_max ? 388d4afb5ceSopenharmony_ci info->tls_session_cache_max : 10; 389d4afb5ceSopenharmony_ci lws_tls_session_cache(vh, info->tls_session_timeout); 390d4afb5ceSopenharmony_ci#endif 391d4afb5ceSopenharmony_ci 392d4afb5ceSopenharmony_ci if (!method) { 393d4afb5ceSopenharmony_ci error = (unsigned long)ERR_get_error(); 394d4afb5ceSopenharmony_ci lwsl_err("problem creating ssl method %lu: %s\n", 395d4afb5ceSopenharmony_ci error, ERR_error_string(error, 396d4afb5ceSopenharmony_ci (char *)vh->context->pt[0].serv_buf)); 397d4afb5ceSopenharmony_ci return 1; 398d4afb5ceSopenharmony_ci } 399d4afb5ceSopenharmony_ci /* create context */ 400d4afb5ceSopenharmony_ci vh->tls.ssl_client_ctx = SSL_CTX_new(method, &vh->context->mcdc); 401d4afb5ceSopenharmony_ci if (!vh->tls.ssl_client_ctx) { 402d4afb5ceSopenharmony_ci error = (unsigned long)ERR_get_error(); 403d4afb5ceSopenharmony_ci lwsl_err("problem creating ssl context %lu: %s\n", 404d4afb5ceSopenharmony_ci error, ERR_error_string(error, 405d4afb5ceSopenharmony_ci (char *)vh->context->pt[0].serv_buf)); 406d4afb5ceSopenharmony_ci return 1; 407d4afb5ceSopenharmony_ci } 408d4afb5ceSopenharmony_ci 409d4afb5ceSopenharmony_ci if (!ca_filepath && (!ca_mem || !ca_mem_len)) 410d4afb5ceSopenharmony_ci return 0; 411d4afb5ceSopenharmony_ci 412d4afb5ceSopenharmony_ci if (ca_filepath) { 413d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) 414d4afb5ceSopenharmony_ci uint8_t *buf; 415d4afb5ceSopenharmony_ci lws_filepos_t len; 416d4afb5ceSopenharmony_ci 417d4afb5ceSopenharmony_ci if (alloc_file(vh->context, ca_filepath, &buf, &len)) { 418d4afb5ceSopenharmony_ci lwsl_err("Load CA cert file %s failed\n", ca_filepath); 419d4afb5ceSopenharmony_ci return 1; 420d4afb5ceSopenharmony_ci } 421d4afb5ceSopenharmony_ci vh->tls.x509_client_CA = d2i_X509(NULL, buf, (long)len); 422d4afb5ceSopenharmony_ci free(buf); 423d4afb5ceSopenharmony_ci 424d4afb5ceSopenharmony_ci lwsl_info("Loading vh %s client CA for verification %s\n", vh->name, ca_filepath); 425d4afb5ceSopenharmony_ci#endif 426d4afb5ceSopenharmony_ci } else { 427d4afb5ceSopenharmony_ci vh->tls.x509_client_CA = d2i_X509(NULL, (uint8_t*)ca_mem, (long)ca_mem_len); 428d4afb5ceSopenharmony_ci lwsl_info("%s: using mem client CA cert %d\n", 429d4afb5ceSopenharmony_ci __func__, ca_mem_len); 430d4afb5ceSopenharmony_ci } 431d4afb5ceSopenharmony_ci 432d4afb5ceSopenharmony_ci if (!vh->tls.x509_client_CA) { 433d4afb5ceSopenharmony_ci lwsl_err("client CA: x509 parse failed\n"); 434d4afb5ceSopenharmony_ci return 1; 435d4afb5ceSopenharmony_ci } 436d4afb5ceSopenharmony_ci 437d4afb5ceSopenharmony_ci if (!vh->tls.ssl_ctx) 438d4afb5ceSopenharmony_ci SSL_CTX_add_client_CA(vh->tls.ssl_client_ctx, vh->tls.x509_client_CA); 439d4afb5ceSopenharmony_ci else 440d4afb5ceSopenharmony_ci SSL_CTX_add_client_CA(vh->tls.ssl_ctx, vh->tls.x509_client_CA); 441d4afb5ceSopenharmony_ci 442d4afb5ceSopenharmony_ci /* support for client-side certificate authentication */ 443d4afb5ceSopenharmony_ci if (cert_filepath) { 444d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) 445d4afb5ceSopenharmony_ci uint8_t *buf; 446d4afb5ceSopenharmony_ci lws_filepos_t amount; 447d4afb5ceSopenharmony_ci 448d4afb5ceSopenharmony_ci if (lws_tls_use_any_upgrade_check_extant(cert_filepath) != 449d4afb5ceSopenharmony_ci LWS_TLS_EXTANT_YES && 450d4afb5ceSopenharmony_ci (info->options & LWS_SERVER_OPTION_IGNORE_MISSING_CERT)) 451d4afb5ceSopenharmony_ci return 0; 452d4afb5ceSopenharmony_ci 453d4afb5ceSopenharmony_ci lwsl_notice("%s: doing cert filepath %s\n", __func__, 454d4afb5ceSopenharmony_ci cert_filepath); 455d4afb5ceSopenharmony_ci 456d4afb5ceSopenharmony_ci if (alloc_file(vh->context, cert_filepath, &buf, &amount)) 457d4afb5ceSopenharmony_ci return 1; 458d4afb5ceSopenharmony_ci 459d4afb5ceSopenharmony_ci buf[amount++] = '\0'; 460d4afb5ceSopenharmony_ci 461d4afb5ceSopenharmony_ci n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx, 462d4afb5ceSopenharmony_ci (int)amount, buf); 463d4afb5ceSopenharmony_ci lws_free(buf); 464d4afb5ceSopenharmony_ci if (n < 1) { 465d4afb5ceSopenharmony_ci lwsl_err("problem %d getting cert '%s'\n", n, 466d4afb5ceSopenharmony_ci cert_filepath); 467d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 468d4afb5ceSopenharmony_ci return 1; 469d4afb5ceSopenharmony_ci } 470d4afb5ceSopenharmony_ci 471d4afb5ceSopenharmony_ci lwsl_info("Loaded client cert %s\n", cert_filepath); 472d4afb5ceSopenharmony_ci#endif 473d4afb5ceSopenharmony_ci } else if (cert_mem && cert_mem_len) { 474d4afb5ceSopenharmony_ci /* lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); */ 475d4afb5ceSopenharmony_ci n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx, 476d4afb5ceSopenharmony_ci (int)cert_mem_len, cert_mem); 477d4afb5ceSopenharmony_ci if (n < 1) { 478d4afb5ceSopenharmony_ci lwsl_err("%s: (mbedtls) problem interpreting client cert\n", 479d4afb5ceSopenharmony_ci __func__); 480d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 481d4afb5ceSopenharmony_ci return 1; 482d4afb5ceSopenharmony_ci } 483d4afb5ceSopenharmony_ci lwsl_info("%s: using mem client cert %d\n", 484d4afb5ceSopenharmony_ci __func__, cert_mem_len); 485d4afb5ceSopenharmony_ci } 486d4afb5ceSopenharmony_ci 487d4afb5ceSopenharmony_ci if (private_key_filepath) { 488d4afb5ceSopenharmony_ci#if !defined(LWS_PLAT_OPTEE) 489d4afb5ceSopenharmony_ci 490d4afb5ceSopenharmony_ci uint8_t *buf; 491d4afb5ceSopenharmony_ci lws_filepos_t amount; 492d4afb5ceSopenharmony_ci 493d4afb5ceSopenharmony_ci lwsl_notice("%s: doing private key filepath %s\n", __func__, 494d4afb5ceSopenharmony_ci private_key_filepath); 495d4afb5ceSopenharmony_ci if (alloc_file(vh->context, private_key_filepath, &buf, &amount)) 496d4afb5ceSopenharmony_ci return 1; 497d4afb5ceSopenharmony_ci 498d4afb5ceSopenharmony_ci buf[amount++] = '\0'; 499d4afb5ceSopenharmony_ci 500d4afb5ceSopenharmony_ci n = SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx, 501d4afb5ceSopenharmony_ci buf, (long)amount); 502d4afb5ceSopenharmony_ci 503d4afb5ceSopenharmony_ci lws_free(buf); 504d4afb5ceSopenharmony_ci if (n < 1) { 505d4afb5ceSopenharmony_ci lwsl_err("problem %d getting private key '%s'\n", n, 506d4afb5ceSopenharmony_ci private_key_filepath); 507d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 508d4afb5ceSopenharmony_ci return 1; 509d4afb5ceSopenharmony_ci } 510d4afb5ceSopenharmony_ci 511d4afb5ceSopenharmony_ci lwsl_notice("Loaded private key %s\n", private_key_filepath); 512d4afb5ceSopenharmony_ci#endif 513d4afb5ceSopenharmony_ci } else if (key_mem && key_mem_len) { 514d4afb5ceSopenharmony_ci /* lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); */ 515d4afb5ceSopenharmony_ci n = SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx, 516d4afb5ceSopenharmony_ci key_mem, (long)key_mem_len - 1); 517d4afb5ceSopenharmony_ci 518d4afb5ceSopenharmony_ci if (n < 1) { 519d4afb5ceSopenharmony_ci lwsl_err("%s: (mbedtls) problem interpreting private key\n", 520d4afb5ceSopenharmony_ci __func__); 521d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 522d4afb5ceSopenharmony_ci return 1; 523d4afb5ceSopenharmony_ci } 524d4afb5ceSopenharmony_ci lwsl_info("%s: using mem private key %d\n", 525d4afb5ceSopenharmony_ci __func__, key_mem_len); 526d4afb5ceSopenharmony_ci 527d4afb5ceSopenharmony_ci } 528d4afb5ceSopenharmony_ci return 0; 529d4afb5ceSopenharmony_ci} 530d4afb5ceSopenharmony_ci 531d4afb5ceSopenharmony_ciint 532d4afb5ceSopenharmony_cilws_tls_client_vhost_extra_cert_mem(struct lws_vhost *vh, 533d4afb5ceSopenharmony_ci const uint8_t *der, size_t der_len) 534d4afb5ceSopenharmony_ci{ 535d4afb5ceSopenharmony_ci if (SSL_CTX_add_client_CA_ASN1(vh->tls.ssl_client_ctx, (int)der_len, der) != 1) { 536d4afb5ceSopenharmony_ci lwsl_err("%s: failed\n", __func__); 537d4afb5ceSopenharmony_ci return 1; 538d4afb5ceSopenharmony_ci } 539d4afb5ceSopenharmony_ci 540d4afb5ceSopenharmony_ci return 0; 541d4afb5ceSopenharmony_ci} 542d4afb5ceSopenharmony_ci 543