From a8cae4e95ba8b5f38c68f23502f1603af8a76c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Uhliarik?= Date: Thu, 23 May 2024 16:18:35 +0200 Subject: [PATCH] Add ssl-pass-phrase-dialog --- contrib/vim/syntax/nginx.vim | 1 + src/event/ngx_event_openssl.c | 133 ++++++++++++++++++++--- src/event/ngx_event_openssl.h | 15 ++- 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 | 76 ++++++++++++- 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 | 68 +++++++++++- src/mail/ngx_mail_ssl_module.h | 2 + src/stream/ngx_stream_proxy_module.c | 2 +- src/stream/ngx_stream_ssl_module.c | 62 ++++++++++- src/stream/ngx_stream_ssl_module.h | 2 + 13 files changed, 344 insertions(+), 25 deletions(-) diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 7d587fc..15b21e2 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim @@ -617,6 +617,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 7b69f3f..3519831 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -9,9 +9,8 @@ #include #include - #define NGX_SSL_PASSWORD_BUFFER_SIZE 4096 - +#define NGX_PASS_PHRASE_ARG_MAX_LEN 255 typedef struct { ngx_uint_t engine; /* unsigned engine:1; */ @@ -20,8 +19,8 @@ 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); +static EVP_PKEY *ngx_ssl_load_certificate_key(ngx_pool_t *pool, + char **err, 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); @@ -88,6 +87,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); @@ -405,7 +410,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; @@ -415,7 +420,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; @@ -428,12 +433,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) { @@ -523,8 +529,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", @@ -594,7 +615,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, @@ -772,10 +793,81 @@ 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_ssl_load_certificate_key(ngx_pool_t *pool, char **err, ngx_str_t *key, ngx_array_t *passwords, ngx_ssl_ppdialog_conf_t *dlg) { BIO *bio; EVP_PKEY *pkey; @@ -871,11 +963,26 @@ ngx_ssl_load_certificate_key(ngx_pool_t *pool, char **err, tries = 1; pwd = NULL; cb = NULL; + + /** directive format: ssl_pass_phrase_dialog buildin|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; + } } - for ( ;; ) { + /* skip decrypting private keys in config test phase to avoid + asking for pass phase twice */ + if (ngx_test_config){ + return NULL; + } + for ( ;; ) { pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, pwd); + if (pkey != NULL) { break; } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 7759e1a..a346792 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -74,9 +74,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; @@ -84,7 +94,6 @@ struct ngx_ssl_s { size_t buffer_size; }; - struct ngx_ssl_connection_s { ngx_ssl_conn_t *connection; SSL_CTX *session_ctx; @@ -185,9 +194,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 f1fae50..ad7e3fe 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -17,8 +17,9 @@ 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_HTTP_ALPN_PROTOS "\x08http/1.1\x08http/1.0\x08http/0.9" +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" #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation static int ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, @@ -53,6 +54,9 @@ static char *ngx_http_ssl_conf_command_check(ngx_conf_t *cf, void *post, static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf); +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 }, @@ -296,6 +300,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 }; @@ -555,7 +566,7 @@ ngx_http_ssl_add_variables(ngx_conf_t *cf) static void * ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) { - ngx_http_ssl_srv_conf_t *sscf; + ngx_http_ssl_srv_conf_t *sscf; sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t)); if (sscf == NULL) { @@ -577,6 +588,8 @@ 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->enable = NGX_CONF_UNSET; @@ -608,6 +621,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; @@ -671,6 +686,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->enable) { @@ -733,6 +751,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 buildin|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, @@ -783,7 +825,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; @@ -1332,3 +1374,31 @@ 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; +} + diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index 7ab0f7e..2f83d75 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -67,6 +67,8 @@ typedef struct { u_char *file; ngx_uint_t line; + + 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 e4f721b..61efa99 100644 --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -2564,7 +2564,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 01a04c8..066aef8 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, @@ -35,6 +36,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 }, @@ -216,6 +219,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 }; @@ -345,6 +355,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; @@ -385,6 +397,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; @@ -446,6 +460,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 buildin|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 @@ -458,7 +495,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; @@ -742,3 +779,32 @@ 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 a0a6113..3d87d50 100644 --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -57,6 +57,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 c692884..a4c14ec 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); @@ -226,6 +231,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_conf_t, pass_phrase_dialog), + NULL }, + ngx_null_command }; @@ -690,6 +702,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) { ngx_stream_ssl_conf_t *prev = parent; ngx_stream_ssl_conf_t *conf = child; + ngx_ssl_ppdialog_conf_t dlg; ngx_pool_cleanup_t *cln; @@ -729,6 +742,8 @@ ngx_stream_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; @@ -776,6 +791,23 @@ ngx_stream_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 buildin|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); @@ -820,7 +852,7 @@ ngx_stream_ssl_merge_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; @@ -1206,3 +1238,31 @@ 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_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 e7c825e..d80daa4 100644 --- a/src/stream/ngx_stream_ssl_module.h +++ b/src/stream/ngx_stream_ssl_module.h @@ -56,6 +56,8 @@ typedef struct { u_char *file; ngx_uint_t line; + + ngx_str_t pass_phrase_dialog; } ngx_stream_ssl_conf_t; -- 2.44.0