From b06665b85122ca55ebab166e7e48c2f367fc40d0 Mon Sep 17 00:00:00 2001 From: Andy Green Date: Mon, 6 Nov 2017 06:28:55 +0800 Subject: [PATCH] mbedtls: improve SNI for client certs --- lib/private-libwebsockets.h | 3 +- lib/server/ssl-server.c | 2 +- lib/tls/mbedtls/server.c | 48 ++++++++++++++++--- lib/tls/mbedtls/wrapper/include/openssl/ssl.h | 3 ++ lib/tls/mbedtls/wrapper/library/ssl_x509.c | 22 +++++++++ lib/tls/mbedtls/wrapper/platform/ssl_pm.c | 21 ++++++-- lib/tls/openssl/server.c | 7 ++- 7 files changed, 89 insertions(+), 17 deletions(-) diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index 9ff8b111..cd93b804 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -2469,8 +2469,7 @@ lws_ssl_get_error_string(int status, int ret, char *buf, size_t len); */ LWS_EXTERN int -lws_tls_server_client_cert_verify_config(struct lws_context_creation_info *info, - struct lws_vhost *vh); +lws_tls_server_client_cert_verify_config(struct lws_vhost *vh); LWS_EXTERN int lws_tls_server_vhost_backend_init(struct lws_context_creation_info *info, struct lws_vhost *vhost, struct lws *wsi); diff --git a/lib/server/ssl-server.c b/lib/server/ssl-server.c index c480d336..ef8ba3d9 100644 --- a/lib/server/ssl-server.c +++ b/lib/server/ssl-server.c @@ -86,7 +86,7 @@ lws_context_init_server_ssl(struct lws_context_creation_info *info, if (lws_tls_server_vhost_backend_init(info, vhost, &wsi)) return -1; - lws_tls_server_client_cert_verify_config(info, vhost); + lws_tls_server_client_cert_verify_config(vhost); vhost->protocols[0].callback(&wsi, LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS, diff --git a/lib/tls/mbedtls/server.c b/lib/tls/mbedtls/server.c index 33efc87c..d351b0c3 100644 --- a/lib/tls/mbedtls/server.c +++ b/lib/tls/mbedtls/server.c @@ -23,20 +23,31 @@ #include int -lws_tls_server_client_cert_verify_config(struct lws_context_creation_info *info, - struct lws_vhost *vh) +lws_tls_server_client_cert_verify_config(struct lws_vhost *vh) { int verify_options = SSL_VERIFY_PEER; /* as a server, are we requiring clients to identify themselves? */ - - if (!lws_check_opt(info->options, - LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) + if (!lws_check_opt(vh->options, + LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) { + lwsl_notice("no client cert required\n"); return 0; + } - if (lws_check_opt(info->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED)) + /* + * The wrapper has this messed-up mapping: + * + * else if (ctx->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + * mode = MBEDTLS_SSL_VERIFY_OPTIONAL; + * + * ie the meaning is inverted. So where we should test for ! we don't + */ + if (lws_check_opt(vh->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED)) verify_options = SSL_VERIFY_FAIL_IF_NO_PEER_CERT; + lwsl_notice("%s: vh %s requires client cert %d\n", __func__, vh->name, + verify_options); + SSL_CTX_set_verify(vh->ssl_ctx, verify_options, NULL); return 0; @@ -78,7 +89,8 @@ lws_mbedtls_sni_cb(void *arg, mbedtls_ssl_context *mbedtls_ctx, return 0; } - lwsl_info("SNI: Found: %s:%d\n", servername, vh->listen_port); + lwsl_info("SNI: Found: %s:%d at vhost '%s'\n", servername, + vh->listen_port, vhost->name); /* select the ssl ctx from the selected vhost for this conn */ SSL_set_SSL_CTX(ssl, vhost->ssl_ctx); @@ -192,6 +204,8 @@ lws_tls_server_vhost_backend_init(struct lws_context_creation_info *info, struct lws_vhost *vhost, struct lws *wsi) { const SSL_METHOD *method = TLS_server_method(); + uint8_t *p; + lws_filepos_t flen; vhost->ssl_ctx = SSL_CTX_new(method); /* create context */ if (!vhost->ssl_ctx) { @@ -202,6 +216,26 @@ lws_tls_server_vhost_backend_init(struct lws_context_creation_info *info, if (!vhost->use_ssl || !info->ssl_cert_filepath) return 0; + if (info->ssl_ca_filepath) { + lwsl_notice("%s: vh %s: loading CA filepath %s\n", __func__, + vhost->name, info->ssl_ca_filepath); + if (lws_tls_alloc_pem_to_der_file(vhost->context, + info->ssl_ca_filepath, NULL, 0, &p, &flen)) { + lwsl_err("couldn't find client CA file %s\n", + info->ssl_ca_filepath); + + return 1; + } + + if (SSL_CTX_add_client_CA_ASN1(vhost->ssl_ctx, (int)flen, p) != 1) { + lwsl_err("%s: SSL_CTX_add_client_CA_ASN1 unhappy\n", + __func__); + free(p); + return 1; + } + free(p); + } + return lws_tls_server_certs_load(vhost, wsi, info->ssl_cert_filepath, info->ssl_private_key_filepath, diff --git a/lib/tls/mbedtls/wrapper/include/openssl/ssl.h b/lib/tls/mbedtls/wrapper/include/openssl/ssl.h index 232a6ee6..a6f950fb 100755 --- a/lib/tls/mbedtls/wrapper/include/openssl/ssl.h +++ b/lib/tls/mbedtls/wrapper/include/openssl/ssl.h @@ -46,6 +46,9 @@ void SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx); + int SSL_CTX_add_client_CA_ASN1(SSL_CTX *ssl, int len, + const unsigned char *d); + SSL *SSL_SSL_from_mbedtls_ssl_context(mbedtls_ssl_context *msc); /** diff --git a/lib/tls/mbedtls/wrapper/library/ssl_x509.c b/lib/tls/mbedtls/wrapper/library/ssl_x509.c index 4441490a..f3995a11 100644 --- a/lib/tls/mbedtls/wrapper/library/ssl_x509.c +++ b/lib/tls/mbedtls/wrapper/library/ssl_x509.c @@ -166,6 +166,28 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) return 1; } +/** + * @brief add CA client certification into the SSL + */ +int SSL_CTX_add_client_CA_ASN1(SSL_CTX *ctx, int len, + const unsigned char *d) +{ + X509 *x; + + x = d2i_X509(NULL, d, len); + if (!x) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "d2i_X509() return NULL"); + return 0; + } + SSL_ASSERT1(ctx); + + X509_free(ctx->client_CA); + + ctx->client_CA = x; + + return 1; +} + /** * @brief add CA client certification into the SSL */ diff --git a/lib/tls/mbedtls/wrapper/platform/ssl_pm.c b/lib/tls/mbedtls/wrapper/platform/ssl_pm.c index e14173b1..8445bfe8 100755 --- a/lib/tls/mbedtls/wrapper/platform/ssl_pm.c +++ b/lib/tls/mbedtls/wrapper/platform/ssl_pm.c @@ -823,17 +823,32 @@ void SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) { struct ssl_pm *ssl_pm = ssl->ssl_pm; struct x509_pm *x509_pm = (struct x509_pm *)ctx->cert->x509->x509_pm; + struct x509_pm *x509_pm_ca = (struct x509_pm *)ctx->client_CA->x509_pm; + struct pkey_pm *pkey_pm = (struct pkey_pm *)ctx->cert->pkey->pkey_pm; + int mode; if (ssl->cert) ssl_cert_free(ssl->cert); ssl->ctx = ctx; ssl->cert = __ssl_cert_new(ctx->cert); + if (ctx->verify_mode == SSL_VERIFY_PEER) + mode = MBEDTLS_SSL_VERIFY_REQUIRED; + else if (ctx->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + mode = MBEDTLS_SSL_VERIFY_OPTIONAL; + else if (ctx->verify_mode == SSL_VERIFY_CLIENT_ONCE) + mode = MBEDTLS_SSL_VERIFY_UNSET; + else + mode = MBEDTLS_SSL_VERIFY_NONE; + + // printf("ssl: %p, client ca x509_crt %p, mbedtls mode %d\n", ssl, x509_pm_ca->x509_crt, mode); + /* apply new ctx cert to ssl */ - mbedtls_ssl_set_hs_own_cert(&ssl_pm->ssl, x509_pm->x509_crt, pkey_pm->pkey); - mbedtls_ssl_set_hs_authmode(&ssl_pm->ssl, MBEDTLS_SSL_VERIFY_NONE); - mbedtls_ssl_set_hs_ca_chain(&ssl_pm->ssl, x509_pm->x509_crt, NULL); + ssl->verify_mode = ctx->verify_mode; + mbedtls_ssl_set_hs_ca_chain(&ssl_pm->ssl, x509_pm_ca->x509_crt, NULL); + mbedtls_ssl_set_hs_own_cert(&ssl_pm->ssl, x509_pm->x509_crt, pkey_pm->pkey); + mbedtls_ssl_set_hs_authmode(&ssl_pm->ssl, mode); } diff --git a/lib/tls/openssl/server.c b/lib/tls/openssl/server.c index d04073e9..f4a62b47 100644 --- a/lib/tls/openssl/server.c +++ b/lib/tls/openssl/server.c @@ -58,18 +58,17 @@ OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) } int -lws_tls_server_client_cert_verify_config(struct lws_context_creation_info *info, - struct lws_vhost *vh) +lws_tls_server_client_cert_verify_config(struct lws_vhost *vh) { int verify_options = SSL_VERIFY_PEER; /* as a server, are we requiring clients to identify themselves? */ - if (!lws_check_opt(info->options, + if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT)) return 0; - if (!lws_check_opt(info->options, + if (!lws_check_opt(vh->options, LWS_SERVER_OPTION_PEER_CERT_NOT_REQUIRED)) verify_options |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;