From 679397c62265a5ee93953d0913dc834b163a5aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Uhliarik?= Date: Wed, 22 May 2024 22:23:08 +0200 Subject: [PATCH 3/3] Add SSL passphrase dialog --- contrib/vim/syntax/nginx.vim | 1 + src/event/ngx_event_openssl.c | 126 +++++++++++++++++++++-- src/event/ngx_event_openssl.h | 14 ++- src/http/modules/ngx_http_grpc_module.c | 2 +- src/http/modules/ngx_http_proxy_module.c | 2 +- src/http/modules/ngx_http_ssl_module.c | 70 ++++++++++++- src/http/modules/ngx_http_ssl_module.h | 2 + src/http/modules/ngx_http_uwsgi_module.c | 2 +- src/mail/ngx_mail_ssl_module.c | 66 +++++++++++- src/mail/ngx_mail_ssl_module.h | 2 + src/stream/ngx_stream_proxy_module.c | 2 +- src/stream/ngx_stream_ssl_module.c | 61 ++++++++++- src/stream/ngx_stream_ssl_module.h | 2 + 13 files changed, 335 insertions(+), 17 deletions(-) diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 29eef7a..e7227eb 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -593,6 +593,7 @@ syn keyword ngxDirective contained ssl_ocsp syn keyword ngxDirective contained ssl_ocsp_cache syn keyword ngxDirective contained ssl_ocsp_responder syn keyword ngxDirective contained ssl_password_file +syn keyword ngxDirective contained ssl_pass_phrase_dialog syn keyword ngxDirective contained ssl_prefer_server_ciphers syn keyword ngxDirective contained ssl_preread syn keyword ngxDirective contained ssl_protocols diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 89f277f..6f7f2a2 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -11,6 +11,7 @@ #define NGX_SSL_PASSWORD_BUFFER_SIZE 4096 +#define NGX_PASS_PHRASE_ARG_MAX_LEN 255 typedef struct { @@ -21,7 +22,7 @@ typedef struct { static X509 *ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, ngx_str_t *cert, STACK_OF(X509) **chain); static EVP_PKEY *ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err, - ngx_str_t *key, ngx_array_t *passwords); + ngx_str_t *key, ngx_array_t *passwords, ngx_ssl_ppdialog_conf_t *dlg); static int ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata); static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); @@ -85,6 +86,12 @@ static time_t ngx_ssl_parse_time( #endif ASN1_TIME *asn1time, ngx_log_t *log); +static int ngx_ssl_read_pstream(const char *cmd, char *buf, + ngx_int_t bufsize); + +static int ngx_ssl_pass_phrase_callback(char *buf, int bufsize, + int rwflag, void *u); + static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_openssl_exit(ngx_cycle_t *cycle); @@ -432,7 +439,7 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data) ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs, - ngx_array_t *keys, ngx_array_t *passwords) + ngx_array_t *keys, ngx_array_t *passwords, ngx_ssl_ppdialog_conf_t *dlg) { ngx_str_t *cert, *key; ngx_uint_t i; @@ -442,7 +449,7 @@ ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs, for (i = 0; i < certs->nelts; i++) { - if (ngx_ssl_certificate(cf, ssl, &cert[i], &key[i], passwords) + if (ngx_ssl_certificate(cf, ssl, &cert[i], &key[i], passwords, dlg) != NGX_OK) { return NGX_ERROR; @@ -455,12 +462,13 @@ ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *certs, ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, - ngx_str_t *key, ngx_array_t *passwords) + ngx_str_t *key, ngx_array_t *passwords, ngx_ssl_ppdialog_conf_t *dlg) { char *err; X509 *x509; EVP_PKEY *pkey; STACK_OF(X509) *chain; + EVP_PKEY *pubkey; x509 = ngx_ssl_load_certificate(cf->pool, &err, cert, &chain); if (x509 == NULL) { @@ -550,8 +558,23 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, } #endif - pkey = ngx_ssl_load_certificate_key(cf->pool, &err, key, passwords); - if (pkey == NULL) { + pubkey = X509_get_pubkey(x509); + if (!pubkey) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_get_pubkey() failed"); + return NGX_ERROR; + } + + if (dlg) { + dlg->cryptosystem = EVP_PKEY_get_base_id(pubkey); + } + + EVP_PKEY_free(pubkey); + + pkey = ngx_ssl_load_certificate_key(cf->pool, &err, key, passwords, dlg); + if (ngx_test_config) { + return NGX_OK; + } else if (pkey == NULL) { if (err != NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "cannot load certificate key \"%s\": %s", @@ -621,7 +644,7 @@ ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, #endif - pkey = ngx_ssl_load_certificate_key(pool, &err, key, passwords); + pkey = ngx_ssl_load_certificate_key(pool, &err, key, passwords, NULL); if (pkey == NULL) { if (err != NULL) { ngx_ssl_error(NGX_LOG_ERR, c->log, 0, @@ -734,10 +757,82 @@ ngx_ssl_load_certificate(ngx_pool_t *pool, char **err, ngx_str_t *cert, return x509; } +static int +ngx_ssl_read_pstream(const char *cmd, char *buf, ngx_int_t bufsize) +{ + FILE *fp; + ngx_int_t i; + char c; + + fp = popen(cmd, "r"); + if (fp == NULL) { + return -1; + } + + for (i = 0; (c = fgetc(fp)) != EOF && + (i < bufsize - 1); i++) { + + if (c == '\n' || c == '\r'){ + break; + } + + buf[i] = c; + } + buf[i] = '\0'; + + pclose(fp); + + return 0; +} + +static int +ngx_ssl_pass_phrase_callback(char *buf, int bufsize, int rwflag, void *u) +{ + u_char cmd[NGX_PASS_PHRASE_ARG_MAX_LEN + 1] = {0}; + u_char *cmd_end; + ngx_ssl_ppdialog_conf_t *dlg = (ngx_ssl_ppdialog_conf_t *)u; + ngx_str_t *pass_phrase_dialog = dlg->data; + char cryptosystem[4] = {0}; + int ret; + + /* remove exec: str from pass_phrase_dialog */ + pass_phrase_dialog->data = pass_phrase_dialog->data + 5; + pass_phrase_dialog->len = pass_phrase_dialog->len - 5; + + switch (dlg->cryptosystem){ + case EVP_PKEY_RSA: + strncpy(cryptosystem, "RSA", 4); + break; + case EVP_PKEY_DSA: + strncpy(cryptosystem, "DSA", 4); + break; + case EVP_PKEY_EC: + strncpy(cryptosystem, "EC", 3); + break; + case EVP_PKEY_DH: + strncpy(cryptosystem, "DH", 3); + break; + default: + strncpy(cryptosystem, "UNK", 4); + break; + } + + cmd_end = ngx_snprintf(cmd, NGX_PASS_PHRASE_ARG_MAX_LEN, "%V %V %s", + pass_phrase_dialog, dlg->server, cryptosystem); + *cmd_end = '\0'; + + ngx_log_stderr(0, "Executing external script: %s\n", cmd); + + if ((ret = ngx_ssl_read_pstream((char *)cmd, buf, bufsize)) != 0){ + return -1; + } + + return strlen(buf); +} static EVP_PKEY * ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err, - ngx_str_t *key, ngx_array_t *passwords) + ngx_str_t *key, ngx_array_t *passwords, ngx_ssl_ppdialog_conf_t *dlg) { BIO *bio; EVP_PKEY *pkey; @@ -825,6 +920,21 @@ ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err, tries = 1; pwd = NULL; cb = NULL; + + /** directive format: ssl_pass_phrase_dialog builtin|exec:filepath */ + if (dlg && ngx_strncasecmp(dlg->data->data, (u_char *)"exec:", 5) == 0){ + pwd = (void *)dlg; + cb = ngx_ssl_pass_phrase_callback; + } else { + pwd = NULL; + cb = NULL; + } + } + + /* skip decrypting private keys in config test phase to avoid + asking for pass phase twice */ + if (ngx_test_config){ + return NULL; } for ( ;; ) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index ebb2c35..761f48d 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -82,9 +82,19 @@ #define ERR_peek_error_data(d, f) ERR_peek_error_line_data(NULL, NULL, d, f) #endif +#define NGX_SSL_PASS_PHRASE_ARG_MAX_LEN 255 +#define NGX_SSL_PASS_PHRASE_DEFAULT_VAL "builtin" +#define NGX_SSL_SERVER_NULL "undefined" typedef struct ngx_ssl_ocsp_s ngx_ssl_ocsp_t; +typedef struct ngx_ssl_ppdialog_conf_s ngx_ssl_ppdialog_conf_t; + +struct ngx_ssl_ppdialog_conf_s { + ngx_str_t *data; + ngx_str_t *server; + ngx_int_t cryptosystem; +}; struct ngx_ssl_s { SSL_CTX *ctx; @@ -192,9 +202,9 @@ ngx_int_t ngx_ssl_init(ngx_log_t *log); ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data); ngx_int_t ngx_ssl_certificates(ngx_conf_t *cf, ngx_ssl_t *ssl, - ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords); + ngx_array_t *certs, ngx_array_t *keys, ngx_array_t *passwords, ngx_ssl_ppdialog_conf_t *dlg); ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, - ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); + ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords, ngx_ssl_ppdialog_conf_t *dlg); ngx_int_t ngx_ssl_connection_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c index dfe49c5..904263d 100644 --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -4983,7 +4983,7 @@ ngx_http_grpc_set_ssl(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *glcf) if (ngx_ssl_certificate(cf, glcf->upstream.ssl, &glcf->upstream.ssl_certificate->value, &glcf->upstream.ssl_certificate_key->value, - glcf->upstream.ssl_passwords) + glcf->upstream.ssl_passwords, NULL) != NGX_OK) { return NGX_ERROR; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 9cc202c..2c938d7 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -5032,7 +5032,7 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf) if (ngx_ssl_certificate(cf, plcf->upstream.ssl, &plcf->upstream.ssl_certificate->value, &plcf->upstream.ssl_certificate_key->value, - plcf->upstream.ssl_passwords) + plcf->upstream.ssl_passwords, NULL) != NGX_OK) { return NGX_ERROR; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 1c92d9f..35132b9 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -21,6 +21,8 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" +static ngx_str_t ngx_ssl_server_null = ngx_string(NGX_SSL_SERVER_NULL); + #define NGX_HTTP_ALPN_PROTOS "\x08http/1.1\x08http/1.0\x08http/0.9" @@ -59,6 +61,9 @@ static ngx_int_t ngx_http_ssl_quic_compat_init(ngx_conf_t *cf, ngx_http_conf_addr_t *addr); #endif +static char *ngx_conf_set_pass_phrase_dialog(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = { { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, @@ -290,6 +295,13 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, reject_handshake), NULL }, + { ngx_string("ssl_pass_phrase_dialog"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_pass_phrase_dialog, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, pass_phrase_dialog), + NULL }, + ngx_null_command }; @@ -609,6 +621,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) * sscf->ocsp_responder = { 0, NULL }; * sscf->stapling_file = { 0, NULL }; * sscf->stapling_responder = { 0, NULL }; + * sscf->pass_phrase_dialog = NULL; */ sscf->prefer_server_ciphers = NGX_CONF_UNSET; @@ -639,6 +652,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) { ngx_http_ssl_srv_conf_t *prev = parent; ngx_http_ssl_srv_conf_t *conf = child; + ngx_http_core_srv_conf_t *cscf; + ngx_ssl_ppdialog_conf_t dlg; ngx_pool_cleanup_t *cln; @@ -694,6 +709,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_str_value(conf->stapling_responder, prev->stapling_responder, ""); + ngx_conf_merge_str_value(conf->pass_phrase_dialog, + prev->pass_phrase_dialog, NGX_SSL_PASS_PHRASE_DEFAULT_VAL); + conf->ssl.log = cf->log; if (conf->certificates) { @@ -726,6 +744,30 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; + /** directive format: ssl_pass_phrase_dialog builtin|exec:filepath */ + if (ngx_strncasecmp(conf->pass_phrase_dialog.data, (u_char *)"exec:", 5) == 0){ + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "ssl_pass_phrase_dialog config directive SET: %s ", conf->pass_phrase_dialog.data); + } else if (ngx_strncasecmp(conf->pass_phrase_dialog.data, (u_char *)NGX_SSL_PASS_PHRASE_DEFAULT_VAL, + sizeof(NGX_SSL_PASS_PHRASE_DEFAULT_VAL)) != 0){ + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "ssl_pass_phrase_dialog config directive accepts only the following " + "values: %s | exec:filepath", NGX_SSL_PASS_PHRASE_DEFAULT_VAL); + + return NGX_CONF_ERROR; + } + + cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); + + dlg.data = &conf->pass_phrase_dialog; + if (cscf->server_name.len != 0) { + dlg.server = &cscf->server_name; + } else { + dlg.server = &ngx_ssl_server_null; + } + + #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx, @@ -776,7 +818,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) /* configure certificates */ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, - conf->certificate_keys, conf->passwords) + conf->certificate_keys, conf->passwords, &dlg) != NGX_OK) { return NGX_CONF_ERROR; @@ -1329,6 +1371,32 @@ ngx_http_ssl_init(ngx_conf_t *cf) return NGX_OK; } +static char * +ngx_conf_set_pass_phrase_dialog(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_ssl_srv_conf_t *sscf = conf; + ngx_str_t *value; + + if (sscf->pass_phrase_dialog.data){ + return "is duplicate"; + } + + value = cf->args->elts; + + sscf->pass_phrase_dialog = value[1]; + + if (sscf->pass_phrase_dialog.len == 0) { + return NGX_CONF_OK; + } else if (sscf->pass_phrase_dialog.len > NGX_SSL_PASS_PHRASE_ARG_MAX_LEN) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "ssl_pass_phrase_dialog argument length exceeded maximum possible length: %d", + NGX_SSL_PASS_PHRASE_ARG_MAX_LEN); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} #if (NGX_QUIC_OPENSSL_COMPAT) diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index c69c8ff..79f1506 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -62,6 +62,8 @@ typedef struct { ngx_flag_t stapling_verify; ngx_str_t stapling_file; ngx_str_t stapling_responder; + + ngx_str_t pass_phrase_dialog; } ngx_http_ssl_srv_conf_t; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c index c1731ff..ab9d98a 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -2567,7 +2567,7 @@ ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) if (ngx_ssl_certificate(cf, uwcf->upstream.ssl, &uwcf->upstream.ssl_certificate->value, &uwcf->upstream.ssl_certificate_key->value, - uwcf->upstream.ssl_passwords) + uwcf->upstream.ssl_passwords, NULL) != NGX_OK) { return NGX_ERROR; diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c index aebb4cc..5d95f44 100644 --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -13,6 +13,7 @@ #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" +static ngx_str_t ngx_ssl_server_null = ngx_string(NGX_SSL_SERVER_NULL); #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation static int ngx_mail_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, @@ -33,6 +34,8 @@ static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_mail_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data); +static char *ngx_conf_set_pass_phrase_dialog(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_conf_enum_t ngx_mail_starttls_state[] = { { ngx_string("off"), NGX_MAIL_STARTTLS_OFF }, @@ -202,6 +205,13 @@ static ngx_command_t ngx_mail_ssl_commands[] = { offsetof(ngx_mail_ssl_conf_t, conf_commands), &ngx_mail_ssl_conf_command_post }, + { ngx_string("ssl_pass_phrase_dialog"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_pass_phrase_dialog, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, pass_phrase_dialog), + NULL }, + ngx_null_command }; @@ -330,6 +340,8 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) { ngx_mail_ssl_conf_t *prev = parent; ngx_mail_ssl_conf_t *conf = child; + ngx_mail_core_srv_conf_t *cscf; + ngx_ssl_ppdialog_conf_t dlg; char *mode; ngx_pool_cleanup_t *cln; @@ -372,6 +384,8 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->conf_commands, prev->conf_commands, NULL); + ngx_conf_merge_str_value(conf->pass_phrase_dialog, + prev->pass_phrase_dialog, NGX_SSL_PASS_PHRASE_DEFAULT_VAL); conf->ssl.log = cf->log; @@ -430,6 +444,29 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; + /** directive format: ssl_pass_phrase_dialog builtin|exec:filepath */ + if (ngx_strncasecmp(conf->pass_phrase_dialog.data, (u_char *)"exec:", 5) == 0){ + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "ssl_pass_phrase_dialog config directive SET: %s ", conf->pass_phrase_dialog.data); + } else if (ngx_strncasecmp(conf->pass_phrase_dialog.data, (u_char *)NGX_SSL_PASS_PHRASE_DEFAULT_VAL, + sizeof(NGX_SSL_PASS_PHRASE_DEFAULT_VAL)) != 0){ + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "ssl_pass_phrase_dialog config directive accepts only the following " + "values: %s | exec:filepath", NGX_SSL_PASS_PHRASE_DEFAULT_VAL); + + return NGX_CONF_ERROR; + } + + cscf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_core_module); + + dlg.data = &conf->pass_phrase_dialog; + if (cscf->server_name.len != 0) { + dlg.server = &cscf->server_name; + } else { + dlg.server = &ngx_ssl_server_null; + } + #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation SSL_CTX_set_alpn_select_cb(conf->ssl.ctx, ngx_mail_ssl_alpn_select, NULL); #endif @@ -442,7 +479,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) } if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, - conf->certificate_keys, conf->passwords) + conf->certificate_keys, conf->passwords, &dlg) != NGX_OK) { return NGX_CONF_ERROR; @@ -692,3 +729,30 @@ ngx_mail_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data) return NGX_CONF_OK; #endif } + +static char * +ngx_conf_set_pass_phrase_dialog(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_ssl_conf_t *sscf = conf; + ngx_str_t *value; + + if (sscf->pass_phrase_dialog.data){ + return "is duplicate"; + } + + value = cf->args->elts; + + sscf->pass_phrase_dialog = value[1]; + + if (sscf->pass_phrase_dialog.len == 0) { + return NGX_CONF_OK; + } else if (sscf->pass_phrase_dialog.len > NGX_SSL_PASS_PHRASE_ARG_MAX_LEN) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "ssl_pass_phrase_dialog argument length exceeded maximum possible length: %d", + NGX_SSL_PASS_PHRASE_ARG_MAX_LEN); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h index c0eb6a3..02b4d4f 100644 --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -56,6 +56,8 @@ typedef struct { u_char *file; ngx_uint_t line; + + ngx_str_t pass_phrase_dialog; } ngx_mail_ssl_conf_t; diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index ed275c0..1747aed 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -2305,7 +2305,7 @@ ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf) if (ngx_ssl_certificate(cf, pscf->ssl, &pscf->ssl_certificate->value, &pscf->ssl_certificate_key->value, - pscf->ssl_passwords) + pscf->ssl_passwords, NULL) != NGX_OK) { return NGX_ERROR; diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index ba44477..43cd7e0 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -17,6 +17,8 @@ typedef ngx_int_t (*ngx_ssl_variable_handler_pt)(ngx_connection_t *c, #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" +#define NGX_SSL_STREAM_NAME "NGX_STREAM_SSL_MODULE" +static ngx_str_t ngx_ssl_stream_default_name = ngx_string(NGX_SSL_STREAM_NAME); static ngx_int_t ngx_stream_ssl_handler(ngx_stream_session_t *s); static ngx_int_t ngx_stream_ssl_init_connection(ngx_ssl_t *ssl, @@ -57,6 +59,9 @@ static char *ngx_stream_ssl_alpn(ngx_conf_t *cf, ngx_command_t *cmd, static char *ngx_stream_ssl_conf_command_check(ngx_conf_t *cf, void *post, void *data); +static char *ngx_conf_set_pass_phrase_dialog(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static ngx_int_t ngx_stream_ssl_init(ngx_conf_t *cf); @@ -233,6 +238,13 @@ static ngx_command_t ngx_stream_ssl_commands[] = { 0, NULL }, + { ngx_string("ssl_pass_phrase_dialog"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_pass_phrase_dialog, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_srv_conf_t, pass_phrase_dialog), + NULL }, + ngx_null_command }; @@ -802,6 +814,7 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) { ngx_stream_ssl_srv_conf_t *prev = parent; ngx_stream_ssl_srv_conf_t *conf = child; + ngx_ssl_ppdialog_conf_t dlg; ngx_pool_cleanup_t *cln; @@ -846,6 +859,8 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->conf_commands, prev->conf_commands, NULL); + ngx_conf_merge_str_value(conf->pass_phrase_dialog, + prev->pass_phrase_dialog, NGX_SSL_PASS_PHRASE_DEFAULT_VAL); conf->ssl.log = cf->log; @@ -879,6 +894,23 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) cln->handler = ngx_ssl_cleanup_ctx; cln->data = &conf->ssl; + /** directive format: ssl_pass_phrase_dialog builtin|exec:filepath */ + if (ngx_strncasecmp(conf->pass_phrase_dialog.data, (u_char *)"exec:", 5) == 0){ + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "ssl_pass_phrase_dialog config directive SET: %s ", conf->pass_phrase_dialog.data); + } else if (ngx_strncasecmp(conf->pass_phrase_dialog.data, (u_char *)NGX_SSL_PASS_PHRASE_DEFAULT_VAL, + sizeof(NGX_SSL_PASS_PHRASE_DEFAULT_VAL)) != 0){ + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "ssl_pass_phrase_dialog config directive accepts only the following " + "values: %s | exec:filepath", NGX_SSL_PASS_PHRASE_DEFAULT_VAL); + + return NGX_CONF_ERROR; + } + + dlg.data = &conf->pass_phrase_dialog; + dlg.server = &ngx_ssl_stream_default_name; + #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx, ngx_stream_ssl_servername); @@ -923,7 +955,7 @@ ngx_stream_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) /* configure certificates */ if (ngx_ssl_certificates(cf, &conf->ssl, conf->certificates, - conf->certificate_keys, conf->passwords) + conf->certificate_keys, conf->passwords, &dlg) != NGX_OK) { return NGX_CONF_ERROR; @@ -1371,3 +1403,30 @@ ngx_stream_ssl_init(ngx_conf_t *cf) return NGX_OK; } + +static char * +ngx_conf_set_pass_phrase_dialog(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_stream_ssl_srv_conf_t *sscf = conf; + ngx_str_t *value; + + if (sscf->pass_phrase_dialog.data){ + return "is duplicate"; + } + + value = cf->args->elts; + + sscf->pass_phrase_dialog = value[1]; + + if (sscf->pass_phrase_dialog.len == 0) { + return NGX_CONF_OK; + } else if (sscf->pass_phrase_dialog.len > NGX_SSL_PASS_PHRASE_ARG_MAX_LEN) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "ssl_pass_phrase_dialog argument length exceeded maximum possible length: %d", + NGX_SSL_PASS_PHRASE_ARG_MAX_LEN); + + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/stream/ngx_stream_ssl_module.h b/src/stream/ngx_stream_ssl_module.h index 6f6d9ae..870640d 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -53,6 +53,8 @@ typedef struct { ngx_flag_t session_tickets; ngx_array_t *session_ticket_keys; + + ngx_str_t pass_phrase_dialog; } ngx_stream_ssl_srv_conf_t; -- 2.44.0