diff --git a/include/libwebsockets/lws-client.h b/include/libwebsockets/lws-client.h index b49e22224..e7f602d0d 100644 --- a/include/libwebsockets/lws-client.h +++ b/include/libwebsockets/lws-client.h @@ -145,6 +145,11 @@ struct lws_client_connect_info { * Currently only the idle parts are applied to the connection. */ + uint8_t sys_tls_client_cert; + /**< 0 means no client cert. 1+ means apply lws_system client cert 0+ + * to the client connection. + */ + /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility * diff --git a/lib/core-net/connect.c b/lib/core-net/connect.c index 91353c2b8..99bff8b71 100644 --- a/lib/core-net/connect.c +++ b/lib/core-net/connect.c @@ -143,6 +143,7 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i) wsi->pending_timeout = NO_PENDING_TIMEOUT; wsi->position_in_fds_table = LWS_NO_FDS_POS; wsi->ocport = wsi->c_port = i->port; + wsi->sys_tls_client_cert = i->sys_tls_client_cert; wsi->protocol = &wsi->vhost->protocols[0]; wsi->client_pipeline = !!(i->ssl_connection & LCCSCF_PIPELINE); diff --git a/lib/core-net/private-lib-core-net.h b/lib/core-net/private-lib-core-net.h index f4452c0ed..de27e7bc6 100644 --- a/lib/core-net/private-lib-core-net.h +++ b/lib/core-net/private-lib-core-net.h @@ -778,6 +778,7 @@ struct lws { #if defined(LWS_WITH_CLIENT) char chunk_parser; /* enum lws_chunk_parser */ uint8_t addrinfo_idx; + uint8_t sys_tls_client_cert; #endif #if defined(LWS_WITH_CGI) || defined(LWS_WITH_CLIENT) char reason_bf; /* internal writeable callback reason bitfield */ diff --git a/lib/tls/mbedtls/mbedtls-client.c b/lib/tls/mbedtls/mbedtls-client.c index 873632d30..9358898d7 100644 --- a/lib/tls/mbedtls/mbedtls-client.c +++ b/lib/tls/mbedtls/mbedtls-client.c @@ -102,7 +102,58 @@ lws_ssl_client_bio_create(struct lws *wsi) SSL_set_fd(wsi->tls.ssl, wsi->desc.sockfd); + if (wsi->sys_tls_client_cert) { + lws_system_blob_t *b = lws_system_get_blob(wsi->context, + LWS_SYSBLOB_TYPE_CLIENT_CERT_DER, + wsi->sys_tls_client_cert - 1); + const uint8_t *data; + size_t size; + + if (!b) + goto no_client_cert; + + /* + * Set up the per-connection client cert + */ + + size = lws_system_blob_get_size(b); + if (!size) + goto no_client_cert; + + if (lws_system_blob_get_single_ptr(b, &data)) + goto no_client_cert; + + if (SSL_use_certificate_ASN1(wsi->tls.ssl, data, size) != 1) + goto no_client_cert; + + b = lws_system_get_blob(wsi->context, + LWS_SYSBLOB_TYPE_CLIENT_KEY_DER, + wsi->sys_tls_client_cert - 1); + if (!b) + goto no_client_cert; + size = lws_system_blob_get_size(b); + if (!size) + goto no_client_cert; + + if (lws_system_blob_get_single_ptr(b, &data)) + goto no_client_cert; + + if (SSL_use_PrivateKey_ASN1(0, wsi->tls.ssl, data, size) != 1) + goto no_client_cert; + + /* no wrapper api for check key */ + + lwsl_notice("%s: set system client cert %u\n", __func__, + wsi->sys_tls_client_cert - 1); + } + return 0; + +no_client_cert: + lwsl_err("%s: unable to set up system client cert %d\n", __func__, + wsi->sys_tls_client_cert - 1); + + return 1; } int ERR_get_error(void) diff --git a/lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h b/lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h index 7594d064b..98e0268ab 100644 --- a/lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h +++ b/lib/tls/mbedtls/wrapper/include/internal/ssl_x509.h @@ -99,7 +99,8 @@ int SSL_add_client_CA(SSL *ssl, X509 *x); * 1 : OK * */ -int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); + +int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len); const char *X509_verify_cert_error_string(long n); diff --git a/lib/tls/mbedtls/wrapper/library/ssl_x509.c b/lib/tls/mbedtls/wrapper/library/ssl_x509.c index ed7915083..09a6afdc5 100644 --- a/lib/tls/mbedtls/wrapper/library/ssl_x509.c +++ b/lib/tls/mbedtls/wrapper/library/ssl_x509.c @@ -286,8 +286,7 @@ failed1: /** * @brief load certification into the SSL */ -int SSL_use_certificate_ASN1(SSL *ssl, int len, - const unsigned char *d) +int SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len) { int ret; X509 *x; diff --git a/lib/tls/openssl/openssl-client.c b/lib/tls/openssl/openssl-client.c index 1cf6a9aa5..96f4fdb03 100644 --- a/lib/tls/openssl/openssl-client.c +++ b/lib/tls/openssl/openssl-client.c @@ -279,7 +279,72 @@ lws_ssl_client_bio_create(struct lws *wsi) SSL_set_ex_data(wsi->tls.ssl, openssl_websocket_private_data_index, wsi); + if (wsi->sys_tls_client_cert) { + lws_system_blob_t *b = lws_system_get_blob(wsi->context, + LWS_SYSBLOB_TYPE_CLIENT_CERT_DER, + wsi->sys_tls_client_cert - 1); + const uint8_t *data; + size_t size; + + if (!b) + goto no_client_cert; + + /* + * Set up the per-connection client cert + */ + + size = lws_system_blob_get_size(b); + if (!size) + goto no_client_cert; + + if (lws_system_blob_get_single_ptr(b, &data)) + goto no_client_cert; + + if (SSL_use_certificate_ASN1(wsi->tls.ssl, data, size) != 1) { + lwsl_err("%s: use_certificate failed\n", __func__); + lws_tls_err_describe_clear(); + goto no_client_cert; + } + + b = lws_system_get_blob(wsi->context, + LWS_SYSBLOB_TYPE_CLIENT_KEY_DER, + wsi->sys_tls_client_cert - 1); + if (!b) + goto no_client_cert; + + size = lws_system_blob_get_size(b); + if (!size) + goto no_client_cert; + + if (lws_system_blob_get_single_ptr(b, &data)) + goto no_client_cert; + + if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, wsi->tls.ssl, + data, size) != 1 && + SSL_use_PrivateKey_ASN1(EVP_PKEY_EC, wsi->tls.ssl, + data, size) != 1) { + lwsl_err("%s: use_privkey failed\n", __func__); + lws_tls_err_describe_clear(); + goto no_client_cert; + } + + if (SSL_check_private_key(wsi->tls.ssl) != 1) { + lwsl_err("Private SSL key doesn't match cert\n"); + lws_tls_err_describe_clear(); + return 1; + } + + lwsl_notice("%s: set system client cert %u\n", __func__, + wsi->sys_tls_client_cert - 1); + } + return 0; + +no_client_cert: + lwsl_err("%s: unable to set up system client cert %d\n", __func__, + wsi->sys_tls_client_cert - 1); + + return 1; } enum lws_ssl_capable_status