diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 394a8c8..60991ec 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1085,6 +1085,49 @@ ngx_ssl_passwords_cleanup(void *data) } +ngx_int_t +ngx_ssl_esni(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *esnipub, ngx_str_t *esnikey) +{ + BIO *bio; + + if (esnikey->len == 0 || esnipub->len == 0) { + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, esnikey, 1) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_conf_full_name(cf->cycle, esnipub, 1) != NGX_OK) { + return NGX_ERROR; + } + + bio = BIO_new_file((char *) esnikey->data, "r"); + if (bio == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "BIO_new_file(\"%s\") failed", esnikey->data); + return NGX_ERROR; + } + + bio = BIO_new_file((char *) esnipub->data, "r"); + if (bio == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "BIO_new_file(\"%s\") failed", esnikey->data); + return NGX_ERROR; + } + + if (SSL_esni_server_enable(ssl->ctx, (char *)esnikey->data, (char *)esnipub->data) != 1) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "ESNI error"); + return NGX_ERROR; + } + + BIO_free(bio); + + return NGX_OK; +} + + ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) { @@ -4003,6 +4046,37 @@ ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) } +ngx_int_t +ngx_ssl_get_esni(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + s->len = 0; + char *hidden=NULL; + char *cover=NULL; + int esnirv=SSL_get_esni_status(c->ssl->connection, &hidden, &cover); + if (esnirv) { + } + switch (esnirv) { + case SSL_ESNI_STATUS_NOT_TRIED: + ngx_str_set(s, "not attemped"); + break; + case SSL_ESNI_STATUS_FAILED: + ngx_str_set(s, "tried but failed"); + break; + case SSL_ESNI_STATUS_BAD_NAME: + ngx_str_set(s, "bad name"); + break; + case SSL_ESNI_STATUS_SUCCESS: + ngx_str_set(s, "success"); + break; + default: + ngx_str_set(s, "esni error"); +break; + } + //s->data = (u_char *) esnis; + return NGX_OK; +} + + ngx_int_t ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h index 31d0923..7d08e16 100644 --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -30,6 +30,7 @@ #include #include #include +#include #define NGX_SSL_NAME "OpenSSL" @@ -178,6 +179,8 @@ 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_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_int_t ngx_ssl_esni(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *esnipub, + ngx_str_t *esnikey); ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, ngx_uint_t prefer_server_ciphers); ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, @@ -205,6 +208,7 @@ ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags); +ngx_int_t ngx_ssl_get_esni(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); void ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session); diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index c5ed248..3c88b07 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -176,6 +176,27 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers), NULL }, + { ngx_string("ssl_esni"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, esni), + NULL }, + + { ngx_string("ssl_esnipub"), + 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, esnipub), + NULL }, + + { ngx_string("ssl_esnikey"), + 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, esnikey), + NULL }, + { ngx_string("ssl_session_cache"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12, ngx_http_ssl_session_cache, @@ -330,6 +351,9 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_curves"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_curves, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_esni_data"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_esni, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_session_id"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_session_id, NGX_HTTP_VAR_CHANGEABLE, 0 }, @@ -599,11 +623,14 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) sscf->enable = NGX_CONF_UNSET; sscf->prefer_server_ciphers = NGX_CONF_UNSET; sscf->early_data = NGX_CONF_UNSET; + sscf->esni = NGX_CONF_UNSET; sscf->buffer_size = NGX_CONF_UNSET_SIZE; sscf->verify = NGX_CONF_UNSET_UINT; sscf->verify_depth = NGX_CONF_UNSET_UINT; sscf->certificates = NGX_CONF_UNSET_PTR; sscf->certificate_keys = NGX_CONF_UNSET_PTR; + //sscf->esnipub = NGX_CONF_UNSET; + //sscf->esnikey = NGX_CONF_UNSET; sscf->passwords = NGX_CONF_UNSET_PTR; sscf->builtin_session_cache = NGX_CONF_UNSET; sscf->session_timeout = NGX_CONF_UNSET; @@ -647,6 +674,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) prev->prefer_server_ciphers, 1); ngx_conf_merge_value(conf->early_data, prev->early_data, 1); + ngx_conf_merge_value(conf->esni, prev->esni, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 @@ -661,6 +689,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL); ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys, NULL); + ngx_conf_merge_str_value(conf->esnipub, prev->esnipub, + NULL); + ngx_conf_merge_str_value(conf->esnikey, prev->esnikey, + NULL); ngx_conf_merge_ptr_value(conf->passwords, prev->passwords, NULL); @@ -761,7 +793,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) "dynamically to an OpenSSL library which has no tlsext support, " "therefore SNI is not available"); } - #endif #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation @@ -788,6 +819,15 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) return NGX_CONF_ERROR; } + if (conf->esni) { + if (ngx_ssl_esni(cf, &conf->ssl, &conf->esnipub, + &conf->esnikey) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, conf->prefer_server_ciphers) != NGX_OK) diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index deeadc3..f71cec7 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -21,6 +21,7 @@ typedef struct { ngx_flag_t prefer_server_ciphers; ngx_flag_t early_data; + ngx_flag_t esni; ngx_uint_t protocols; @@ -36,6 +37,8 @@ typedef struct { ngx_array_t *certificates; ngx_array_t *certificate_keys; + ngx_str_t esnipub; + ngx_str_t esnikey; ngx_str_t dhparam; ngx_str_t ecdh_curve; ngx_str_t client_certificate; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index 1901129..ec42395 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -852,8 +852,25 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module); + sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); + + if (sscf->esni) { + if (SSL_esni_server_enable(sscf->ssl.ctx, sscf->esnikey, sscf->esnipub) != 1) { + ngx_ssl_error(NGX_LOG_INFO, c->log, 0, + "ESNI error"); + return NGX_ERROR; + } + } + servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name); + char *hidden=NULL; + char *cover=NULL; + + SSL_get_esni_status(ssl_conn,&hidden,&cover); + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "esni cover : %s, hidden: %s, servername: %s", (cover==NULL?"none":cover), (hidden==NULL?"none":hidden), (servername==NULL?"none":servername)); + if (servername == NULL) { return (clcf->strict_sni) ? SSL_TLSEXT_ERR_ALERT_FATAL : SSL_TLSEXT_ERR_NOACK; } @@ -895,8 +912,6 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) ngx_set_connection_log(c, clcf->error_log); - sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module); - c->ssl->buffer_size = sscf->buffer_size; if (sscf->ssl.ctx) {