summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMaxim Dounin <mdounin@mdounin.ru>2014-09-15 17:59:47 +0400
committerMaxim Dounin <mdounin@mdounin.ru>2014-09-15 17:59:47 +0400
commit1c5943c21f4e54a0ffbd6ff4c9fdfe3a0bea8ca9 (patch)
treea2edd47e8e512f2dda01e20f3d4caff4736a25df
parent20f0527892a159200dcbfefab50e185271cc5c69 (diff)
downloadnginx-1c5943c21f4e54a0ffbd6ff4c9fdfe3a0bea8ca9.tar.gz
nginx-1c5943c21f4e54a0ffbd6ff4c9fdfe3a0bea8ca9.tar.bz2
SSL: session id context now includes certificate hash.
This prevents inappropriate session reuse in unrelated server{} blocks, while preserving ability to restore sessions on other servers when using TLS Session Tickets. Additionally, session context is now set even if there is no session cache configured. This is needed as it's also used for TLS Session Tickets. Thanks to Antoine Delignat-Lavaud and Piotr Sikora.
-rw-r--r--src/event/ngx_event_openssl.c98
1 files changed, 96 insertions, 2 deletions
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index d8dd3d358..72c255908 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -27,6 +27,8 @@ static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
ngx_err_t err, char *text);
static void ngx_ssl_clear_error(ngx_log_t *log);
+static ngx_int_t ngx_ssl_session_id_context(ngx_ssl_t *ssl,
+ ngx_str_t *sess_ctx);
ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,
ngx_ssl_session_t *sess);
@@ -1729,13 +1731,15 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
+ if (ngx_ssl_session_id_context(ssl, sess_ctx) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
if (builtin_session_cache == NGX_SSL_NO_SCACHE) {
SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF);
return NGX_OK;
}
- SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len);
-
if (builtin_session_cache == NGX_SSL_NONE_SCACHE) {
/*
@@ -1792,6 +1796,96 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
}
+static ngx_int_t
+ngx_ssl_session_id_context(ngx_ssl_t *ssl, ngx_str_t *sess_ctx)
+{
+ int n, i;
+ X509 *cert;
+ X509_NAME *name;
+ EVP_MD_CTX md;
+ unsigned int len;
+ STACK_OF(X509_NAME) *list;
+ u_char buf[EVP_MAX_MD_SIZE];
+
+ /*
+ * Session ID context is set based on the string provided,
+ * the server certificate, and the client CA list.
+ */
+
+ EVP_MD_CTX_init(&md);
+
+ if (EVP_DigestInit_ex(&md, EVP_sha1(), NULL) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "EVP_DigestInit_ex() failed");
+ goto failed;
+ }
+
+ if (EVP_DigestUpdate(&md, sess_ctx->data, sess_ctx->len) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "EVP_DigestUpdate() failed");
+ goto failed;
+ }
+
+ cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
+
+ if (X509_digest(cert, EVP_sha1(), buf, &len) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "X509_digest() failed");
+ goto failed;
+ }
+
+ if (EVP_DigestUpdate(&md, buf, len) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "EVP_DigestUpdate() failed");
+ goto failed;
+ }
+
+ list = SSL_CTX_get_client_CA_list(ssl->ctx);
+
+ if (list != NULL) {
+ n = sk_X509_NAME_num(list);
+
+ for (i = 0; i < n; i++) {
+ name = sk_X509_NAME_value(list, i);
+
+ if (X509_NAME_digest(name, EVP_sha1(), buf, &len) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "X509_NAME_digest() failed");
+ goto failed;
+ }
+
+ if (EVP_DigestUpdate(&md, buf, len) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "EVP_DigestUpdate() failed");
+ goto failed;
+ }
+ }
+ }
+
+ if (EVP_DigestFinal_ex(&md, buf, &len) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "EVP_DigestUpdate() failed");
+ goto failed;
+ }
+
+ EVP_MD_CTX_cleanup(&md);
+
+ if (SSL_CTX_set_session_id_context(ssl->ctx, buf, len) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_set_session_id_context() failed");
+ return NGX_ERROR;
+ }
+
+ return NGX_OK;
+
+failed:
+
+ EVP_MD_CTX_cleanup(&md);
+
+ return NGX_ERROR;
+}
+
+
ngx_int_t
ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
{