summaryrefslogtreecommitdiff
path: root/src/event/ngx_event_openssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/event/ngx_event_openssl.c')
-rw-r--r--src/event/ngx_event_openssl.c201
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;