mirror of
https://github.com/nginx/nginx.git
synced 2024-12-03 13:09:01 +08:00
SSL: the "ssl_password_file" directive.
This commit is contained in:
parent
3d167cd42e
commit
9f8785ae5e
@ -10,14 +10,20 @@
|
||||
#include <ngx_event.h>
|
||||
|
||||
|
||||
#define NGX_SSL_PASSWORD_BUFFER_SIZE 4096
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t engine; /* unsigned engine:1; */
|
||||
} ngx_openssl_conf_t;
|
||||
|
||||
|
||||
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);
|
||||
static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
|
||||
int ret);
|
||||
static void ngx_ssl_passwords_cleanup(void *data);
|
||||
static void ngx_ssl_handshake_handler(ngx_event_t *ev);
|
||||
static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
|
||||
static void ngx_ssl_write_handler(ngx_event_t *wev);
|
||||
@ -257,11 +263,13 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
ngx_str_t *key)
|
||||
ngx_str_t *key, ngx_array_t *passwords)
|
||||
{
|
||||
BIO *bio;
|
||||
X509 *x509;
|
||||
u_long n;
|
||||
BIO *bio;
|
||||
X509 *x509;
|
||||
u_long n;
|
||||
ngx_str_t *pwd;
|
||||
ngx_uint_t tries;
|
||||
|
||||
if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
@ -348,19 +356,76 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
|
||||
SSL_FILETYPE_PEM)
|
||||
== 0)
|
||||
{
|
||||
if (passwords) {
|
||||
tries = passwords->nelts;
|
||||
pwd = passwords->elts;
|
||||
|
||||
SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback);
|
||||
SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd);
|
||||
|
||||
} else {
|
||||
tries = 1;
|
||||
#if (NGX_SUPPRESS_WARN)
|
||||
pwd = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
for ( ;; ) {
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
|
||||
SSL_FILETYPE_PEM)
|
||||
!= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (--tries) {
|
||||
n = ERR_peek_error();
|
||||
|
||||
if (ERR_GET_LIB(n) == ERR_LIB_EVP
|
||||
&& ERR_GET_REASON(n) == EVP_R_BAD_DECRYPT)
|
||||
{
|
||||
ERR_clear_error();
|
||||
SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
|
||||
"SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata)
|
||||
{
|
||||
ngx_str_t *pwd = userdata;
|
||||
|
||||
if (rwflag) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
|
||||
"ngx_ssl_password_callback() is called for encryption");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pwd->len > (size_t) size) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
|
||||
"password is truncated to %d bytes", size);
|
||||
} else {
|
||||
size = pwd->len;
|
||||
}
|
||||
|
||||
ngx_memcpy(buf, pwd->data, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
|
||||
ngx_int_t depth)
|
||||
@ -597,6 +662,148 @@ ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
|
||||
}
|
||||
|
||||
|
||||
ngx_array_t *
|
||||
ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file)
|
||||
{
|
||||
u_char *p, *last, *end;
|
||||
size_t len;
|
||||
ssize_t n;
|
||||
ngx_fd_t fd;
|
||||
ngx_str_t *pwd;
|
||||
ngx_array_t *passwords;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
u_char buf[NGX_SSL_PASSWORD_BUFFER_SIZE];
|
||||
|
||||
if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cln = ngx_pool_cleanup_add(cf->temp_pool, 0);
|
||||
passwords = ngx_array_create(cf->temp_pool, 4, sizeof(ngx_str_t));
|
||||
|
||||
if (cln == NULL || passwords == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cln->handler = ngx_ssl_passwords_cleanup;
|
||||
cln->data = passwords;
|
||||
|
||||
fd = ngx_open_file(file->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
|
||||
if (fd == NGX_INVALID_FILE) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
|
||||
ngx_open_file_n " \"%s\" failed", file->data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = 0;
|
||||
last = buf;
|
||||
|
||||
do {
|
||||
n = ngx_read_fd(fd, last, NGX_SSL_PASSWORD_BUFFER_SIZE - len);
|
||||
|
||||
if (n == -1) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
|
||||
ngx_read_fd_n " \"%s\" failed", file->data);
|
||||
passwords = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
end = last + n;
|
||||
|
||||
if (len && n == 0) {
|
||||
*end++ = LF;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
for ( ;; ) {
|
||||
last = ngx_strlchr(last, end, LF);
|
||||
|
||||
if (last == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
len = last++ - p;
|
||||
|
||||
if (len && p[len - 1] == CR) {
|
||||
len--;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
pwd = ngx_array_push(passwords);
|
||||
if (pwd == NULL) {
|
||||
passwords = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
pwd->len = len;
|
||||
pwd->data = ngx_pnalloc(cf->temp_pool, len);
|
||||
|
||||
if (pwd->data == NULL) {
|
||||
passwords->nelts--;
|
||||
passwords = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ngx_memcpy(pwd->data, p, len);
|
||||
}
|
||||
|
||||
p = last;
|
||||
}
|
||||
|
||||
len = end - p;
|
||||
|
||||
if (len == NGX_SSL_PASSWORD_BUFFER_SIZE) {
|
||||
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
||||
"too long line in \"%s\"", file->data);
|
||||
passwords = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ngx_memmove(buf, p, len);
|
||||
last = buf + len;
|
||||
|
||||
} while (n != 0);
|
||||
|
||||
if (passwords->nelts == 0) {
|
||||
pwd = ngx_array_push(passwords);
|
||||
if (pwd == NULL) {
|
||||
passwords = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ngx_memzero(pwd, sizeof(ngx_str_t));
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
||||
if (ngx_close_file(fd) == NGX_FILE_ERROR) {
|
||||
ngx_conf_log_error(NGX_LOG_ALERT, cf, ngx_errno,
|
||||
ngx_close_file_n " \"%s\" failed", file->data);
|
||||
}
|
||||
|
||||
ngx_memzero(buf, NGX_SSL_PASSWORD_BUFFER_SIZE);
|
||||
|
||||
return passwords;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_ssl_passwords_cleanup(void *data)
|
||||
{
|
||||
ngx_array_t *passwords = data;
|
||||
|
||||
ngx_str_t *pwd;
|
||||
ngx_uint_t i;
|
||||
|
||||
pwd = passwords->elts;
|
||||
|
||||
for (i = 0; i < passwords->nelts; i++) {
|
||||
ngx_memzero(pwd[i].data, pwd[i].len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
|
||||
{
|
||||
|
@ -112,7 +112,7 @@ typedef struct {
|
||||
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_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_str_t *cert, ngx_str_t *key);
|
||||
ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords);
|
||||
ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_str_t *cert, ngx_int_t depth);
|
||||
ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
@ -124,6 +124,7 @@ ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
|
||||
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
|
||||
RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
|
||||
int key_length);
|
||||
ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
|
||||
ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
|
||||
ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
|
||||
ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
|
||||
|
@ -43,6 +43,8 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
|
||||
|
||||
static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
@ -91,6 +93,13 @@ static ngx_command_t ngx_http_ssl_commands[] = {
|
||||
offsetof(ngx_http_ssl_srv_conf_t, certificate_key),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("ssl_password_file"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
|
||||
ngx_http_ssl_password_file,
|
||||
NGX_HTTP_SRV_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("ssl_dhparam"),
|
||||
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_str_slot,
|
||||
@ -514,6 +523,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
|
||||
sscf->buffer_size = NGX_CONF_UNSET_SIZE;
|
||||
sscf->verify = NGX_CONF_UNSET_UINT;
|
||||
sscf->verify_depth = NGX_CONF_UNSET_UINT;
|
||||
sscf->passwords = NGX_CONF_UNSET_PTR;
|
||||
sscf->builtin_session_cache = NGX_CONF_UNSET;
|
||||
sscf->session_timeout = NGX_CONF_UNSET;
|
||||
sscf->session_tickets = NGX_CONF_UNSET;
|
||||
@ -563,6 +573,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
|
||||
ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");
|
||||
|
||||
ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
|
||||
|
||||
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
|
||||
|
||||
ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate,
|
||||
@ -652,7 +664,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
cln->data = &conf->ssl;
|
||||
|
||||
if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
|
||||
&conf->certificate_key)
|
||||
&conf->certificate_key, conf->passwords)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_CONF_ERROR;
|
||||
@ -781,6 +793,29 @@ ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_http_ssl_srv_conf_t *sscf = conf;
|
||||
|
||||
ngx_str_t *value;
|
||||
|
||||
if (sscf->passwords != NGX_CONF_UNSET_PTR) {
|
||||
return "is duplicate";
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
sscf->passwords = ngx_ssl_read_password_file(cf, &value[1]);
|
||||
|
||||
if (sscf->passwords == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
|
@ -42,6 +42,8 @@ typedef struct {
|
||||
|
||||
ngx_str_t ciphers;
|
||||
|
||||
ngx_array_t *passwords;
|
||||
|
||||
ngx_shm_zone_t *shm_zone;
|
||||
|
||||
ngx_flag_t session_tickets;
|
||||
|
@ -21,6 +21,8 @@ static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
@ -74,6 +76,13 @@ static ngx_command_t ngx_mail_ssl_commands[] = {
|
||||
offsetof(ngx_mail_ssl_conf_t, certificate_key),
|
||||
NULL },
|
||||
|
||||
{ ngx_string("ssl_password_file"),
|
||||
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
|
||||
ngx_mail_ssl_password_file,
|
||||
NGX_MAIL_SRV_CONF_OFFSET,
|
||||
0,
|
||||
NULL },
|
||||
|
||||
{ ngx_string("ssl_dhparam"),
|
||||
NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
|
||||
ngx_conf_set_str_slot,
|
||||
@ -195,6 +204,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf)
|
||||
|
||||
scf->enable = NGX_CONF_UNSET;
|
||||
scf->starttls = NGX_CONF_UNSET_UINT;
|
||||
scf->passwords = NGX_CONF_UNSET_PTR;
|
||||
scf->prefer_server_ciphers = NGX_CONF_UNSET;
|
||||
scf->builtin_session_cache = NGX_CONF_UNSET;
|
||||
scf->session_timeout = NGX_CONF_UNSET;
|
||||
@ -231,6 +241,8 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
ngx_conf_merge_str_value(conf->certificate, prev->certificate, "");
|
||||
ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, "");
|
||||
|
||||
ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL);
|
||||
|
||||
ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, "");
|
||||
|
||||
ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve,
|
||||
@ -302,7 +314,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
|
||||
cln->data = &conf->ssl;
|
||||
|
||||
if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
|
||||
&conf->certificate_key)
|
||||
&conf->certificate_key, conf->passwords)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_CONF_ERROR;
|
||||
@ -421,6 +433,29 @@ ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_mail_ssl_password_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
ngx_mail_ssl_conf_t *scf = conf;
|
||||
|
||||
ngx_str_t *value;
|
||||
|
||||
if (scf->passwords != NGX_CONF_UNSET_PTR) {
|
||||
return "is duplicate";
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
scf->passwords = ngx_ssl_read_password_file(cf, &value[1]);
|
||||
|
||||
if (scf->passwords == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
{
|
||||
|
@ -39,6 +39,8 @@ typedef struct {
|
||||
|
||||
ngx_str_t ciphers;
|
||||
|
||||
ngx_array_t *passwords;
|
||||
|
||||
ngx_shm_zone_t *shm_zone;
|
||||
|
||||
ngx_flag_t session_tickets;
|
||||
|
Loading…
Reference in New Issue
Block a user