diff --git a/lib/lejp-conf.c b/lib/lejp-conf.c index 531f93be..6fc358fe 100644 --- a/lib/lejp-conf.c +++ b/lib/lejp-conf.c @@ -95,6 +95,10 @@ static const char * const paths_vhosts[] = { "vhosts[].mounts[].pmo[].*", "vhosts[].headers[].*", "vhosts[].headers[]", + "vhosts[].client-ssl-key", + "vhosts[].client-ssl-cert", + "vhosts[].client-ssl-ca", + "vhosts[].client-ssl-ciphers", }; enum lejp_vhost_paths { @@ -137,6 +141,10 @@ enum lejp_vhost_paths { LEJPVP_PMO, LEJPVP_HEADERS_NAME, LEJPVP_HEADERS, + LEJPVP_CLIENT_SSL_KEY, + LEJPVP_CLIENT_SSL_CERT, + LEJPVP_CLIENT_SSL_CA, + LEJPVP_CLIENT_CIPHERS, }; static const char * const parser_errs[] = { @@ -313,6 +321,22 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) a->info->ssl_cert_filepath = NULL; a->info->ssl_private_key_filepath = NULL; a->info->ssl_ca_filepath = NULL; + a->info->client_ssl_cert_filepath = NULL; + a->info->client_ssl_private_key_filepath = NULL; + a->info->client_ssl_ca_filepath = NULL; + a->info->client_ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:" + "ECDHE-RSA-AES256-GCM-SHA384:" + "DHE-RSA-AES256-GCM-SHA384:" + "ECDHE-RSA-AES256-SHA384:" + "HIGH:!aNULL:!eNULL:!EXPORT:" + "!DES:!MD5:!PSK:!RC4:!HMAC_SHA1:" + "!SHA1:!DHE-RSA-AES128-GCM-SHA256:" + "!DHE-RSA-AES128-SHA256:" + "!AES128-GCM-SHA256:" + "!AES128-SHA256:" + "!DHE-RSA-AES256-SHA256:" + "!AES256-GCM-SHA384:" + "!AES256-SHA256"; a->info->timeout_secs = 5; a->info->ssl_cipher_list = "ECDHE-ECDSA-AES256-GCM-SHA384:" "ECDHE-RSA-AES256-GCM-SHA384:" @@ -406,7 +430,15 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) a->any_vhosts = 1; if (a->enable_client_ssl) { + const char *cert_filepath = a->info->client_ssl_cert_filepath; + const char *private_key_filepath = a->info->client_ssl_private_key_filepath; + const char *ca_filepath = a->info->client_ssl_ca_filepath; + const char *cipher_list = a->info->client_ssl_cipher_list; memset(a->info, 0, sizeof(*a->info)); + a->info->client_ssl_cert_filepath = cert_filepath; + a->info->client_ssl_private_key_filepath = private_key_filepath; + a->info->client_ssl_ca_filepath = ca_filepath; + a->info->client_ssl_cipher_list = cipher_list; a->info->options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT; lws_init_vhost_client_ssl(a->info, vhost); } @@ -538,6 +570,9 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) case LEJPVP_KEEPALIVE_TIMEOUT: a->info->keepalive_timeout = atoi(ctx->buf); return 0; + case LEJPVP_CLIENT_CIPHERS: + a->info->client_ssl_cipher_list = a->p; + break; case LEJPVP_CIPHERS: a->info->ssl_cipher_list = a->p; break; @@ -613,6 +648,15 @@ lejp_vhosts_cb(struct lejp_ctx *ctx, char reason) case LEJPVP_ENABLE_CLIENT_SSL: a->enable_client_ssl = arg_to_bool(ctx->buf); return 0; + case LEJPVP_CLIENT_SSL_KEY: + a->info->client_ssl_private_key_filepath = a->p; + break; + case LEJPVP_CLIENT_SSL_CERT: + a->info->client_ssl_cert_filepath = a->p; + break; + case LEJPVP_CLIENT_SSL_CA: + a->info->client_ssl_ca_filepath = a->p; + break; case LEJPVP_NOIPV6: if (arg_to_bool(ctx->buf)) diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 3120bc84..89becac8 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -1870,6 +1870,29 @@ struct lws_context_creation_info { * succeeded to create. */ +#ifdef LWS_OPENSSL_SUPPORT + /**< CONTEXT: NULL or struct lws_token_limits pointer which is initialized + * with a token length limit for each possible WSI_TOKEN_ */ + const char *client_ssl_private_key_password; + /**< VHOST: NULL or the passphrase needed for the private key */ + const char *client_ssl_cert_filepath; + /**< VHOST: If libwebsockets was compiled to use ssl, and you want + * to listen using SSL, set to the filepath to fetch the + * server cert from, otherwise NULL for unencrypted */ + const char *client_ssl_private_key_filepath; + /**< VHOST: filepath to private key if wanting SSL mode; + * if this is set to NULL but sll_cert_filepath is set, the + * OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY callback is called + * to allow setting of the private key directly via openSSL + * library calls */ + const char *client_ssl_ca_filepath; + /**< VHOST: CA certificate filepath or NULL */ + const char *client_ssl_cipher_list; + /**< VHOST: List of valid ciphers to use (eg, + * "RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL" + * or you can leave it as NULL to get "DEFAULT" */ +#endif + /* Add new things just above here ---^ * This is part of the ABI, don't needlessly break compatibility * diff --git a/lib/ssl-client.c b/lib/ssl-client.c index 6c3c7095..102a4d3e 100644 --- a/lib/ssl-client.c +++ b/lib/ssl-client.c @@ -479,9 +479,9 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info, #endif SSL_CTX_set_options(vhost->ssl_client_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); - if (info->ssl_cipher_list) + if (info->client_ssl_cipher_list) SSL_CTX_set_cipher_list(vhost->ssl_client_ctx, - info->ssl_cipher_list); + info->client_ssl_cipher_list); #ifdef LWS_SSL_CLIENT_USE_OS_CA_CERTS if (!lws_check_opt(info->options, LWS_SERVER_OPTION_DISABLE_OS_CA_CERTS)) @@ -490,7 +490,7 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info, #endif /* openssl init for cert verification (for client sockets) */ - if (!info->ssl_ca_filepath) { + if (!info->client_ssl_ca_filepath) { if (!SSL_CTX_load_verify_locations( vhost->ssl_client_ctx, NULL, LWS_OPENSSL_CLIENT_CERTS)) @@ -501,12 +501,12 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info, "going to work\n", LWS_OPENSSL_CLIENT_CERTS); } else if (!SSL_CTX_load_verify_locations( - vhost->ssl_client_ctx, info->ssl_ca_filepath, + vhost->ssl_client_ctx, info->client_ssl_ca_filepath, NULL)) { lwsl_err( "Unable to load SSL Client certs " "file from %s -- client ssl isn't " - "going to work\n", info->ssl_ca_filepath); + "going to work\n", info->client_ssl_ca_filepath); lws_ssl_elaborate_error(); } else @@ -518,32 +518,32 @@ int lws_context_init_client_ssl(struct lws_context_creation_info *info, */ /* support for client-side certificate authentication */ - if (info->ssl_cert_filepath) { + if (info->client_ssl_cert_filepath) { lwsl_notice("%s: doing cert filepath\n", __func__); n = SSL_CTX_use_certificate_chain_file(vhost->ssl_client_ctx, - info->ssl_cert_filepath); + info->client_ssl_cert_filepath); if (n < 1) { lwsl_err("problem %d getting cert '%s'\n", n, - info->ssl_cert_filepath); + info->client_ssl_cert_filepath); lws_ssl_elaborate_error(); return 1; } - lwsl_notice("Loaded client cert %s\n", info->ssl_cert_filepath); + lwsl_notice("Loaded client cert %s\n", info->client_ssl_cert_filepath); } - if (info->ssl_private_key_filepath) { + if (info->client_ssl_private_key_filepath) { lwsl_notice("%s: doing private key filepath\n", __func__); lws_ssl_bind_passphrase(vhost->ssl_client_ctx, info); /* set the private key from KeyFile */ if (SSL_CTX_use_PrivateKey_file(vhost->ssl_client_ctx, - info->ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { + info->client_ssl_private_key_filepath, SSL_FILETYPE_PEM) != 1) { lwsl_err("use_PrivateKey_file '%s'\n", - info->ssl_private_key_filepath); + info->client_ssl_private_key_filepath); lws_ssl_elaborate_error(); return 1; } lwsl_notice("Loaded client cert private key %s\n", - info->ssl_private_key_filepath); + info->client_ssl_private_key_filepath); /* verify private key */ if (!SSL_CTX_check_private_key(vhost->ssl_client_ctx)) {