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 "private-lib-core.h" 26d4afb5ceSopenharmony_ci 27d4afb5ceSopenharmony_ci/* 28d4afb5ceSopenharmony_ci * Care: many openssl apis return 1 for success. These are translated to the 29d4afb5ceSopenharmony_ci * lws convention of 0 for success. 30d4afb5ceSopenharmony_ci */ 31d4afb5ceSopenharmony_ci 32d4afb5ceSopenharmony_ciextern int openssl_websocket_private_data_index, 33d4afb5ceSopenharmony_ci openssl_SSL_CTX_private_data_index; 34d4afb5ceSopenharmony_ci 35d4afb5ceSopenharmony_ciint lws_openssl_describe_cipher(struct lws *wsi); 36d4afb5ceSopenharmony_ci 37d4afb5ceSopenharmony_cistatic int 38d4afb5ceSopenharmony_ciOpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) 39d4afb5ceSopenharmony_ci{ 40d4afb5ceSopenharmony_ci SSL *ssl; 41d4afb5ceSopenharmony_ci int n; 42d4afb5ceSopenharmony_ci struct lws *wsi; 43d4afb5ceSopenharmony_ci union lws_tls_cert_info_results ir; 44d4afb5ceSopenharmony_ci X509 *topcert = X509_STORE_CTX_get_current_cert(x509_ctx); 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ci ssl = X509_STORE_CTX_get_ex_data(x509_ctx, 47d4afb5ceSopenharmony_ci SSL_get_ex_data_X509_STORE_CTX_idx()); 48d4afb5ceSopenharmony_ci 49d4afb5ceSopenharmony_ci /* 50d4afb5ceSopenharmony_ci * !!! nasty openssl requires the index to come as a library-scope 51d4afb5ceSopenharmony_ci * static 52d4afb5ceSopenharmony_ci */ 53d4afb5ceSopenharmony_ci wsi = SSL_get_ex_data(ssl, openssl_websocket_private_data_index); 54d4afb5ceSopenharmony_ci 55d4afb5ceSopenharmony_ci n = lws_tls_openssl_cert_info(topcert, LWS_TLS_CERT_INFO_COMMON_NAME, 56d4afb5ceSopenharmony_ci &ir, sizeof(ir.ns.name)); 57d4afb5ceSopenharmony_ci if (!n) 58d4afb5ceSopenharmony_ci lwsl_info("%s: client cert CN '%s'\n", __func__, ir.ns.name); 59d4afb5ceSopenharmony_ci else 60d4afb5ceSopenharmony_ci lwsl_info("%s: couldn't get client cert CN\n", __func__); 61d4afb5ceSopenharmony_ci 62d4afb5ceSopenharmony_ci n = wsi->a.vhost->protocols[0].callback(wsi, 63d4afb5ceSopenharmony_ci LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, 64d4afb5ceSopenharmony_ci x509_ctx, ssl, (unsigned int)preverify_ok); 65d4afb5ceSopenharmony_ci 66d4afb5ceSopenharmony_ci /* convert return code from 0 = OK to 1 = OK */ 67d4afb5ceSopenharmony_ci return !n; 68d4afb5ceSopenharmony_ci} 69d4afb5ceSopenharmony_ci 70d4afb5ceSopenharmony_ciint 71d4afb5ceSopenharmony_cilws_tls_server_client_cert_verify_config(struct lws_vhost *vh) 72d4afb5ceSopenharmony_ci{ 73d4afb5ceSopenharmony_ci int verify_options = SSL_VERIFY_PEER; 74d4afb5ceSopenharmony_ci 75d4afb5ceSopenharmony_ci /* as a server, are we requiring clients to identify themselves? */ 76d4afb5ceSopenharmony_ci 77d4afb5ceSopenharmony_ci if (!lws_check_opt(vh->options, 78d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) 79d4afb5ceSopenharmony_ci return 0; 80d4afb5ceSopenharmony_ci 81d4afb5ceSopenharmony_ci if (!lws_check_opt(vh->options, 82d4afb5ceSopenharmony_ci LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED)) 83d4afb5ceSopenharmony_ci verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; 84d4afb5ceSopenharmony_ci 85d4afb5ceSopenharmony_ci SSL_CTX_set_session_id_context(vh->tls.ssl_ctx, (uint8_t *)vh->context, 86d4afb5ceSopenharmony_ci sizeof(void *)); 87d4afb5ceSopenharmony_ci 88d4afb5ceSopenharmony_ci /* absolutely require the client cert */ 89d4afb5ceSopenharmony_ci SSL_CTX_set_verify(vh->tls.ssl_ctx, verify_options, 90d4afb5ceSopenharmony_ci OpenSSL_verify_callback); 91d4afb5ceSopenharmony_ci 92d4afb5ceSopenharmony_ci return 0; 93d4afb5ceSopenharmony_ci} 94d4afb5ceSopenharmony_ci 95d4afb5ceSopenharmony_ci#if defined(SSL_TLSEXT_ERR_NOACK) && !defined(OPENSSL_NO_TLSEXT) 96d4afb5ceSopenharmony_cistatic int 97d4afb5ceSopenharmony_cilws_ssl_server_name_cb(SSL *ssl, int *ad, void *arg) 98d4afb5ceSopenharmony_ci{ 99d4afb5ceSopenharmony_ci struct lws_context *context = (struct lws_context *)arg; 100d4afb5ceSopenharmony_ci struct lws_vhost *vhost, *vh; 101d4afb5ceSopenharmony_ci const char *servername; 102d4afb5ceSopenharmony_ci 103d4afb5ceSopenharmony_ci if (!ssl) 104d4afb5ceSopenharmony_ci return SSL_TLSEXT_ERR_NOACK; 105d4afb5ceSopenharmony_ci 106d4afb5ceSopenharmony_ci /* 107d4afb5ceSopenharmony_ci * We can only get ssl accepted connections by using a vhost's ssl_ctx 108d4afb5ceSopenharmony_ci * find out which listening one took us and only match vhosts on the 109d4afb5ceSopenharmony_ci * same port. 110d4afb5ceSopenharmony_ci */ 111d4afb5ceSopenharmony_ci vh = context->vhost_list; 112d4afb5ceSopenharmony_ci while (vh) { 113d4afb5ceSopenharmony_ci if (!vh->being_destroyed && 114d4afb5ceSopenharmony_ci vh->tls.ssl_ctx == SSL_get_SSL_CTX(ssl)) 115d4afb5ceSopenharmony_ci break; 116d4afb5ceSopenharmony_ci vh = vh->vhost_next; 117d4afb5ceSopenharmony_ci } 118d4afb5ceSopenharmony_ci 119d4afb5ceSopenharmony_ci if (!vh) { 120d4afb5ceSopenharmony_ci assert(vh); /* can't match the incoming vh? */ 121d4afb5ceSopenharmony_ci return SSL_TLSEXT_ERR_OK; 122d4afb5ceSopenharmony_ci } 123d4afb5ceSopenharmony_ci 124d4afb5ceSopenharmony_ci servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); 125d4afb5ceSopenharmony_ci if (!servername) { 126d4afb5ceSopenharmony_ci /* the client doesn't know what hostname it wants */ 127d4afb5ceSopenharmony_ci lwsl_info("SNI: Unknown ServerName\n"); 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_ci return SSL_TLSEXT_ERR_OK; 130d4afb5ceSopenharmony_ci } 131d4afb5ceSopenharmony_ci 132d4afb5ceSopenharmony_ci vhost = lws_select_vhost(context, vh->listen_port, servername); 133d4afb5ceSopenharmony_ci if (!vhost) { 134d4afb5ceSopenharmony_ci lwsl_info("SNI: none: %s:%d\n", servername, vh->listen_port); 135d4afb5ceSopenharmony_ci 136d4afb5ceSopenharmony_ci return SSL_TLSEXT_ERR_OK; 137d4afb5ceSopenharmony_ci } 138d4afb5ceSopenharmony_ci 139d4afb5ceSopenharmony_ci lwsl_info("SNI: Found: %s:%d\n", servername, vh->listen_port); 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci /* select the ssl ctx from the selected vhost for this conn */ 142d4afb5ceSopenharmony_ci SSL_set_SSL_CTX(ssl, vhost->tls.ssl_ctx); 143d4afb5ceSopenharmony_ci 144d4afb5ceSopenharmony_ci return SSL_TLSEXT_ERR_OK; 145d4afb5ceSopenharmony_ci} 146d4afb5ceSopenharmony_ci#endif 147d4afb5ceSopenharmony_ci 148d4afb5ceSopenharmony_ci/* 149d4afb5ceSopenharmony_ci * this may now get called after the vhost creation, when certs become 150d4afb5ceSopenharmony_ci * available. 151d4afb5ceSopenharmony_ci */ 152d4afb5ceSopenharmony_ciint 153d4afb5ceSopenharmony_cilws_tls_server_certs_load(struct lws_vhost *vhost, struct lws *wsi, 154d4afb5ceSopenharmony_ci const char *cert, const char *private_key, 155d4afb5ceSopenharmony_ci const char *mem_cert, size_t mem_cert_len, 156d4afb5ceSopenharmony_ci const char *mem_privkey, size_t mem_privkey_len) 157d4afb5ceSopenharmony_ci{ 158d4afb5ceSopenharmony_ci#if !defined(OPENSSL_NO_EC) && defined(LWS_HAVE_EC_KEY_new_by_curve_name) && \ 159d4afb5ceSopenharmony_ci ((OPENSSL_VERSION_NUMBER < 0x30000000l) || \ 160d4afb5ceSopenharmony_ci defined(LWS_SUPPRESS_DEPRECATED_API_WARNINGS)) 161d4afb5ceSopenharmony_ci const char *ecdh_curve = "prime256v1"; 162d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_BORINGSSL) && defined(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS) 163d4afb5ceSopenharmony_ci STACK_OF(X509) *extra_certs = NULL; 164d4afb5ceSopenharmony_ci#endif 165d4afb5ceSopenharmony_ci EC_KEY *ecdh, *EC_key = NULL; 166d4afb5ceSopenharmony_ci EVP_PKEY *pkey; 167d4afb5ceSopenharmony_ci X509 *x = NULL; 168d4afb5ceSopenharmony_ci int ecdh_nid; 169d4afb5ceSopenharmony_ci int KeyType; 170d4afb5ceSopenharmony_ci#endif 171d4afb5ceSopenharmony_ci unsigned long error; 172d4afb5ceSopenharmony_ci lws_filepos_t flen; 173d4afb5ceSopenharmony_ci uint8_t *p; 174d4afb5ceSopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10100000L 175d4afb5ceSopenharmony_ci int ret; 176d4afb5ceSopenharmony_ci#endif 177d4afb5ceSopenharmony_ci int n = (int)lws_tls_generic_cert_checks(vhost, cert, private_key), m; 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci if (!cert && !private_key) 180d4afb5ceSopenharmony_ci n = LWS_TLS_EXTANT_ALTERNATIVE; 181d4afb5ceSopenharmony_ci 182d4afb5ceSopenharmony_ci if (n == LWS_TLS_EXTANT_NO && (!mem_cert || !mem_privkey)) 183d4afb5ceSopenharmony_ci return 0; 184d4afb5ceSopenharmony_ci if (n == LWS_TLS_EXTANT_NO) 185d4afb5ceSopenharmony_ci n = LWS_TLS_EXTANT_ALTERNATIVE; 186d4afb5ceSopenharmony_ci 187d4afb5ceSopenharmony_ci if (n == LWS_TLS_EXTANT_ALTERNATIVE && (!mem_cert || !mem_privkey)) 188d4afb5ceSopenharmony_ci return 1; /* no alternative */ 189d4afb5ceSopenharmony_ci 190d4afb5ceSopenharmony_ci if (n == LWS_TLS_EXTANT_ALTERNATIVE) { 191d4afb5ceSopenharmony_ci 192d4afb5ceSopenharmony_ci#if OPENSSL_VERSION_NUMBER >= 0x10100000L 193d4afb5ceSopenharmony_ci 194d4afb5ceSopenharmony_ci /* 195d4afb5ceSopenharmony_ci * Although we have prepared update certs, we no longer have 196d4afb5ceSopenharmony_ci * the rights to read our own cert + key we saved. 197d4afb5ceSopenharmony_ci * 198d4afb5ceSopenharmony_ci * If we were passed copies in memory buffers, use those 199d4afb5ceSopenharmony_ci * in favour of the filepaths we normally want. 200d4afb5ceSopenharmony_ci */ 201d4afb5ceSopenharmony_ci cert = NULL; 202d4afb5ceSopenharmony_ci private_key = NULL; 203d4afb5ceSopenharmony_ci } 204d4afb5ceSopenharmony_ci 205d4afb5ceSopenharmony_ci /* 206d4afb5ceSopenharmony_ci * use the multi-cert interface for backwards compatibility in the 207d4afb5ceSopenharmony_ci * both simple files case 208d4afb5ceSopenharmony_ci */ 209d4afb5ceSopenharmony_ci 210d4afb5ceSopenharmony_ci if (n != LWS_TLS_EXTANT_ALTERNATIVE && cert) { 211d4afb5ceSopenharmony_ci 212d4afb5ceSopenharmony_ci /* set the local certificate from CertFile */ 213d4afb5ceSopenharmony_ci m = SSL_CTX_use_certificate_chain_file(vhost->tls.ssl_ctx, cert); 214d4afb5ceSopenharmony_ci if (m != 1) { 215d4afb5ceSopenharmony_ci const char *s; 216d4afb5ceSopenharmony_ci error = ERR_get_error(); 217d4afb5ceSopenharmony_ci 218d4afb5ceSopenharmony_ci s = ERR_error_string( 219d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 220d4afb5ceSopenharmony_ci (uint32_t) 221d4afb5ceSopenharmony_ci#endif 222d4afb5ceSopenharmony_ci error, 223d4afb5ceSopenharmony_ci (char *)vhost->context->pt[0].serv_buf); 224d4afb5ceSopenharmony_ci 225d4afb5ceSopenharmony_ci lwsl_err("problem getting cert '%s' %lu: %s\n", 226d4afb5ceSopenharmony_ci cert, error, s); 227d4afb5ceSopenharmony_ci 228d4afb5ceSopenharmony_ci return 1; 229d4afb5ceSopenharmony_ci } 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci if (!private_key) { 232d4afb5ceSopenharmony_ci lwsl_err("ssl private key not set\n"); 233d4afb5ceSopenharmony_ci return 1; 234d4afb5ceSopenharmony_ci } else { 235d4afb5ceSopenharmony_ci /* set the private key from KeyFile */ 236d4afb5ceSopenharmony_ci if (SSL_CTX_use_PrivateKey_file(vhost->tls.ssl_ctx, private_key, 237d4afb5ceSopenharmony_ci SSL_FILETYPE_PEM) != 1) { 238d4afb5ceSopenharmony_ci const char *s; 239d4afb5ceSopenharmony_ci error = ERR_get_error(); 240d4afb5ceSopenharmony_ci s = ERR_error_string( 241d4afb5ceSopenharmony_ci #if defined(LWS_WITH_BORINGSSL) 242d4afb5ceSopenharmony_ci (uint32_t) 243d4afb5ceSopenharmony_ci #endif 244d4afb5ceSopenharmony_ci error, 245d4afb5ceSopenharmony_ci (char *)vhost->context->pt[0].serv_buf); 246d4afb5ceSopenharmony_ci lwsl_err("ssl problem getting key '%s' %lu: %s\n", 247d4afb5ceSopenharmony_ci private_key, error, s); 248d4afb5ceSopenharmony_ci return 1; 249d4afb5ceSopenharmony_ci } 250d4afb5ceSopenharmony_ci } 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ci return 0; 253d4afb5ceSopenharmony_ci } 254d4afb5ceSopenharmony_ci 255d4afb5ceSopenharmony_ci /* otherwise allow for DER or PEM, file or memory image */ 256d4afb5ceSopenharmony_ci 257d4afb5ceSopenharmony_ci if (lws_tls_alloc_pem_to_der_file(vhost->context, cert, mem_cert, 258d4afb5ceSopenharmony_ci mem_cert_len, &p, &flen)) { 259d4afb5ceSopenharmony_ci lwsl_err("%s: couldn't read cert file\n", __func__); 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_ci return 1; 262d4afb5ceSopenharmony_ci } 263d4afb5ceSopenharmony_ci 264d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 265d4afb5ceSopenharmony_ci ret = SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx, 266d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 267d4afb5ceSopenharmony_ci (size_t) 268d4afb5ceSopenharmony_ci#else 269d4afb5ceSopenharmony_ci (int) 270d4afb5ceSopenharmony_ci#endif 271d4afb5ceSopenharmony_ci flen, p); 272d4afb5ceSopenharmony_ci#else 273d4afb5ceSopenharmony_ci ret = wolfSSL_CTX_use_certificate_buffer(vhost->tls.ssl_ctx, 274d4afb5ceSopenharmony_ci (uint8_t *)p, (int)flen, 275d4afb5ceSopenharmony_ci WOLFSSL_FILETYPE_ASN1); 276d4afb5ceSopenharmony_ci#endif 277d4afb5ceSopenharmony_ci lws_free_set_NULL(p); 278d4afb5ceSopenharmony_ci if (ret != 1) { 279d4afb5ceSopenharmony_ci lwsl_err("%s: Problem loading cert\n", __func__); 280d4afb5ceSopenharmony_ci 281d4afb5ceSopenharmony_ci return 1; 282d4afb5ceSopenharmony_ci } 283d4afb5ceSopenharmony_ci 284d4afb5ceSopenharmony_ci if (lws_tls_alloc_pem_to_der_file(vhost->context, private_key, 285d4afb5ceSopenharmony_ci mem_privkey, mem_privkey_len, 286d4afb5ceSopenharmony_ci &p, &flen)) { 287d4afb5ceSopenharmony_ci lwsl_notice("unable to convert memory privkey\n"); 288d4afb5ceSopenharmony_ci 289d4afb5ceSopenharmony_ci return 1; 290d4afb5ceSopenharmony_ci } 291d4afb5ceSopenharmony_ci 292d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 293d4afb5ceSopenharmony_ci ret = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, vhost->tls.ssl_ctx, p, 294d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 295d4afb5ceSopenharmony_ci (size_t) 296d4afb5ceSopenharmony_ci#else 297d4afb5ceSopenharmony_ci (long)(long long) 298d4afb5ceSopenharmony_ci#endif 299d4afb5ceSopenharmony_ci flen); 300d4afb5ceSopenharmony_ci if (ret != 1) { 301d4afb5ceSopenharmony_ci ret = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC, 302d4afb5ceSopenharmony_ci vhost->tls.ssl_ctx, p, 303d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 304d4afb5ceSopenharmony_ci (size_t) 305d4afb5ceSopenharmony_ci#else 306d4afb5ceSopenharmony_ci (long)(long long) 307d4afb5ceSopenharmony_ci#endif 308d4afb5ceSopenharmony_ci flen); 309d4afb5ceSopenharmony_ci } 310d4afb5ceSopenharmony_ci#else 311d4afb5ceSopenharmony_ci ret = wolfSSL_CTX_use_PrivateKey_buffer(vhost->tls.ssl_ctx, p, flen, 312d4afb5ceSopenharmony_ci WOLFSSL_FILETYPE_ASN1); 313d4afb5ceSopenharmony_ci#endif 314d4afb5ceSopenharmony_ci lws_free_set_NULL(p); 315d4afb5ceSopenharmony_ci if (ret != 1) { 316d4afb5ceSopenharmony_ci lwsl_notice("unable to use memory privkey\n"); 317d4afb5ceSopenharmony_ci 318d4afb5ceSopenharmony_ci return 1; 319d4afb5ceSopenharmony_ci } 320d4afb5ceSopenharmony_ci 321d4afb5ceSopenharmony_ci#else 322d4afb5ceSopenharmony_ci /* 323d4afb5ceSopenharmony_ci * Although we have prepared update certs, we no longer have 324d4afb5ceSopenharmony_ci * the rights to read our own cert + key we saved. 325d4afb5ceSopenharmony_ci * 326d4afb5ceSopenharmony_ci * If we were passed copies in memory buffers, use those 327d4afb5ceSopenharmony_ci * instead. 328d4afb5ceSopenharmony_ci * 329d4afb5ceSopenharmony_ci * The passed memory-buffer cert image is in DER, and the 330d4afb5ceSopenharmony_ci * memory-buffer private key image is PEM. 331d4afb5ceSopenharmony_ci */ 332d4afb5ceSopenharmony_ci#ifndef USE_WOLFSSL 333d4afb5ceSopenharmony_ci if (lws_tls_alloc_pem_to_der_file(vhost->context, cert, mem_cert, 334d4afb5ceSopenharmony_ci mem_cert_len, &p, &flen)) { 335d4afb5ceSopenharmony_ci lwsl_err("%s: couldn't convert pem to der\n", __func__); 336d4afb5ceSopenharmony_ci return 1; 337d4afb5ceSopenharmony_ci } 338d4afb5ceSopenharmony_ci if (SSL_CTX_use_certificate_ASN1(vhost->tls.ssl_ctx, 339d4afb5ceSopenharmony_ci (int)flen, 340d4afb5ceSopenharmony_ci (uint8_t *)p) != 1) { 341d4afb5ceSopenharmony_ci#else 342d4afb5ceSopenharmony_ci if (wolfSSL_CTX_use_certificate_buffer(vhost->tls.ssl_ctx, 343d4afb5ceSopenharmony_ci (uint8_t *)mem_cert, 344d4afb5ceSopenharmony_ci (int)mem_cert_len, 345d4afb5ceSopenharmony_ci WOLFSSL_FILETYPE_ASN1) != 1) { 346d4afb5ceSopenharmony_ci 347d4afb5ceSopenharmony_ci#endif 348d4afb5ceSopenharmony_ci lwsl_err("Problem loading update cert\n"); 349d4afb5ceSopenharmony_ci 350d4afb5ceSopenharmony_ci return 1; 351d4afb5ceSopenharmony_ci } 352d4afb5ceSopenharmony_ci 353d4afb5ceSopenharmony_ci if (lws_tls_alloc_pem_to_der_file(vhost->context, NULL, 354d4afb5ceSopenharmony_ci mem_privkey, mem_privkey_len, 355d4afb5ceSopenharmony_ci &p, &flen)) { 356d4afb5ceSopenharmony_ci lwsl_notice("unable to convert memory privkey\n"); 357d4afb5ceSopenharmony_ci 358d4afb5ceSopenharmony_ci return 1; 359d4afb5ceSopenharmony_ci } 360d4afb5ceSopenharmony_ci#ifndef USE_WOLFSSL 361d4afb5ceSopenharmony_ci if (SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, 362d4afb5ceSopenharmony_ci vhost->tls.ssl_ctx, p, 363d4afb5ceSopenharmony_ci (long)(long long)flen) != 1) { 364d4afb5ceSopenharmony_ci#else 365d4afb5ceSopenharmony_ci if (wolfSSL_CTX_use_PrivateKey_buffer(vhost->tls.ssl_ctx, p, 366d4afb5ceSopenharmony_ci (long)flen, WOLFSSL_FILETYPE_ASN1) != 1) { 367d4afb5ceSopenharmony_ci#endif 368d4afb5ceSopenharmony_ci lwsl_notice("unable to use memory privkey\n"); 369d4afb5ceSopenharmony_ci 370d4afb5ceSopenharmony_ci return 1; 371d4afb5ceSopenharmony_ci } 372d4afb5ceSopenharmony_ci 373d4afb5ceSopenharmony_ci goto check_key; 374d4afb5ceSopenharmony_ci } 375d4afb5ceSopenharmony_ci 376d4afb5ceSopenharmony_ci /* set the local certificate from CertFile */ 377d4afb5ceSopenharmony_ci m = SSL_CTX_use_certificate_chain_file(vhost->tls.ssl_ctx, cert); 378d4afb5ceSopenharmony_ci if (m != 1) { 379d4afb5ceSopenharmony_ci error = ERR_get_error(); 380d4afb5ceSopenharmony_ci lwsl_err("problem getting cert '%s' %lu: %s\n", 381d4afb5ceSopenharmony_ci cert, error, ERR_error_string(error, 382d4afb5ceSopenharmony_ci (char *)vhost->context->pt[0].serv_buf)); 383d4afb5ceSopenharmony_ci 384d4afb5ceSopenharmony_ci return 1; 385d4afb5ceSopenharmony_ci } 386d4afb5ceSopenharmony_ci 387d4afb5ceSopenharmony_ci if (n == LWS_TLS_EXTANT_ALTERNATIVE || !private_key) { 388d4afb5ceSopenharmony_ci lwsl_err("ssl private key not set\n"); 389d4afb5ceSopenharmony_ci return 1; 390d4afb5ceSopenharmony_ci } else { 391d4afb5ceSopenharmony_ci /* set the private key from KeyFile */ 392d4afb5ceSopenharmony_ci if (SSL_CTX_use_PrivateKey_file(vhost->tls.ssl_ctx, private_key, 393d4afb5ceSopenharmony_ci SSL_FILETYPE_PEM) != 1) { 394d4afb5ceSopenharmony_ci error = ERR_get_error(); 395d4afb5ceSopenharmony_ci lwsl_err("ssl problem getting key '%s' %lu: %s\n", 396d4afb5ceSopenharmony_ci private_key, error, 397d4afb5ceSopenharmony_ci ERR_error_string(error, 398d4afb5ceSopenharmony_ci (char *)vhost->context->pt[0].serv_buf)); 399d4afb5ceSopenharmony_ci return 1; 400d4afb5ceSopenharmony_ci } 401d4afb5ceSopenharmony_ci } 402d4afb5ceSopenharmony_ci 403d4afb5ceSopenharmony_cicheck_key: 404d4afb5ceSopenharmony_ci#endif 405d4afb5ceSopenharmony_ci 406d4afb5ceSopenharmony_ci /* verify private key */ 407d4afb5ceSopenharmony_ci if (!SSL_CTX_check_private_key(vhost->tls.ssl_ctx)) { 408d4afb5ceSopenharmony_ci lwsl_err("Private SSL key doesn't match cert\n"); 409d4afb5ceSopenharmony_ci 410d4afb5ceSopenharmony_ci return 1; 411d4afb5ceSopenharmony_ci } 412d4afb5ceSopenharmony_ci 413d4afb5ceSopenharmony_ci 414d4afb5ceSopenharmony_ci#if !defined(OPENSSL_NO_EC) && defined(LWS_HAVE_EC_KEY_new_by_curve_name) && \ 415d4afb5ceSopenharmony_ci ((OPENSSL_VERSION_NUMBER < 0x30000000l) || \ 416d4afb5ceSopenharmony_ci defined(LWS_SUPPRESS_DEPRECATED_API_WARNINGS)) 417d4afb5ceSopenharmony_ci if (vhost->tls.ecdh_curve[0]) 418d4afb5ceSopenharmony_ci ecdh_curve = vhost->tls.ecdh_curve; 419d4afb5ceSopenharmony_ci 420d4afb5ceSopenharmony_ci ecdh_nid = OBJ_sn2nid(ecdh_curve); 421d4afb5ceSopenharmony_ci if (NID_undef == ecdh_nid) { 422d4afb5ceSopenharmony_ci lwsl_err("SSL: Unknown curve name '%s'", ecdh_curve); 423d4afb5ceSopenharmony_ci return 1; 424d4afb5ceSopenharmony_ci } 425d4afb5ceSopenharmony_ci 426d4afb5ceSopenharmony_ci ecdh = EC_KEY_new_by_curve_name(ecdh_nid); 427d4afb5ceSopenharmony_ci if (NULL == ecdh) { 428d4afb5ceSopenharmony_ci lwsl_err("SSL: Unable to create curve '%s'", ecdh_curve); 429d4afb5ceSopenharmony_ci return 1; 430d4afb5ceSopenharmony_ci } 431d4afb5ceSopenharmony_ci SSL_CTX_set_tmp_ecdh(vhost->tls.ssl_ctx, ecdh); 432d4afb5ceSopenharmony_ci EC_KEY_free(ecdh); 433d4afb5ceSopenharmony_ci 434d4afb5ceSopenharmony_ci SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_SINGLE_ECDH_USE); 435d4afb5ceSopenharmony_ci 436d4afb5ceSopenharmony_ci lwsl_notice(" SSL ECDH curve '%s'\n", ecdh_curve); 437d4afb5ceSopenharmony_ci 438d4afb5ceSopenharmony_ci if (lws_check_opt(vhost->context->options, LWS_SERVER_OPTION_SSL_ECDH)) 439d4afb5ceSopenharmony_ci lwsl_notice(" Using ECDH certificate support\n"); 440d4afb5ceSopenharmony_ci 441d4afb5ceSopenharmony_ci /* Get X509 certificate from ssl context */ 442d4afb5ceSopenharmony_ci#if !defined(LWS_WITH_BORINGSSL) 443d4afb5ceSopenharmony_ci#if !defined(LWS_HAVE_SSL_EXTRA_CHAIN_CERTS) 444d4afb5ceSopenharmony_ci x = sk_X509_value(vhost->tls.ssl_ctx->extra_certs, 0); 445d4afb5ceSopenharmony_ci#else 446d4afb5ceSopenharmony_ci SSL_CTX_get_extra_chain_certs_only(vhost->tls.ssl_ctx, &extra_certs); 447d4afb5ceSopenharmony_ci if (extra_certs) 448d4afb5ceSopenharmony_ci x = sk_X509_value(extra_certs, 0); 449d4afb5ceSopenharmony_ci else 450d4afb5ceSopenharmony_ci lwsl_info("%s: no extra certs\n", __func__); 451d4afb5ceSopenharmony_ci#endif 452d4afb5ceSopenharmony_ci if (!x) { 453d4afb5ceSopenharmony_ci //lwsl_err("%s: x is NULL\n", __func__); 454d4afb5ceSopenharmony_ci goto post_ecdh; 455d4afb5ceSopenharmony_ci } 456d4afb5ceSopenharmony_ci#else 457d4afb5ceSopenharmony_ci return 0; 458d4afb5ceSopenharmony_ci#endif /* !boringssl */ 459d4afb5ceSopenharmony_ci 460d4afb5ceSopenharmony_ci /* Get the public key from certificate */ 461d4afb5ceSopenharmony_ci pkey = X509_get_pubkey(x); 462d4afb5ceSopenharmony_ci if (!pkey) { 463d4afb5ceSopenharmony_ci lwsl_err("%s: pkey is NULL\n", __func__); 464d4afb5ceSopenharmony_ci 465d4afb5ceSopenharmony_ci return 1; 466d4afb5ceSopenharmony_ci } 467d4afb5ceSopenharmony_ci /* Get the key type */ 468d4afb5ceSopenharmony_ci KeyType = EVP_PKEY_type(EVP_PKEY_id(pkey)); 469d4afb5ceSopenharmony_ci 470d4afb5ceSopenharmony_ci if (EVP_PKEY_EC != KeyType) { 471d4afb5ceSopenharmony_ci lwsl_notice("Key type is not EC\n"); 472d4afb5ceSopenharmony_ci return 0; 473d4afb5ceSopenharmony_ci } 474d4afb5ceSopenharmony_ci /* Get the key */ 475d4afb5ceSopenharmony_ci EC_key = EVP_PKEY_get1_EC_KEY(pkey); 476d4afb5ceSopenharmony_ci /* Set ECDH parameter */ 477d4afb5ceSopenharmony_ci if (!EC_key) { 478d4afb5ceSopenharmony_ci lwsl_err("%s: ECDH key is NULL \n", __func__); 479d4afb5ceSopenharmony_ci return 1; 480d4afb5ceSopenharmony_ci } 481d4afb5ceSopenharmony_ci SSL_CTX_set_tmp_ecdh(vhost->tls.ssl_ctx, EC_key); 482d4afb5ceSopenharmony_ci 483d4afb5ceSopenharmony_ci EC_KEY_free(EC_key); 484d4afb5ceSopenharmony_ci 485d4afb5ceSopenharmony_ci#if !defined(OPENSSL_NO_EC) && !defined(LWS_WITH_BORINGSSL) 486d4afb5ceSopenharmony_cipost_ecdh: 487d4afb5ceSopenharmony_ci#endif 488d4afb5ceSopenharmony_ci vhost->tls.skipped_certs = 0; 489d4afb5ceSopenharmony_ci#else 490d4afb5ceSopenharmony_ci lwsl_notice(" OpenSSL doesn't support ECDH\n"); 491d4afb5ceSopenharmony_ci#endif 492d4afb5ceSopenharmony_ci 493d4afb5ceSopenharmony_ci return 0; 494d4afb5ceSopenharmony_ci} 495d4afb5ceSopenharmony_ci 496d4afb5ceSopenharmony_ciint 497d4afb5ceSopenharmony_cilws_tls_server_vhost_backend_init(const struct lws_context_creation_info *info, 498d4afb5ceSopenharmony_ci struct lws_vhost *vhost, struct lws *wsi) 499d4afb5ceSopenharmony_ci{ 500d4afb5ceSopenharmony_ci unsigned long error; 501d4afb5ceSopenharmony_ci SSL_METHOD *method = (SSL_METHOD *)SSLv23_server_method(); 502d4afb5ceSopenharmony_ci 503d4afb5ceSopenharmony_ci if (!method) { 504d4afb5ceSopenharmony_ci const char *s; 505d4afb5ceSopenharmony_ci error = ERR_get_error(); 506d4afb5ceSopenharmony_ci s = ERR_error_string( 507d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 508d4afb5ceSopenharmony_ci (uint32_t) 509d4afb5ceSopenharmony_ci#endif 510d4afb5ceSopenharmony_ci error, 511d4afb5ceSopenharmony_ci (char *)vhost->context->pt[0].serv_buf); 512d4afb5ceSopenharmony_ci 513d4afb5ceSopenharmony_ci lwsl_err("problem creating ssl method %lu: %s\n", 514d4afb5ceSopenharmony_ci error, s); 515d4afb5ceSopenharmony_ci return 1; 516d4afb5ceSopenharmony_ci } 517d4afb5ceSopenharmony_ci vhost->tls.ssl_ctx = SSL_CTX_new(method); /* create context */ 518d4afb5ceSopenharmony_ci if (!vhost->tls.ssl_ctx) { 519d4afb5ceSopenharmony_ci const char *s; 520d4afb5ceSopenharmony_ci 521d4afb5ceSopenharmony_ci error = ERR_get_error(); 522d4afb5ceSopenharmony_ci s = ERR_error_string( 523d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 524d4afb5ceSopenharmony_ci (uint32_t) 525d4afb5ceSopenharmony_ci#endif 526d4afb5ceSopenharmony_ci error, 527d4afb5ceSopenharmony_ci (char *)vhost->context->pt[0].serv_buf); 528d4afb5ceSopenharmony_ci lwsl_err("problem creating ssl context %lu: %s\n", 529d4afb5ceSopenharmony_ci error, s); 530d4afb5ceSopenharmony_ci return 1; 531d4afb5ceSopenharmony_ci } 532d4afb5ceSopenharmony_ci 533d4afb5ceSopenharmony_ci SSL_CTX_set_ex_data(vhost->tls.ssl_ctx, 534d4afb5ceSopenharmony_ci openssl_SSL_CTX_private_data_index, 535d4afb5ceSopenharmony_ci (char *)vhost->context); 536d4afb5ceSopenharmony_ci /* Disable SSLv2 and SSLv3 */ 537d4afb5ceSopenharmony_ci SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_NO_SSLv2 | 538d4afb5ceSopenharmony_ci SSL_OP_NO_SSLv3); 539d4afb5ceSopenharmony_ci#ifdef SSL_OP_NO_COMPRESSION 540d4afb5ceSopenharmony_ci SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_NO_COMPRESSION); 541d4afb5ceSopenharmony_ci#endif 542d4afb5ceSopenharmony_ci SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_SINGLE_DH_USE); 543d4afb5ceSopenharmony_ci SSL_CTX_set_options(vhost->tls.ssl_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); 544d4afb5ceSopenharmony_ci 545d4afb5ceSopenharmony_ci if (info->ssl_cipher_list) 546d4afb5ceSopenharmony_ci SSL_CTX_set_cipher_list(vhost->tls.ssl_ctx, info->ssl_cipher_list); 547d4afb5ceSopenharmony_ci 548d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_set_ciphersuites) 549d4afb5ceSopenharmony_ci if (info->tls1_3_plus_cipher_list) 550d4afb5ceSopenharmony_ci SSL_CTX_set_ciphersuites(vhost->tls.ssl_ctx, 551d4afb5ceSopenharmony_ci info->tls1_3_plus_cipher_list); 552d4afb5ceSopenharmony_ci#endif 553d4afb5ceSopenharmony_ci 554d4afb5ceSopenharmony_ci#if !defined(OPENSSL_NO_TLSEXT) 555d4afb5ceSopenharmony_ci SSL_CTX_set_tlsext_servername_callback(vhost->tls.ssl_ctx, 556d4afb5ceSopenharmony_ci lws_ssl_server_name_cb); 557d4afb5ceSopenharmony_ci SSL_CTX_set_tlsext_servername_arg(vhost->tls.ssl_ctx, vhost->context); 558d4afb5ceSopenharmony_ci#endif 559d4afb5ceSopenharmony_ci 560d4afb5ceSopenharmony_ci if (info->ssl_ca_filepath && 561d4afb5ceSopenharmony_ci#if defined(LWS_HAVE_SSL_CTX_load_verify_file) 562d4afb5ceSopenharmony_ci !SSL_CTX_load_verify_file(vhost->tls.ssl_ctx, 563d4afb5ceSopenharmony_ci info->ssl_ca_filepath)) { 564d4afb5ceSopenharmony_ci#else 565d4afb5ceSopenharmony_ci !SSL_CTX_load_verify_locations(vhost->tls.ssl_ctx, 566d4afb5ceSopenharmony_ci info->ssl_ca_filepath, NULL)) { 567d4afb5ceSopenharmony_ci#endif 568d4afb5ceSopenharmony_ci lwsl_err("%s: SSL_CTX_load_verify_locations unhappy\n", 569d4afb5ceSopenharmony_ci __func__); 570d4afb5ceSopenharmony_ci } 571d4afb5ceSopenharmony_ci 572d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL) 573d4afb5ceSopenharmony_ci long 574d4afb5ceSopenharmony_ci#else 575d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 576d4afb5ceSopenharmony_ci uint32_t 577d4afb5ceSopenharmony_ci#else 578d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ 579d4afb5ceSopenharmony_ci unsigned long 580d4afb5ceSopenharmony_ci#else 581d4afb5ceSopenharmony_ci long 582d4afb5ceSopenharmony_ci#endif 583d4afb5ceSopenharmony_ci#endif 584d4afb5ceSopenharmony_ci#endif 585d4afb5ceSopenharmony_ci ssl_options_set_value = 586d4afb5ceSopenharmony_ci#if defined(USE_WOLFSSL) 587d4afb5ceSopenharmony_ci (long) 588d4afb5ceSopenharmony_ci#else 589d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 590d4afb5ceSopenharmony_ci (uint32_t) 591d4afb5ceSopenharmony_ci#else 592d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER) /* not documented by openssl */ 593d4afb5ceSopenharmony_ci (unsigned long) 594d4afb5ceSopenharmony_ci#else 595d4afb5ceSopenharmony_ci (long) 596d4afb5ceSopenharmony_ci#endif 597d4afb5ceSopenharmony_ci#endif 598d4afb5ceSopenharmony_ci#endif 599d4afb5ceSopenharmony_ci info->ssl_options_set; 600d4afb5ceSopenharmony_ci 601d4afb5ceSopenharmony_ci if (info->ssl_options_set) 602d4afb5ceSopenharmony_ci SSL_CTX_set_options(vhost->tls.ssl_ctx, ssl_options_set_value); 603d4afb5ceSopenharmony_ci 604d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x009080df) && !defined(USE_WOLFSSL) 605d4afb5ceSopenharmony_ci 606d4afb5ceSopenharmony_ci/* SSL_clear_options introduced in 0.9.8m */ 607d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 608d4afb5ceSopenharmony_ci uint32_t 609d4afb5ceSopenharmony_ci#else 610d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER)/* not documented by openssl */ 611d4afb5ceSopenharmony_ci unsigned long 612d4afb5ceSopenharmony_ci#else 613d4afb5ceSopenharmony_ci long 614d4afb5ceSopenharmony_ci#endif 615d4afb5ceSopenharmony_ci#endif 616d4afb5ceSopenharmony_ci 617d4afb5ceSopenharmony_ci ssl_options_clear_value = 618d4afb5ceSopenharmony_ci#if defined(LWS_WITH_BORINGSSL) 619d4afb5ceSopenharmony_ci (uint32_t) 620d4afb5ceSopenharmony_ci#else 621d4afb5ceSopenharmony_ci#if (OPENSSL_VERSION_NUMBER >= 0x10003000l) && !defined(LIBRESSL_VERSION_NUMBER)/* not documented by openssl */ 622d4afb5ceSopenharmony_ci (unsigned long) 623d4afb5ceSopenharmony_ci#else 624d4afb5ceSopenharmony_ci (long) 625d4afb5ceSopenharmony_ci#endif 626d4afb5ceSopenharmony_ci#endif 627d4afb5ceSopenharmony_ci info->ssl_options_clear; 628d4afb5ceSopenharmony_ci 629d4afb5ceSopenharmony_ci if (info->ssl_options_clear) { 630d4afb5ceSopenharmony_ci SSL_CTX_clear_options(vhost->tls.ssl_ctx, ssl_options_clear_value); 631d4afb5ceSopenharmony_ci } 632d4afb5ceSopenharmony_ci 633d4afb5ceSopenharmony_ci lwsl_info(" SSL options 0x%lX\n", 634d4afb5ceSopenharmony_ci (unsigned long)SSL_CTX_get_options(vhost->tls.ssl_ctx)); 635d4afb5ceSopenharmony_ci#endif 636d4afb5ceSopenharmony_ci 637d4afb5ceSopenharmony_ci if (!vhost->tls.use_ssl || 638d4afb5ceSopenharmony_ci (!info->ssl_cert_filepath && !info->server_ssl_cert_mem)) 639d4afb5ceSopenharmony_ci return 0; 640d4afb5ceSopenharmony_ci 641d4afb5ceSopenharmony_ci lws_ssl_bind_passphrase(vhost->tls.ssl_ctx, 0, info); 642d4afb5ceSopenharmony_ci 643d4afb5ceSopenharmony_ci return lws_tls_server_certs_load(vhost, wsi, info->ssl_cert_filepath, 644d4afb5ceSopenharmony_ci info->ssl_private_key_filepath, 645d4afb5ceSopenharmony_ci info->server_ssl_cert_mem, 646d4afb5ceSopenharmony_ci info->server_ssl_cert_mem_len, 647d4afb5ceSopenharmony_ci info->server_ssl_private_key_mem, 648d4afb5ceSopenharmony_ci info->server_ssl_private_key_mem_len); 649d4afb5ceSopenharmony_ci} 650d4afb5ceSopenharmony_ci 651d4afb5ceSopenharmony_ciint 652d4afb5ceSopenharmony_cilws_tls_server_new_nonblocking(struct lws *wsi, lws_sockfd_type accept_fd) 653d4afb5ceSopenharmony_ci{ 654d4afb5ceSopenharmony_ci#if !defined(USE_WOLFSSL) 655d4afb5ceSopenharmony_ci BIO *bio; 656d4afb5ceSopenharmony_ci#endif 657d4afb5ceSopenharmony_ci 658d4afb5ceSopenharmony_ci errno = 0; 659d4afb5ceSopenharmony_ci ERR_clear_error(); 660d4afb5ceSopenharmony_ci wsi->tls.ssl = SSL_new(wsi->a.vhost->tls.ssl_ctx); 661d4afb5ceSopenharmony_ci if (wsi->tls.ssl == NULL) { 662d4afb5ceSopenharmony_ci lwsl_err("SSL_new failed: %d (errno %d)\n", 663d4afb5ceSopenharmony_ci lws_ssl_get_error(wsi, 0), errno); 664d4afb5ceSopenharmony_ci 665d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 666d4afb5ceSopenharmony_ci return 1; 667d4afb5ceSopenharmony_ci } 668d4afb5ceSopenharmony_ci 669d4afb5ceSopenharmony_ci SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index, wsi); 670d4afb5ceSopenharmony_ci SSL_set_fd(wsi->tls.ssl, (int)(lws_intptr_t)accept_fd); 671d4afb5ceSopenharmony_ci 672d4afb5ceSopenharmony_ci#ifdef USE_WOLFSSL 673d4afb5ceSopenharmony_ci#ifdef USE_OLD_CYASSL 674d4afb5ceSopenharmony_ci CyaSSL_set_using_nonblock(wsi->tls.ssl, 1); 675d4afb5ceSopenharmony_ci#else 676d4afb5ceSopenharmony_ci wolfSSL_set_using_nonblock(wsi->tls.ssl, 1); 677d4afb5ceSopenharmony_ci#endif 678d4afb5ceSopenharmony_ci#else 679d4afb5ceSopenharmony_ci 680d4afb5ceSopenharmony_ci SSL_set_mode(wsi->tls.ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | 681d4afb5ceSopenharmony_ci SSL_MODE_RELEASE_BUFFERS); 682d4afb5ceSopenharmony_ci bio = SSL_get_rbio(wsi->tls.ssl); 683d4afb5ceSopenharmony_ci if (bio) 684d4afb5ceSopenharmony_ci BIO_set_nbio(bio, 1); /* nonblocking */ 685d4afb5ceSopenharmony_ci else 686d4afb5ceSopenharmony_ci lwsl_notice("NULL rbio\n"); 687d4afb5ceSopenharmony_ci bio = SSL_get_wbio(wsi->tls.ssl); 688d4afb5ceSopenharmony_ci if (bio) 689d4afb5ceSopenharmony_ci BIO_set_nbio(bio, 1); /* nonblocking */ 690d4afb5ceSopenharmony_ci else 691d4afb5ceSopenharmony_ci lwsl_notice("NULL rbio\n"); 692d4afb5ceSopenharmony_ci#endif 693d4afb5ceSopenharmony_ci 694d4afb5ceSopenharmony_ci#if defined (LWS_HAVE_SSL_SET_INFO_CALLBACK) 695d4afb5ceSopenharmony_ci if (wsi->a.vhost->tls.ssl_info_event_mask) 696d4afb5ceSopenharmony_ci SSL_set_info_callback(wsi->tls.ssl, lws_ssl_info_callback); 697d4afb5ceSopenharmony_ci#endif 698d4afb5ceSopenharmony_ci 699d4afb5ceSopenharmony_ci return 0; 700d4afb5ceSopenharmony_ci} 701d4afb5ceSopenharmony_ci 702d4afb5ceSopenharmony_cienum lws_ssl_capable_status 703d4afb5ceSopenharmony_cilws_tls_server_abort_connection(struct lws *wsi) 704d4afb5ceSopenharmony_ci{ 705d4afb5ceSopenharmony_ci if (wsi->tls.use_ssl) 706d4afb5ceSopenharmony_ci SSL_shutdown(wsi->tls.ssl); 707d4afb5ceSopenharmony_ci SSL_free(wsi->tls.ssl); 708d4afb5ceSopenharmony_ci 709d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_DONE; 710d4afb5ceSopenharmony_ci} 711d4afb5ceSopenharmony_ci 712d4afb5ceSopenharmony_cienum lws_ssl_capable_status 713d4afb5ceSopenharmony_cilws_tls_server_accept(struct lws *wsi) 714d4afb5ceSopenharmony_ci{ 715d4afb5ceSopenharmony_ci struct lws_context_per_thread *pt = &wsi->a.context->pt[(int)wsi->tsi]; 716d4afb5ceSopenharmony_ci union lws_tls_cert_info_results ir; 717d4afb5ceSopenharmony_ci int m, n; 718d4afb5ceSopenharmony_ci 719d4afb5ceSopenharmony_ci errno = 0; 720d4afb5ceSopenharmony_ci ERR_clear_error(); 721d4afb5ceSopenharmony_ci n = SSL_accept(wsi->tls.ssl); 722d4afb5ceSopenharmony_ci 723d4afb5ceSopenharmony_ci wsi->skip_fallback = 1; 724d4afb5ceSopenharmony_ci 725d4afb5ceSopenharmony_ci if (n == 1) { 726d4afb5ceSopenharmony_ci n = lws_tls_peer_cert_info(wsi, LWS_TLS_CERT_INFO_COMMON_NAME, &ir, 727d4afb5ceSopenharmony_ci sizeof(ir.ns.name)); 728d4afb5ceSopenharmony_ci if (!n) 729d4afb5ceSopenharmony_ci lwsl_notice("%s: client cert CN '%s'\n", __func__, 730d4afb5ceSopenharmony_ci ir.ns.name); 731d4afb5ceSopenharmony_ci else 732d4afb5ceSopenharmony_ci lwsl_info("%s: no client cert CN\n", __func__); 733d4afb5ceSopenharmony_ci 734d4afb5ceSopenharmony_ci lws_openssl_describe_cipher(wsi); 735d4afb5ceSopenharmony_ci 736d4afb5ceSopenharmony_ci if (SSL_pending(wsi->tls.ssl) && 737d4afb5ceSopenharmony_ci lws_dll2_is_detached(&wsi->tls.dll_pending_tls)) 738d4afb5ceSopenharmony_ci lws_dll2_add_head(&wsi->tls.dll_pending_tls, 739d4afb5ceSopenharmony_ci &pt->tls.dll_pending_tls_owner); 740d4afb5ceSopenharmony_ci 741d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_DONE; 742d4afb5ceSopenharmony_ci } 743d4afb5ceSopenharmony_ci 744d4afb5ceSopenharmony_ci m = lws_ssl_get_error(wsi, n); 745d4afb5ceSopenharmony_ci lws_tls_err_describe_clear(); 746d4afb5ceSopenharmony_ci 747d4afb5ceSopenharmony_ci if (m == SSL_ERROR_SYSCALL || m == SSL_ERROR_SSL) 748d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_ERROR; 749d4afb5ceSopenharmony_ci 750d4afb5ceSopenharmony_ci if (m == SSL_ERROR_WANT_READ || 751d4afb5ceSopenharmony_ci (m != SSL_ERROR_ZERO_RETURN && SSL_want_read(wsi->tls.ssl))) { 752d4afb5ceSopenharmony_ci if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) { 753d4afb5ceSopenharmony_ci lwsl_info("%s: WANT_READ change_pollfd failed\n", 754d4afb5ceSopenharmony_ci __func__); 755d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_ERROR; 756d4afb5ceSopenharmony_ci } 757d4afb5ceSopenharmony_ci 758d4afb5ceSopenharmony_ci lwsl_info("SSL_ERROR_WANT_READ: m %d\n", m); 759d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_MORE_SERVICE_READ; 760d4afb5ceSopenharmony_ci } 761d4afb5ceSopenharmony_ci if (m == SSL_ERROR_WANT_WRITE || SSL_want_write(wsi->tls.ssl)) { 762d4afb5ceSopenharmony_ci lwsl_debug("%s: WANT_WRITE\n", __func__); 763d4afb5ceSopenharmony_ci 764d4afb5ceSopenharmony_ci if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) { 765d4afb5ceSopenharmony_ci lwsl_info("%s: WANT_WRITE change_pollfd failed\n", 766d4afb5ceSopenharmony_ci __func__); 767d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_ERROR; 768d4afb5ceSopenharmony_ci } 769d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_MORE_SERVICE_WRITE; 770d4afb5ceSopenharmony_ci } 771d4afb5ceSopenharmony_ci 772d4afb5ceSopenharmony_ci return LWS_SSL_CAPABLE_ERROR; 773d4afb5ceSopenharmony_ci} 774d4afb5ceSopenharmony_ci 775d4afb5ceSopenharmony_ci#if defined(LWS_WITH_ACME) 776d4afb5ceSopenharmony_cistatic int 777d4afb5ceSopenharmony_cilws_tls_openssl_rsa_new_key(RSA **rsa, int bits) 778d4afb5ceSopenharmony_ci{ 779d4afb5ceSopenharmony_ci BIGNUM *bn = BN_new(); 780d4afb5ceSopenharmony_ci int n; 781d4afb5ceSopenharmony_ci 782d4afb5ceSopenharmony_ci if (!bn) 783d4afb5ceSopenharmony_ci return 1; 784d4afb5ceSopenharmony_ci 785d4afb5ceSopenharmony_ci if (BN_set_word(bn, RSA_F4) != 1) { 786d4afb5ceSopenharmony_ci BN_free(bn); 787d4afb5ceSopenharmony_ci return 1; 788d4afb5ceSopenharmony_ci } 789d4afb5ceSopenharmony_ci 790d4afb5ceSopenharmony_ci *rsa = RSA_new(); 791d4afb5ceSopenharmony_ci if (!*rsa) { 792d4afb5ceSopenharmony_ci BN_free(bn); 793d4afb5ceSopenharmony_ci return 1; 794d4afb5ceSopenharmony_ci } 795d4afb5ceSopenharmony_ci 796d4afb5ceSopenharmony_ci n = RSA_generate_key_ex(*rsa, bits, bn, NULL); 797d4afb5ceSopenharmony_ci BN_free(bn); 798d4afb5ceSopenharmony_ci if (n == 1) 799d4afb5ceSopenharmony_ci return 0; 800d4afb5ceSopenharmony_ci 801d4afb5ceSopenharmony_ci RSA_free(*rsa); 802d4afb5ceSopenharmony_ci *rsa = NULL; 803d4afb5ceSopenharmony_ci 804d4afb5ceSopenharmony_ci return 1; 805d4afb5ceSopenharmony_ci} 806d4afb5ceSopenharmony_ci 807d4afb5ceSopenharmony_cistruct lws_tls_ss_pieces { 808d4afb5ceSopenharmony_ci X509 *x509; 809d4afb5ceSopenharmony_ci EVP_PKEY *pkey; 810d4afb5ceSopenharmony_ci RSA *rsa; 811d4afb5ceSopenharmony_ci}; 812d4afb5ceSopenharmony_ci 813d4afb5ceSopenharmony_ciint 814d4afb5ceSopenharmony_cilws_tls_acme_sni_cert_create(struct lws_vhost *vhost, const char *san_a, 815d4afb5ceSopenharmony_ci const char *san_b) 816d4afb5ceSopenharmony_ci{ 817d4afb5ceSopenharmony_ci GENERAL_NAMES *gens = sk_GENERAL_NAME_new_null(); 818d4afb5ceSopenharmony_ci GENERAL_NAME *gen = NULL; 819d4afb5ceSopenharmony_ci ASN1_IA5STRING *ia5 = NULL; 820d4afb5ceSopenharmony_ci X509_NAME *name; 821d4afb5ceSopenharmony_ci 822d4afb5ceSopenharmony_ci if (!gens) 823d4afb5ceSopenharmony_ci return 1; 824d4afb5ceSopenharmony_ci 825d4afb5ceSopenharmony_ci vhost->tls.ss = lws_zalloc(sizeof(*vhost->tls.ss), "sni cert"); 826d4afb5ceSopenharmony_ci if (!vhost->tls.ss) { 827d4afb5ceSopenharmony_ci GENERAL_NAMES_free(gens); 828d4afb5ceSopenharmony_ci return 1; 829d4afb5ceSopenharmony_ci } 830d4afb5ceSopenharmony_ci 831d4afb5ceSopenharmony_ci vhost->tls.ss->x509 = X509_new(); 832d4afb5ceSopenharmony_ci if (!vhost->tls.ss->x509) 833d4afb5ceSopenharmony_ci goto bail; 834d4afb5ceSopenharmony_ci 835d4afb5ceSopenharmony_ci ASN1_INTEGER_set(X509_get_serialNumber(vhost->tls.ss->x509), 1); 836d4afb5ceSopenharmony_ci X509_gmtime_adj(X509_get_notBefore(vhost->tls.ss->x509), 0); 837d4afb5ceSopenharmony_ci X509_gmtime_adj(X509_get_notAfter(vhost->tls.ss->x509), 3600); 838d4afb5ceSopenharmony_ci 839d4afb5ceSopenharmony_ci vhost->tls.ss->pkey = EVP_PKEY_new(); 840d4afb5ceSopenharmony_ci if (!vhost->tls.ss->pkey) 841d4afb5ceSopenharmony_ci goto bail0; 842d4afb5ceSopenharmony_ci 843d4afb5ceSopenharmony_ci if (lws_tls_openssl_rsa_new_key(&vhost->tls.ss->rsa, 4096)) 844d4afb5ceSopenharmony_ci goto bail1; 845d4afb5ceSopenharmony_ci 846d4afb5ceSopenharmony_ci if (!EVP_PKEY_assign_RSA(vhost->tls.ss->pkey, vhost->tls.ss->rsa)) 847d4afb5ceSopenharmony_ci goto bail2; 848d4afb5ceSopenharmony_ci 849d4afb5ceSopenharmony_ci X509_set_pubkey(vhost->tls.ss->x509, vhost->tls.ss->pkey); 850d4afb5ceSopenharmony_ci 851d4afb5ceSopenharmony_ci name = X509_get_subject_name(vhost->tls.ss->x509); 852d4afb5ceSopenharmony_ci X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, 853d4afb5ceSopenharmony_ci (unsigned char *)"GB", -1, -1, 0); 854d4afb5ceSopenharmony_ci X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, 855d4afb5ceSopenharmony_ci (unsigned char *)"somecompany", -1, -1, 0); 856d4afb5ceSopenharmony_ci if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_UTF8, 857d4afb5ceSopenharmony_ci (unsigned char *)"temp.acme.invalid", 858d4afb5ceSopenharmony_ci -1, -1, 0) != 1) { 859d4afb5ceSopenharmony_ci lwsl_notice("failed to add CN\n"); 860d4afb5ceSopenharmony_ci goto bail2; 861d4afb5ceSopenharmony_ci } 862d4afb5ceSopenharmony_ci X509_set_issuer_name(vhost->tls.ss->x509, name); 863d4afb5ceSopenharmony_ci 864d4afb5ceSopenharmony_ci /* add the SAN payloads */ 865d4afb5ceSopenharmony_ci 866d4afb5ceSopenharmony_ci gen = GENERAL_NAME_new(); 867d4afb5ceSopenharmony_ci ia5 = ASN1_IA5STRING_new(); 868d4afb5ceSopenharmony_ci if (!ASN1_STRING_set(ia5, san_a, -1)) { 869d4afb5ceSopenharmony_ci lwsl_notice("failed to set ia5\n"); 870d4afb5ceSopenharmony_ci GENERAL_NAME_free(gen); 871d4afb5ceSopenharmony_ci goto bail2; 872d4afb5ceSopenharmony_ci } 873d4afb5ceSopenharmony_ci GENERAL_NAME_set0_value(gen, GEN_DNS, ia5); 874d4afb5ceSopenharmony_ci sk_GENERAL_NAME_push(gens, gen); 875d4afb5ceSopenharmony_ci 876d4afb5ceSopenharmony_ci if (X509_add1_ext_i2d(vhost->tls.ss->x509, NID_subject_alt_name, 877d4afb5ceSopenharmony_ci gens, 0, X509V3_ADD_APPEND) != 1) 878d4afb5ceSopenharmony_ci goto bail2; 879d4afb5ceSopenharmony_ci 880d4afb5ceSopenharmony_ci GENERAL_NAMES_free(gens); 881d4afb5ceSopenharmony_ci 882d4afb5ceSopenharmony_ci if (san_b && san_b[0]) { 883d4afb5ceSopenharmony_ci gens = sk_GENERAL_NAME_new_null(); 884d4afb5ceSopenharmony_ci gen = GENERAL_NAME_new(); 885d4afb5ceSopenharmony_ci ia5 = ASN1_IA5STRING_new(); 886d4afb5ceSopenharmony_ci if (!ASN1_STRING_set(ia5, san_a, -1)) { 887d4afb5ceSopenharmony_ci lwsl_notice("failed to set ia5\n"); 888d4afb5ceSopenharmony_ci GENERAL_NAME_free(gen); 889d4afb5ceSopenharmony_ci goto bail2; 890d4afb5ceSopenharmony_ci } 891d4afb5ceSopenharmony_ci GENERAL_NAME_set0_value(gen, GEN_DNS, ia5); 892d4afb5ceSopenharmony_ci sk_GENERAL_NAME_push(gens, gen); 893d4afb5ceSopenharmony_ci 894d4afb5ceSopenharmony_ci if (X509_add1_ext_i2d(vhost->tls.ss->x509, NID_subject_alt_name, 895d4afb5ceSopenharmony_ci gens, 0, X509V3_ADD_APPEND) != 1) 896d4afb5ceSopenharmony_ci goto bail2; 897d4afb5ceSopenharmony_ci 898d4afb5ceSopenharmony_ci GENERAL_NAMES_free(gens); 899d4afb5ceSopenharmony_ci } 900d4afb5ceSopenharmony_ci 901d4afb5ceSopenharmony_ci /* sign it with our private key */ 902d4afb5ceSopenharmony_ci if (!X509_sign(vhost->tls.ss->x509, vhost->tls.ss->pkey, EVP_sha256())) 903d4afb5ceSopenharmony_ci goto bail2; 904d4afb5ceSopenharmony_ci 905d4afb5ceSopenharmony_ci#if 0 906d4afb5ceSopenharmony_ci {/* useful to take a sample of a working cert for mbedtls to crib */ 907d4afb5ceSopenharmony_ci FILE *fp = fopen("/tmp/acme-temp-cert", "w+"); 908d4afb5ceSopenharmony_ci 909d4afb5ceSopenharmony_ci i2d_X509_fp(fp, vhost->tls.ss->x509); 910d4afb5ceSopenharmony_ci fclose(fp); 911d4afb5ceSopenharmony_ci } 912d4afb5ceSopenharmony_ci#endif 913d4afb5ceSopenharmony_ci 914d4afb5ceSopenharmony_ci /* tell the vhost to use our crafted certificate */ 915d4afb5ceSopenharmony_ci SSL_CTX_use_certificate(vhost->tls.ssl_ctx, vhost->tls.ss->x509); 916d4afb5ceSopenharmony_ci /* and to use our generated private key */ 917d4afb5ceSopenharmony_ci SSL_CTX_use_PrivateKey(vhost->tls.ssl_ctx, vhost->tls.ss->pkey); 918d4afb5ceSopenharmony_ci 919d4afb5ceSopenharmony_ci return 0; 920d4afb5ceSopenharmony_ci 921d4afb5ceSopenharmony_cibail2: 922d4afb5ceSopenharmony_ci RSA_free(vhost->tls.ss->rsa); 923d4afb5ceSopenharmony_cibail1: 924d4afb5ceSopenharmony_ci EVP_PKEY_free(vhost->tls.ss->pkey); 925d4afb5ceSopenharmony_cibail0: 926d4afb5ceSopenharmony_ci X509_free(vhost->tls.ss->x509); 927d4afb5ceSopenharmony_cibail: 928d4afb5ceSopenharmony_ci lws_free(vhost->tls.ss); 929d4afb5ceSopenharmony_ci GENERAL_NAMES_free(gens); 930d4afb5ceSopenharmony_ci 931d4afb5ceSopenharmony_ci return 1; 932d4afb5ceSopenharmony_ci} 933d4afb5ceSopenharmony_ci 934d4afb5ceSopenharmony_civoid 935d4afb5ceSopenharmony_cilws_tls_acme_sni_cert_destroy(struct lws_vhost *vhost) 936d4afb5ceSopenharmony_ci{ 937d4afb5ceSopenharmony_ci if (!vhost->tls.ss) 938d4afb5ceSopenharmony_ci return; 939d4afb5ceSopenharmony_ci 940d4afb5ceSopenharmony_ci EVP_PKEY_free(vhost->tls.ss->pkey); 941d4afb5ceSopenharmony_ci X509_free(vhost->tls.ss->x509); 942d4afb5ceSopenharmony_ci lws_free_set_NULL(vhost->tls.ss); 943d4afb5ceSopenharmony_ci} 944d4afb5ceSopenharmony_ci 945d4afb5ceSopenharmony_cistatic int 946d4afb5ceSopenharmony_cilws_tls_openssl_add_nid(X509_NAME *name, int nid, const char *value) 947d4afb5ceSopenharmony_ci{ 948d4afb5ceSopenharmony_ci X509_NAME_ENTRY *e; 949d4afb5ceSopenharmony_ci int n; 950d4afb5ceSopenharmony_ci 951d4afb5ceSopenharmony_ci if (!value || value[0] == '\0') 952d4afb5ceSopenharmony_ci value = "none"; 953d4afb5ceSopenharmony_ci 954d4afb5ceSopenharmony_ci e = X509_NAME_ENTRY_create_by_NID(NULL, nid, MBSTRING_ASC, 955d4afb5ceSopenharmony_ci (unsigned char *)value, -1); 956d4afb5ceSopenharmony_ci if (!e) 957d4afb5ceSopenharmony_ci return 1; 958d4afb5ceSopenharmony_ci n = X509_NAME_add_entry(name, e, -1, 0); 959d4afb5ceSopenharmony_ci X509_NAME_ENTRY_free(e); 960d4afb5ceSopenharmony_ci 961d4afb5ceSopenharmony_ci return n != 1; 962d4afb5ceSopenharmony_ci} 963d4afb5ceSopenharmony_ci 964d4afb5ceSopenharmony_cistatic int nid_list[] = { 965d4afb5ceSopenharmony_ci NID_countryName, /* LWS_TLS_REQ_ELEMENT_COUNTRY */ 966d4afb5ceSopenharmony_ci NID_stateOrProvinceName, /* LWS_TLS_REQ_ELEMENT_STATE */ 967d4afb5ceSopenharmony_ci NID_localityName, /* LWS_TLS_REQ_ELEMENT_LOCALITY */ 968d4afb5ceSopenharmony_ci NID_organizationName, /* LWS_TLS_REQ_ELEMENT_ORGANIZATION */ 969d4afb5ceSopenharmony_ci NID_commonName, /* LWS_TLS_REQ_ELEMENT_COMMON_NAME */ 970d4afb5ceSopenharmony_ci NID_subject_alt_name, /* LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME */ 971d4afb5ceSopenharmony_ci NID_pkcs9_emailAddress, /* LWS_TLS_REQ_ELEMENT_EMAIL */ 972d4afb5ceSopenharmony_ci}; 973d4afb5ceSopenharmony_ci 974d4afb5ceSopenharmony_ciint 975d4afb5ceSopenharmony_cilws_tls_acme_sni_csr_create(struct lws_context *context, const char *elements[], 976d4afb5ceSopenharmony_ci uint8_t *csr, size_t csr_len, char **privkey_pem, 977d4afb5ceSopenharmony_ci size_t *privkey_len) 978d4afb5ceSopenharmony_ci{ 979d4afb5ceSopenharmony_ci uint8_t *csr_in = csr; 980d4afb5ceSopenharmony_ci RSA *rsakey; 981d4afb5ceSopenharmony_ci X509_REQ *req; 982d4afb5ceSopenharmony_ci X509_NAME *subj; 983d4afb5ceSopenharmony_ci EVP_PKEY *pkey; 984d4afb5ceSopenharmony_ci char *p, *end; 985d4afb5ceSopenharmony_ci BIO *bio; 986d4afb5ceSopenharmony_ci long bio_len; 987d4afb5ceSopenharmony_ci int n, ret = -1; 988d4afb5ceSopenharmony_ci 989d4afb5ceSopenharmony_ci if (lws_tls_openssl_rsa_new_key(&rsakey, 4096)) 990d4afb5ceSopenharmony_ci return -1; 991d4afb5ceSopenharmony_ci 992d4afb5ceSopenharmony_ci pkey = EVP_PKEY_new(); 993d4afb5ceSopenharmony_ci if (!pkey) 994d4afb5ceSopenharmony_ci goto bail0; 995d4afb5ceSopenharmony_ci if (!EVP_PKEY_set1_RSA(pkey, rsakey)) 996d4afb5ceSopenharmony_ci goto bail1; 997d4afb5ceSopenharmony_ci 998d4afb5ceSopenharmony_ci req = X509_REQ_new(); 999d4afb5ceSopenharmony_ci if (!req) 1000d4afb5ceSopenharmony_ci goto bail1; 1001d4afb5ceSopenharmony_ci 1002d4afb5ceSopenharmony_ci X509_REQ_set_pubkey(req, pkey); 1003d4afb5ceSopenharmony_ci 1004d4afb5ceSopenharmony_ci subj = X509_NAME_new(); 1005d4afb5ceSopenharmony_ci if (!subj) 1006d4afb5ceSopenharmony_ci goto bail2; 1007d4afb5ceSopenharmony_ci 1008d4afb5ceSopenharmony_ci for (n = 0; n < LWS_TLS_REQ_ELEMENT_COUNT; n++) 1009d4afb5ceSopenharmony_ci if (elements[n] && 1010d4afb5ceSopenharmony_ci lws_tls_openssl_add_nid(subj, nid_list[n], 1011d4afb5ceSopenharmony_ci elements[n])) { 1012d4afb5ceSopenharmony_ci lwsl_notice("%s: failed to add element %d\n", 1013d4afb5ceSopenharmony_ci __func__, n); 1014d4afb5ceSopenharmony_ci goto bail3; 1015d4afb5ceSopenharmony_ci } 1016d4afb5ceSopenharmony_ci 1017d4afb5ceSopenharmony_ci if (X509_REQ_set_subject_name(req, subj) != 1) 1018d4afb5ceSopenharmony_ci goto bail3; 1019d4afb5ceSopenharmony_ci 1020d4afb5ceSopenharmony_ci if (elements[LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME]) { 1021d4afb5ceSopenharmony_ci STACK_OF(X509_EXTENSION) *exts; 1022d4afb5ceSopenharmony_ci X509_EXTENSION *ext; 1023d4afb5ceSopenharmony_ci char san[256]; 1024d4afb5ceSopenharmony_ci 1025d4afb5ceSopenharmony_ci exts = sk_X509_EXTENSION_new_null(); 1026d4afb5ceSopenharmony_ci if (!exts) 1027d4afb5ceSopenharmony_ci goto bail3; 1028d4afb5ceSopenharmony_ci 1029d4afb5ceSopenharmony_ci lws_snprintf(san, sizeof(san), "DNS:%s,DNS:%s", 1030d4afb5ceSopenharmony_ci elements[LWS_TLS_REQ_ELEMENT_COMMON_NAME], 1031d4afb5ceSopenharmony_ci elements[LWS_TLS_REQ_ELEMENT_SUBJECT_ALT_NAME]); 1032d4afb5ceSopenharmony_ci 1033d4afb5ceSopenharmony_ci ext = X509V3_EXT_conf_nid(NULL, NULL, NID_subject_alt_name, 1034d4afb5ceSopenharmony_ci san); 1035d4afb5ceSopenharmony_ci if (!ext) { 1036d4afb5ceSopenharmony_ci sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); 1037d4afb5ceSopenharmony_ci goto bail3; 1038d4afb5ceSopenharmony_ci } 1039d4afb5ceSopenharmony_ci sk_X509_EXTENSION_push(exts, ext); 1040d4afb5ceSopenharmony_ci 1041d4afb5ceSopenharmony_ci if (!X509_REQ_add_extensions(req, exts)) { 1042d4afb5ceSopenharmony_ci sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); 1043d4afb5ceSopenharmony_ci goto bail3; 1044d4afb5ceSopenharmony_ci } 1045d4afb5ceSopenharmony_ci sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); 1046d4afb5ceSopenharmony_ci } 1047d4afb5ceSopenharmony_ci 1048d4afb5ceSopenharmony_ci if (!X509_REQ_sign(req, pkey, EVP_sha256())) 1049d4afb5ceSopenharmony_ci goto bail3; 1050d4afb5ceSopenharmony_ci 1051d4afb5ceSopenharmony_ci /* 1052d4afb5ceSopenharmony_ci * issue the CSR as PEM to a BIO, and translate to b64urlenc without 1053d4afb5ceSopenharmony_ci * headers, trailers, or whitespace 1054d4afb5ceSopenharmony_ci */ 1055d4afb5ceSopenharmony_ci 1056d4afb5ceSopenharmony_ci bio = BIO_new(BIO_s_mem()); 1057d4afb5ceSopenharmony_ci if (!bio) 1058d4afb5ceSopenharmony_ci goto bail3; 1059d4afb5ceSopenharmony_ci 1060d4afb5ceSopenharmony_ci if (PEM_write_bio_X509_REQ(bio, req) != 1) { 1061d4afb5ceSopenharmony_ci BIO_free(bio); 1062d4afb5ceSopenharmony_ci goto bail3; 1063d4afb5ceSopenharmony_ci } 1064d4afb5ceSopenharmony_ci 1065d4afb5ceSopenharmony_ci bio_len = BIO_get_mem_data(bio, &p); 1066d4afb5ceSopenharmony_ci end = p + bio_len; 1067d4afb5ceSopenharmony_ci 1068d4afb5ceSopenharmony_ci /* strip the header line */ 1069d4afb5ceSopenharmony_ci while (p < end && *p != '\n') 1070d4afb5ceSopenharmony_ci p++; 1071d4afb5ceSopenharmony_ci 1072d4afb5ceSopenharmony_ci while (p < end && csr_len) { 1073d4afb5ceSopenharmony_ci if (*p == '\n') { 1074d4afb5ceSopenharmony_ci p++; 1075d4afb5ceSopenharmony_ci continue; 1076d4afb5ceSopenharmony_ci } 1077d4afb5ceSopenharmony_ci 1078d4afb5ceSopenharmony_ci if (*p == '-') 1079d4afb5ceSopenharmony_ci break; 1080d4afb5ceSopenharmony_ci 1081d4afb5ceSopenharmony_ci if (*p == '+') 1082d4afb5ceSopenharmony_ci *csr++ = '-'; 1083d4afb5ceSopenharmony_ci else 1084d4afb5ceSopenharmony_ci if (*p == '/') 1085d4afb5ceSopenharmony_ci *csr++ = '_'; 1086d4afb5ceSopenharmony_ci else 1087d4afb5ceSopenharmony_ci *csr++ = (uint8_t)*p; 1088d4afb5ceSopenharmony_ci p++; 1089d4afb5ceSopenharmony_ci csr_len--; 1090d4afb5ceSopenharmony_ci } 1091d4afb5ceSopenharmony_ci BIO_free(bio); 1092d4afb5ceSopenharmony_ci if (!csr_len) { 1093d4afb5ceSopenharmony_ci lwsl_notice("%s: need %ld for CSR\n", __func__, bio_len); 1094d4afb5ceSopenharmony_ci goto bail3; 1095d4afb5ceSopenharmony_ci } 1096d4afb5ceSopenharmony_ci 1097d4afb5ceSopenharmony_ci /* 1098d4afb5ceSopenharmony_ci * Also return the private key as a PEM in memory 1099d4afb5ceSopenharmony_ci * (platform may not have a filesystem) 1100d4afb5ceSopenharmony_ci */ 1101d4afb5ceSopenharmony_ci bio = BIO_new(BIO_s_mem()); 1102d4afb5ceSopenharmony_ci if (!bio) 1103d4afb5ceSopenharmony_ci goto bail3; 1104d4afb5ceSopenharmony_ci 1105d4afb5ceSopenharmony_ci if (PEM_write_bio_PrivateKey(bio, pkey, NULL, NULL, 0, 0, NULL) != 1) { 1106d4afb5ceSopenharmony_ci BIO_free(bio); 1107d4afb5ceSopenharmony_ci goto bail3; 1108d4afb5ceSopenharmony_ci } 1109d4afb5ceSopenharmony_ci bio_len = BIO_get_mem_data(bio, &p); 1110d4afb5ceSopenharmony_ci *privkey_pem = malloc((unsigned long)bio_len); /* malloc so user code can own / free */ 1111d4afb5ceSopenharmony_ci *privkey_len = (size_t)bio_len; 1112d4afb5ceSopenharmony_ci if (!*privkey_pem) { 1113d4afb5ceSopenharmony_ci lwsl_notice("%s: need %ld for private key\n", __func__, 1114d4afb5ceSopenharmony_ci bio_len); 1115d4afb5ceSopenharmony_ci BIO_free(bio); 1116d4afb5ceSopenharmony_ci goto bail3; 1117d4afb5ceSopenharmony_ci } 1118d4afb5ceSopenharmony_ci memcpy(*privkey_pem, p, (unsigned int)(int)(long long)bio_len); 1119d4afb5ceSopenharmony_ci BIO_free(bio); 1120d4afb5ceSopenharmony_ci 1121d4afb5ceSopenharmony_ci ret = lws_ptr_diff(csr, csr_in); 1122d4afb5ceSopenharmony_ci 1123d4afb5ceSopenharmony_cibail3: 1124d4afb5ceSopenharmony_ci X509_NAME_free(subj); 1125d4afb5ceSopenharmony_cibail2: 1126d4afb5ceSopenharmony_ci X509_REQ_free(req); 1127d4afb5ceSopenharmony_cibail1: 1128d4afb5ceSopenharmony_ci EVP_PKEY_free(pkey); 1129d4afb5ceSopenharmony_cibail0: 1130d4afb5ceSopenharmony_ci RSA_free(rsakey); 1131d4afb5ceSopenharmony_ci 1132d4afb5ceSopenharmony_ci return ret; 1133d4afb5ceSopenharmony_ci} 1134d4afb5ceSopenharmony_ci#endif 1135