# HG changeset patch # User Igor Sysoev # Date 1256576014 0 # Node ID 08570d26c7c5499281e8326d1b09594fab8b8635 # Parent f678ea405737d14d49dad14ba04c9c1110198c41 merge r2995, r2996, r2997, r2998, r3003, r3141, r3210, r3211, r3232: various SSL fixes and features: *) $ssl_client_verify *) "ssl_verify_client ask" was changed to "ssl_verify_client optional" *) ssl_crl *) delete OpenSSL pre-0.9.7 compatibility: the sources were not actually compatible with OpenSSL 0.9.6 since ssl_session_cache introduction *) fix memory corruption in $ssl_client_cert *) issue SNI warning instead of failure: this is too common case *) use ngx_log_error(), since OpenSSL does not set an error on the failure *) add SNI support in -V output diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -239,6 +239,13 @@ main(int argc, char *const *argv) #ifdef NGX_COMPILER ngx_log_stderr(0, "built by " NGX_COMPILER); #endif +#if (NGX_SSL) +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + ngx_log_stderr(0, "TLS SNI support enabled"); +#else + ngx_log_stderr(0, "TLS SNI support disabled"); +#endif +#endif ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE); } diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -97,16 +97,12 @@ int ngx_ssl_session_cache_index; ngx_int_t ngx_ssl_init(ngx_log_t *log) { -#if OPENSSL_VERSION_NUMBER >= 0x00907000 OPENSSL_config(NULL); -#endif SSL_library_init(); SSL_load_error_strings(); -#if (NGX_SSL_ENGINE) ENGINE_load_builtin_engines(); -#endif ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); @@ -169,9 +165,7 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_ SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG); -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); -#endif SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE); @@ -267,6 +261,51 @@ ngx_ssl_client_certificate(ngx_conf_t *c } +ngx_int_t +ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl) +{ + X509_STORE *store; + X509_LOOKUP *lookup; + + if (crl->len == 0) { + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) { + return NGX_ERROR; + } + + store = SSL_CTX_get_cert_store(ssl->ctx); + + if (store == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_get_cert_store() failed"); + return NGX_ERROR; + } + + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + + if (lookup == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_STORE_add_lookup() failed"); + return NGX_ERROR; + } + + if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_LOOKUP_load_file(\"%s\") failed", crl->data); + return NGX_ERROR; + } + + X509_STORE_set_flags(store, + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + + return NGX_OK; +} + + static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) { @@ -1201,9 +1240,7 @@ ngx_ssl_connection_error(ngx_connection_ if (err == NGX_ECONNRESET || err == NGX_EPIPE || err == NGX_ENOTCONN -#if !(NGX_CRIT_ETIMEDOUT) || err == NGX_ETIMEDOUT -#endif || err == NGX_ECONNREFUSED || err == NGX_ENETDOWN || err == NGX_ENETUNREACH @@ -1974,7 +2011,7 @@ ngx_ssl_get_certificate(ngx_connection_t p = s->data; - for (i = 0; i < len; i++) { + for (i = 0; i < cert.len - 1; i++) { *p++ = cert.data[i]; if (cert.data[i] == LF) { *p++ = '\t'; @@ -2108,6 +2145,35 @@ ngx_ssl_get_serial_number(ngx_connection } +ngx_int_t +ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + X509 *cert; + + if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) { + s->len = sizeof("FAILED") - 1; + s->data = (u_char *) "FAILED"; + + return NGX_OK; + } + + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert) { + s->len = sizeof("SUCCESS") - 1; + s->data = (u_char *) "SUCCESS"; + + } else { + s->len = sizeof("NONE") - 1; + s->data = (u_char *) "NONE"; + } + + X509_free(cert); + + return NGX_OK; +} + + static void * ngx_openssl_create_conf(ngx_cycle_t *cycle) { @@ -2131,7 +2197,6 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc static char * ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { -#if (NGX_SSL_ENGINE) ngx_openssl_conf_t *oscf = conf; ENGINE *engine; @@ -2166,23 +2231,11 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_c ENGINE_free(engine); return NGX_CONF_OK; - -#else - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"ssl_engine\" directive is available only in " - "OpenSSL 0.9.7 and higher,"); - - return NGX_CONF_ERROR; - -#endif } static void ngx_openssl_exit(ngx_cycle_t *cycle) { -#if (NGX_SSL_ENGINE) ENGINE_cleanup(); -#endif } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -13,12 +13,8 @@ #include #include - -#if OPENSSL_VERSION_NUMBER >= 0x00907000 #include #include -#define NGX_SSL_ENGINE 1 -#endif #define NGX_SSL_NAME "OpenSSL" @@ -100,6 +96,7 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t ngx_str_t *cert, ngx_str_t *key); 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_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl); ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl); ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, @@ -131,6 +128,8 @@ ngx_int_t ngx_ssl_get_issuer_dn(ngx_conn ngx_str_t *s); ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -31,15 +31,6 @@ static char *ngx_http_ssl_enable(ngx_con static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char *ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - -static char ngx_http_ssl_openssl097[] = "OpenSSL 0.9.7 and higher"; - -#endif - static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = { { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, @@ -52,7 +43,7 @@ static ngx_conf_bitmask_t ngx_http_ssl_ static ngx_conf_enum_t ngx_http_ssl_verify[] = { { ngx_string("off"), 0 }, { ngx_string("on"), 1 }, - { ngx_string("ask"), 2 }, + { ngx_string("optional"), 2 }, { ngx_null_string, 0 } }; @@ -124,14 +115,10 @@ static ngx_command_t ngx_http_ssl_comma { ngx_string("ssl_prefer_server_ciphers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE ngx_conf_set_flag_slot, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers), NULL }, -#else - ngx_http_ssl_nosupported, 0, 0, ngx_http_ssl_openssl097 }, -#endif { ngx_string("ssl_session_cache"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12, @@ -147,6 +134,13 @@ static ngx_command_t ngx_http_ssl_comma offsetof(ngx_http_ssl_srv_conf_t, session_timeout), NULL }, + { ngx_string("ssl_crl"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, crl), + NULL }, + ngx_null_command }; @@ -206,6 +200,9 @@ static ngx_http_variable_t ngx_http_ssl { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -313,6 +310,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t * sscf->certificate_key = { 0, NULL }; * sscf->dhparam = { 0, NULL }; * sscf->client_certificate = { 0, NULL }; + * sscf->crl = { 0, NULL }; * sscf->ciphers.len = 0; * sscf->ciphers.data = NULL; * sscf->shm_zone = NULL; @@ -359,6 +357,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, ""); + ngx_conf_merge_str_value(conf->crl, prev->crl, ""); ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); @@ -407,9 +406,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_http_ssl_servername) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_tlsext_servername_callback() failed"); - return NGX_CONF_ERROR; + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "nginx was built with SNI support, however, now it is linked " + "dynamically to an OpenSSL library which has no tlsext support, " + "therefore SNI is not available"); } #endif @@ -453,16 +453,16 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * { return NGX_CONF_ERROR; } + + if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) { + return NGX_CONF_ERROR; + } } -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE - if (conf->prefer_server_ciphers) { SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#endif - /* a temporary 512-bit RSA key is required for export versions of MSIE */ if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) { return NGX_CONF_ERROR; @@ -620,18 +620,3 @@ invalid: return NGX_CONF_ERROR; } - - -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char * -ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" directive is available only in %s,", - &cmd->name, cmd->post); - - return NGX_CONF_ERROR; -} - -#endif diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -33,6 +33,7 @@ typedef struct { ngx_str_t certificate_key; ngx_str_t dhparam; ngx_str_t client_certificate; + ngx_str_t crl; ngx_str_t ciphers; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1520,7 +1520,7 @@ ngx_http_process_request(ngx_http_reques sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - if (sscf->verify == 1) { + if (sscf->verify) { rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK) { @@ -1535,20 +1535,22 @@ ngx_http_process_request(ngx_http_reques return; } - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert == NULL) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent no required SSL certificate"); - - ngx_ssl_remove_cached_session(sscf->ssl.ctx, + if (sscf->verify == 1) { + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent no required SSL certificate"); + + ngx_ssl_remove_cached_session(sscf->ssl.ctx, (SSL_get0_session(c->ssl->connection))); - ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); - return; + ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); + return; + } + + X509_free(cert); } - - X509_free(cert); } } diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -22,15 +22,6 @@ static char *ngx_mail_ssl_starttls(ngx_c static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char *ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - -static char ngx_mail_ssl_openssl097[] = "OpenSSL 0.9.7 and higher"; - -#endif - static ngx_conf_enum_t ngx_http_starttls_state[] = { { ngx_string("off"), NGX_MAIL_STARTTLS_OFF }, @@ -102,14 +93,10 @@ static ngx_command_t ngx_mail_ssl_comma { ngx_string("ssl_prefer_server_ciphers"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE ngx_conf_set_flag_slot, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers), NULL }, -#else - ngx_mail_ssl_nosupported, 0, 0, ngx_mail_ssl_openssl097 }, -#endif { ngx_string("ssl_session_cache"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12, @@ -297,14 +284,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, } } -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE - if (conf->prefer_server_ciphers) { SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#endif - if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) { return NGX_CONF_ERROR; } @@ -492,18 +475,3 @@ invalid: return NGX_CONF_ERROR; } - - -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char * -ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" directive is available only in %s,", - &cmd->name, cmd->post); - - return NGX_CONF_ERROR; -} - -#endif