diff options
Diffstat (limited to 'src/event/ngx_event_openssl.c')
-rw-r--r-- | src/event/ngx_event_openssl.c | 201 |
1 files changed, 198 insertions, 3 deletions
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index d8dd3d358..88472fc90 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -44,6 +44,10 @@ static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, HMAC_CTX *hctx, int enc); #endif +#if OPENSSL_VERSION_NUMBER < 0x10002001L +static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str); +#endif + 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); @@ -2418,7 +2422,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, if (enc == 1) { /* encrypt session ticket */ - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl session ticket encrypt, key: \"%*s\" (%s session)", ngx_hex_dump(buf, key[0].name, 16) - buf, buf, SSL_session_reused(ssl_conn) ? "reused" : "new"); @@ -2440,7 +2444,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, } } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl session ticket decrypt, key: \"%*s\" not found", ngx_hex_dump(buf, name, 16) - buf, buf); @@ -2448,7 +2452,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, found: - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "ssl session ticket decrypt, key: \"%*s\"%s", ngx_hex_dump(buf, key[i].name, 16) - buf, buf, (i == 0) ? " (default)" : ""); @@ -2487,6 +2491,175 @@ ngx_ssl_cleanup_ctx(void *data) ngx_int_t +ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name) +{ + X509 *cert; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_ERROR; + } + +#if OPENSSL_VERSION_NUMBER >= 0x10002001L + + /* X509_check_host() is only available in OpenSSL 1.0.2+ */ + + if (name->len == 0) { + goto failed; + } + + if (X509_check_host(cert, name->data, name->len, 0) != 1) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "X509_check_host(): no match"); + goto failed; + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "X509_check_host(): match"); + + goto found; + +#else + { + int n, i; + X509_NAME *sname; + ASN1_STRING *str; + X509_NAME_ENTRY *entry; + GENERAL_NAME *altname; + STACK_OF(GENERAL_NAME) *altnames; + + /* + * As per RFC6125 and RFC2818, we check subjectAltName extension, + * and if it's not present - commonName in Subject is checked. + */ + + altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + + if (altnames) { + n = sk_GENERAL_NAME_num(altnames); + + for (i = 0; i < n; i++) { + altname = sk_GENERAL_NAME_value(altnames, i); + + if (altname->type != GEN_DNS) { + continue; + } + + str = altname->d.dNSName; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL subjectAltName: \"%*s\"", + ASN1_STRING_length(str), ASN1_STRING_data(str)); + + if (ngx_ssl_check_name(name, str) == NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL subjectAltName: match"); + GENERAL_NAMES_free(altnames); + goto found; + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL subjectAltName: no match"); + + GENERAL_NAMES_free(altnames); + goto failed; + } + + /* + * If there is no subjectAltName extension, check commonName + * in Subject. While RFC2818 requires to only check "most specific" + * CN, both Apache and OpenSSL check all CNs, and so do we. + */ + + sname = X509_get_subject_name(cert); + + if (sname == NULL) { + goto failed; + } + + i = -1; + for ( ;; ) { + i = X509_NAME_get_index_by_NID(sname, NID_commonName, i); + + if (i < 0) { + break; + } + + entry = X509_NAME_get_entry(sname, i); + str = X509_NAME_ENTRY_get_data(entry); + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL commonName: \"%*s\"", + ASN1_STRING_length(str), ASN1_STRING_data(str)); + + if (ngx_ssl_check_name(name, str) == NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL commonName: match"); + goto found; + } + } + + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL commonName: no match"); + } +#endif + +failed: + + X509_free(cert); + return NGX_ERROR; + +found: + + X509_free(cert); + return NGX_OK; +} + + +#if OPENSSL_VERSION_NUMBER < 0x10002001L + +static ngx_int_t +ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *pattern) +{ + u_char *s, *p, *end; + size_t slen, plen; + + s = name->data; + slen = name->len; + + p = ASN1_STRING_data(pattern); + plen = ASN1_STRING_length(pattern); + + if (slen == plen && ngx_strncasecmp(s, p, plen) == 0) { + return NGX_OK; + } + + if (plen > 2 && p[0] == '*' && p[1] == '.') { + plen -= 1; + p += 1; + + end = s + slen; + s = ngx_strlchr(s, end, '.'); + + if (s == NULL) { + return NGX_ERROR; + } + + slen = end - s; + + if (plen == slen && ngx_strncasecmp(s, p, plen) == 0) { + return NGX_OK; + } + } + + return NGX_ERROR; +} + +#endif + + +ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { s->data = (u_char *) SSL_get_version(c->ssl->connection); @@ -2545,6 +2718,28 @@ ngx_ssl_get_session_reused(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) ngx_int_t +ngx_ssl_get_server_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + + const char *servername; + + servername = SSL_get_servername(c->ssl->connection, + TLSEXT_NAMETYPE_host_name); + if (servername) { + s->data = (u_char *) servername; + s->len = ngx_strlen(servername); + return NGX_OK; + } + +#endif + + s->len = 0; + return NGX_OK; +} + + +ngx_int_t ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) { size_t len; |