diff --git a/include/libwebsockets/lws-context-vhost.h b/include/libwebsockets/lws-context-vhost.h index 09c2b126c..28abda9e9 100644 --- a/include/libwebsockets/lws-context-vhost.h +++ b/include/libwebsockets/lws-context-vhost.h @@ -487,6 +487,12 @@ struct lws_context_creation_info { * can handle the LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS * callback of protocols[0] to allow setting of the private key directly * via tls library calls */ + const void *client_ssl_key_mem; + /**< VHOST: Client SSL context init: client key memory buffer or + * NULL... use this to load client key from memory instead of file */ + unsigned int client_ssl_key_mem_len; + /**< VHOST: Client SSL context init: length of client_ssl_key_mem in + * bytes */ const char *client_ssl_ca_filepath; /**< VHOST: Client SSL context init: CA certificate filepath or NULL */ const void *client_ssl_ca_mem; diff --git a/lib/tls/mbedtls/mbedtls-client.c b/lib/tls/mbedtls/mbedtls-client.c index 0eac6b5ff..f93774aaa 100644 --- a/lib/tls/mbedtls/mbedtls-client.c +++ b/lib/tls/mbedtls/mbedtls-client.c @@ -256,7 +256,10 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, const char *cert_filepath, const void *cert_mem, unsigned int cert_mem_len, - const char *private_key_filepath) + const char *private_key_filepath, + const void *key_mem, + unsigned int key_mem_len + ) { X509 *d2i_X509(X509 **cert, const unsigned char *buffer, long len); SSL_METHOD *method = (SSL_METHOD *)TLS_client_method(); @@ -347,13 +350,13 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, lwsl_notice("Loaded client cert %s\n", cert_filepath); #endif } else if (cert_mem && cert_mem_len) { - // lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); + /* lwsl_hexdump_notice(cert_mem, cert_mem_len - 1); */ SSL_CTX_use_PrivateKey_ASN1(0, vh->tls.ssl_client_ctx, cert_mem, cert_mem_len - 1); n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx, cert_mem_len, cert_mem); if (n < 1) { - lwsl_err("%s: problem interpreting client cert\n", + lwsl_err("%s: (mbedtls) problem interpreting client cert\n", __func__); lws_tls_err_describe_clear(); return 1; diff --git a/lib/tls/openssl/openssl-client.c b/lib/tls/openssl/openssl-client.c index 9dd0a2c6e..b19523fc4 100644 --- a/lib/tls/openssl/openssl-client.c +++ b/lib/tls/openssl/openssl-client.c @@ -531,7 +531,10 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, const char *cert_filepath, const void *cert_mem, unsigned int cert_mem_len, - const char *private_key_filepath) + const char *private_key_filepath, + const void *key_mem, + unsigned int key_mem_len + ) { struct lws_tls_client_reuse *tcr; X509_STORE *x509_store; @@ -752,12 +755,11 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, } else { lws_filepos_t amount = 0; - uint8_t *up1; const uint8_t *up; + uint8_t *up1; if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, ca_mem, - ca_mem_len, &up1, - &amount)) { + ca_mem_len, &up1, &amount)) { lwsl_err("%s: Unable to decode x.509 mem\n", __func__); lwsl_hexdump_notice(ca_mem, ca_mem_len); return 1; @@ -796,6 +798,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, */ /* support for client-side certificate authentication */ + if (cert_filepath) { if (lws_tls_use_any_upgrade_check_extant(cert_filepath) != LWS_TLS_EXTANT_YES && @@ -813,18 +816,33 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, return 1; } lwsl_notice("Loaded client cert %s\n", cert_filepath); + } else if (cert_mem && cert_mem_len) { - n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx, - cert_mem_len, cert_mem); - if (n < 1) { - lwsl_err("%s: problem interpreting client cert\n", - __func__); - lws_tls_err_describe_clear(); + lws_filepos_t flen; + uint8_t *p; + + if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, cert_mem, + cert_mem_len, &p, &flen)) { + lwsl_err("%s: couldn't read cert file\n", __func__); + return 1; } + + n = SSL_CTX_use_certificate_ASN1(vh->tls.ssl_client_ctx, (int)flen, p); + + if (n < 1) { + lwsl_err("%s: problem interpreting client cert\n", __func__); + lws_tls_err_describe_clear(); + } + + lws_free_set_NULL(p); + + if (n != 1) + return 1; + } if (private_key_filepath) { - lwsl_notice("%s: doing private key filepath\n", __func__); + lwsl_info("%s: using private key filepath\n", __func__); lws_ssl_bind_passphrase(vh->tls.ssl_client_ctx, 1, info); /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(vh->tls.ssl_client_ctx, @@ -834,7 +852,7 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, lws_tls_err_describe_clear(); return 1; } - lwsl_notice("Loaded client cert private key %s\n", + lwsl_info("Loaded client cert private key %s\n", private_key_filepath); /* verify private key */ @@ -843,6 +861,33 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, return 1; } } + else if (key_mem && key_mem_len) { + + lws_filepos_t flen; + uint8_t *p; + + if (lws_tls_alloc_pem_to_der_file(vh->context, NULL, key_mem, + key_mem_len, &p, &flen)) { + lwsl_err("%s: couldn't use mem cert\n", __func__); + + return 1; + } + + n = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, vh->tls.ssl_client_ctx, p, + (long)(lws_intptr_t)flen); + if (n != 1) + n = SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_EC, + vh->tls.ssl_client_ctx, p, + (long)(lws_intptr_t)flen); + + lws_free_set_NULL(p); + + if (n != 1) { + lwsl_err("%s: unable to use key_mem\n", __func__); + + return 1; + } + } return 0; } diff --git a/lib/tls/private-network.h b/lib/tls/private-network.h index 0cb92321b..0dd3a838d 100644 --- a/lib/tls/private-network.h +++ b/lib/tls/private-network.h @@ -171,7 +171,10 @@ lws_tls_client_create_vhost_context(struct lws_vhost *vh, const char *cert_filepath, const void *cert_mem, unsigned int cert_mem_len, - const char *private_key_filepath); + const char *private_key_filepath, + const void *key_mem, + unsigned int key_mem_len); + LWS_EXTERN lws_tls_ctx * lws_tls_ctx_from_wsi(struct lws *wsi); diff --git a/lib/tls/tls-client.c b/lib/tls/tls-client.c index a3d455365..85e64ac6e 100644 --- a/lib/tls/tls-client.c +++ b/lib/tls/tls-client.c @@ -134,7 +134,10 @@ int lws_context_init_client_ssl(const struct lws_context_creation_info *info, cert_filepath, info->client_ssl_cert_mem, info->client_ssl_cert_mem_len, - private_key_filepath)) + private_key_filepath, + info->client_ssl_key_mem, + info->client_ssl_key_mem_len + )) return 1; lwsl_info("created client ssl context for %s\n", vhost->name);