Skip to content

Commit

Permalink
Verify certificate CN/SAN
Browse files Browse the repository at this point in the history
  • Loading branch information
victorhahncastell committed Feb 5, 2016
1 parent acb13cf commit 2e3e8a9
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 20 deletions.
2 changes: 1 addition & 1 deletion LICENSE
@@ -1,7 +1,7 @@
/**
* Copyright (C) 2011-2013 Valery Komarov <komarov@valerka.net>
* Copyright (C) 2013 Jiri Hruska <jirka@fud.cz>
* Copyright (C) 2015 Victor Hahn Castell <victor.hahn@flexoptix.net>
* Copyright (C) 2015-2016 Victor Hahn Castell <victor.hahn@flexoptix.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -108,6 +108,8 @@ accepted which exposes you to possible man-in-the-middle attacks. Note that the
certificate will need to be signed by a proper CA trusted by your system if this is enabled.
See below how to trust CAs without installing them system-wide.

This options needs OpenSSL >= 1.0.2; it is unavailable if compiled with older versions.

## ssl_ca_file
expected value: file path

Expand Down
79 changes: 60 additions & 19 deletions ngx_http_auth_ldap_module.c
@@ -1,6 +1,7 @@
/**
* Copyright (C) 2011-2013 Valery Komarov <komarov@valerka.net>
* Copyright (C) 2013 Jiri Hruska <jirka@fud.cz>
* Copyright (C) 2015-2016 Victor Hahn Castell <victor.hahn@flexoptix.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -31,6 +32,11 @@
#include <ngx_md5.h>
#include <ldap.h>

// used for manual warnings
#define XSTR(x) STR(x)
#define STR(x) #x
#pragma GCC diagnostic warning "-Wcpp"

#ifndef LDAP_PROTO_EXT
/* Some OpenLDAP headers are accidentally missing ldap_init_fd() etc. */

Expand Down Expand Up @@ -383,7 +389,15 @@ ngx_http_auth_ldap_ldap_server(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
}
server->connections = i;
} else if (ngx_strcmp(value[0].data, "ssl_check_cert") == 0 && ngx_strcmp(value[1].data, "on") == 0) {
#if OPENSSL_VERSION_NUMBER >= 0x10002000
server->ssl_check_cert = 1;
#else
#warning "http_auth_ldap: Compiling with OpenSSL < 1.0.2, certificate verification will be unavailable. OPENSSL_VERSION_NUMBER == " XSTR(OPENSSL_VERSION_NUMBER)
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"http_auth_ldap: 'ssl_cert_check': cannot verify remote certificate's domain name because "
"your version of OpenSSL is too old. "
"Please install OpenSSL >= 1.02 and recompile nginx.");
#endif
} else if (ngx_strcmp(value[0].data, "ssl_ca_dir") == 0) {
server->ssl_ca_dir = value[1];
} else if (ngx_strcmp(value[0].data, "ssl_ca_file") == 0) {
Expand Down Expand Up @@ -1224,30 +1238,57 @@ static void
ngx_http_auth_ldap_ssl_handshake_handler(ngx_connection_t *conn, ngx_flag_t validate)
{
ngx_http_auth_ldap_connection_t *c;

c = conn->data;

if (conn->ssl->handshaked) {
// verify remote certificate
X509 *cert = SSL_get_peer_certificate(conn->ssl->connection);
long verified = SSL_get_verify_result(conn->ssl->connection);

if (!validate || (cert && verified == X509_V_OK) ) { // everything fine
conn->read->handler = &ngx_http_auth_ldap_read_handler;
ngx_http_auth_ldap_restore_handlers(conn);
ngx_http_auth_ldap_connection_established(c);
return;
} else { // smells fishy
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"http_auth_ldap: Remote side presented invalid SSL certificate: error %l, %s",
verified, X509_verify_cert_error_string(verified));
ngx_http_auth_ldap_close_connection(c);
return;
#if OPENSSL_VERSION_NUMBER >= 0x10002000
if (validate) { // verify remote certificate if requested
X509 *cert = SSL_get_peer_certificate(conn->ssl->connection);
long chain_verified = SSL_get_verify_result(conn->ssl->connection);

int addr_verified;
char *hostname = c->server->ludpp->lud_host;
addr_verified = X509_check_host(cert, hostname, 0, 0, 0);

if (!addr_verified) { // domain not in cert? try IP
size_t len; // get IP length
if (conn->sockaddr->sa_family == 4) len = 4;
else if (conn->sockaddr->sa_family == 6) len = 16;
else { // very unlikely indeed
ngx_http_auth_ldap_close_connection(c);
return;
}
addr_verified = X509_check_ip(cert, (const unsigned char*)conn->sockaddr->sa_data, len, 0);
}

// Find anything fishy?
if ( !(cert && addr_verified && chain_verified == X509_V_OK) ) {
if (!addr_verified) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"http_auth_ldap: Remote side presented invalid SSL certificate: "
"does not match address (neither server's domain nor IP in certificate's CN or SAN)");
fprintf(stderr, "DEBUG: SSL cert domain mismatch\n"); fflush(stderr);
} else {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"http_auth_ldap: Remote side presented invalid SSL certificate: error %l, %s",
chain_verified, X509_verify_cert_error_string(chain_verified));
}
ngx_http_auth_ldap_close_connection(c);
return;
}
}
}
#endif

ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: SSL handshake failed");
ngx_http_auth_ldap_close_connection(c);
// handshaked validation successful -- or not required in the first place
conn->read->handler = &ngx_http_auth_ldap_read_handler;
ngx_http_auth_ldap_restore_handlers(conn);
ngx_http_auth_ldap_connection_established(c);
return;
}
else { // handshake failed
ngx_log_error(NGX_LOG_ERR, c->log, 0, "http_auth_ldap: SSL handshake failed");
ngx_http_auth_ldap_close_connection(c);
}
}

static void
Expand Down

0 comments on commit 2e3e8a9

Please sign in to comment.