Skip to content

Commit

Permalink
SSL: client certificate validation with OCSP (ticket #1534).
Browse files Browse the repository at this point in the history
OCSP validation for client certificates is enabled by the "ssl_ocsp" directive.
OCSP responder can be optionally specified by "ssl_ocsp_responder".

When session is reused, peer chain is not available for validation.
If the verified chain contains certificates from the peer chain not available
at the server, validation will fail.
  • Loading branch information
arut committed May 22, 2020
1 parent aa94ee8 commit 60438ae
Show file tree
Hide file tree
Showing 6 changed files with 681 additions and 20 deletions.
58 changes: 51 additions & 7 deletions src/event/ngx_event_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ int ngx_ssl_connection_index;
int ngx_ssl_server_conf_index;
int ngx_ssl_session_cache_index;
int ngx_ssl_session_ticket_keys_index;
int ngx_ssl_ocsp_index;
int ngx_ssl_certificate_index;
int ngx_ssl_next_certificate_index;
int ngx_ssl_certificate_name_index;
Expand Down Expand Up @@ -213,6 +214,13 @@ ngx_ssl_init(ngx_log_t *log)
return NGX_ERROR;
}

ngx_ssl_ocsp_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
if (ngx_ssl_ocsp_index == -1) {
ngx_ssl_error(NGX_LOG_ALERT, log, 0,
"SSL_CTX_get_ex_new_index() failed");
return NGX_ERROR;
}

ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
NULL);
if (ngx_ssl_certificate_index == -1) {
Expand Down Expand Up @@ -1594,13 +1602,18 @@ ngx_ssl_handshake(ngx_connection_t *c)
{
int n, sslerr;
ngx_err_t err;
ngx_int_t rc;

#ifdef SSL_READ_EARLY_DATA_SUCCESS
if (c->ssl->try_early_data) {
return ngx_ssl_try_early_data(c);
}
#endif

if (c->ssl->in_ocsp) {
return ngx_ssl_ocsp_validate(c);
}

ngx_ssl_clear_error(c->log);

n = SSL_do_handshake(c->ssl->connection);
Expand All @@ -1621,8 +1634,6 @@ ngx_ssl_handshake(ngx_connection_t *c)
ngx_ssl_handshake_log(c);
#endif

c->ssl->handshaked = 1;

c->recv = ngx_ssl_recv;
c->send = ngx_ssl_write;
c->recv_chain = ngx_ssl_recv_chain;
Expand All @@ -1641,6 +1652,20 @@ ngx_ssl_handshake(ngx_connection_t *c)
#endif
#endif

rc = ngx_ssl_ocsp_validate(c);

if (rc == NGX_ERROR) {
return NGX_ERROR;
}

if (rc == NGX_AGAIN) {
c->read->handler = ngx_ssl_handshake_handler;
c->write->handler = ngx_ssl_handshake_handler;
return NGX_AGAIN;
}

c->ssl->handshaked = 1;

return NGX_OK;
}

Expand Down Expand Up @@ -1710,6 +1735,7 @@ ngx_ssl_try_early_data(ngx_connection_t *c)
u_char buf;
size_t readbytes;
ngx_err_t err;
ngx_int_t rc;

ngx_ssl_clear_error(c->log);

Expand Down Expand Up @@ -1744,14 +1770,27 @@ ngx_ssl_try_early_data(ngx_connection_t *c)
c->ssl->early_buf = buf;
c->ssl->early_preread = 1;

c->ssl->handshaked = 1;
c->ssl->in_early = 1;

c->recv = ngx_ssl_recv;
c->send = ngx_ssl_write;
c->recv_chain = ngx_ssl_recv_chain;
c->send_chain = ngx_ssl_send_chain;

rc = ngx_ssl_ocsp_validate(c);

if (rc == NGX_ERROR) {
return NGX_ERROR;
}

if (rc == NGX_AGAIN) {
c->read->handler = ngx_ssl_handshake_handler;
c->write->handler = ngx_ssl_handshake_handler;
return NGX_AGAIN;
}

c->ssl->handshaked = 1;

return NGX_OK;
}

Expand Down Expand Up @@ -2735,6 +2774,8 @@ ngx_ssl_shutdown(ngx_connection_t *c)
int n, sslerr, mode;
ngx_err_t err;

ngx_ssl_ocsp_cleanup(c);

if (SSL_in_init(c->ssl->connection)) {
/*
* OpenSSL 1.0.2f complains if SSL_shutdown() is called during
Expand Down Expand Up @@ -4894,11 +4935,14 @@ ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
rc = SSL_get_verify_result(c->ssl->connection);

if (rc == X509_V_OK) {
ngx_str_set(s, "SUCCESS");
return NGX_OK;
}
if (ngx_ssl_ocsp_get_status(c, &str) == NGX_OK) {
ngx_str_set(s, "SUCCESS");
return NGX_OK;
}

str = X509_verify_cert_error_string(rc);
} else {
str = X509_verify_cert_error_string(rc);
}

s->data = ngx_pnalloc(pool, sizeof("FAILED:") - 1 + ngx_strlen(str));
if (s->data == NULL) {
Expand Down
14 changes: 14 additions & 0 deletions src/event/ngx_event_openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@
#endif


typedef struct ngx_ssl_ocsp_s ngx_ssl_ocsp_t;


struct ngx_ssl_s {
SSL_CTX *ctx;
ngx_log_t *log;
Expand All @@ -87,6 +90,8 @@ struct ngx_ssl_connection_s {
ngx_event_handler_pt saved_read_handler;
ngx_event_handler_pt saved_write_handler;

ngx_ssl_ocsp_t *ocsp;

u_char early_buf;

unsigned handshaked:1;
Expand All @@ -97,6 +102,7 @@ struct ngx_ssl_connection_s {
unsigned handshake_buffer_set:1;
unsigned try_early_data:1;
unsigned in_early:1;
unsigned in_ocsp:1;
unsigned early_preread:1;
unsigned write_blocked:1;
};
Expand Down Expand Up @@ -180,6 +186,13 @@ ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify);
ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
ngx_int_t ngx_ssl_ocsp(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder,
ngx_uint_t depth);
ngx_int_t ngx_ssl_ocsp_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
ngx_int_t ngx_ssl_ocsp_validate(ngx_connection_t *c);
ngx_int_t ngx_ssl_ocsp_get_status(ngx_connection_t *c, const char **s);
void ngx_ssl_ocsp_cleanup(ngx_connection_t *c);
RSA *ngx_ssl_rsa512_key_callback(ngx_ssl_conn_t *ssl_conn, int is_export,
int key_length);
ngx_array_t *ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file);
Expand Down Expand Up @@ -281,6 +294,7 @@ extern int ngx_ssl_connection_index;
extern int ngx_ssl_server_conf_index;
extern int ngx_ssl_session_cache_index;
extern int ngx_ssl_session_ticket_keys_index;
extern int ngx_ssl_ocsp_index;
extern int ngx_ssl_certificate_index;
extern int ngx_ssl_next_certificate_index;
extern int ngx_ssl_certificate_name_index;
Expand Down
Loading

0 comments on commit 60438ae

Please sign in to comment.