Klaus Demo nginx / 79be6a5
SSL: added ability to set keys used for Session Tickets (RFC5077). In order to support key rollover, ssl_session_ticket_key can be defined multiple times. The first key will be used to issue and resume Session Tickets, while the rest will be used only to resume them. ssl_session_ticket_key session_tickets/current.key; ssl_session_ticket_key session_tickets/prev-1h.key; ssl_session_ticket_key session_tickets/prev-2h.key; Please note that nginx supports Session Tickets even without explicit configuration of the keys and this feature should be only used in setups where SSL traffic is distributed across multiple nginx servers. Signed-off-by: Piotr Sikora <piotr@cloudflare.com> Piotr Sikora 8 years ago
6 changed file(s) with 278 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
3636 ngx_slab_pool_t *shpool, ngx_uint_t n);
3737 static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
3838 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
39
40 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
41 static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
42 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
43 HMAC_CTX *hctx, int enc);
44 #endif
3945
4046 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
4147 static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
8187 int ngx_ssl_connection_index;
8288 int ngx_ssl_server_conf_index;
8389 int ngx_ssl_session_cache_index;
90 int ngx_ssl_session_ticket_keys_index;
8491 int ngx_ssl_certificate_index;
8592 int ngx_ssl_stapling_index;
8693
133140 ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
134141 NULL);
135142 if (ngx_ssl_session_cache_index == -1) {
143 ngx_ssl_error(NGX_LOG_ALERT, log, 0,
144 "SSL_CTX_get_ex_new_index() failed");
145 return NGX_ERROR;
146 }
147
148 ngx_ssl_session_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL,
149 NULL, NULL);
150 if (ngx_ssl_session_ticket_keys_index == -1) {
136151 ngx_ssl_error(NGX_LOG_ALERT, log, 0,
137152 "SSL_CTX_get_ex_new_index() failed");
138153 return NGX_ERROR;
22392254 }
22402255
22412256
2257 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
2258
2259 ngx_int_t
2260 ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
2261 {
2262 u_char buf[48];
2263 ssize_t n;
2264 ngx_str_t *path;
2265 ngx_file_t file;
2266 ngx_uint_t i;
2267 ngx_array_t *keys;
2268 ngx_file_info_t fi;
2269 ngx_ssl_session_ticket_key_t *key;
2270
2271 if (paths == NULL) {
2272 return NGX_OK;
2273 }
2274
2275 keys = ngx_array_create(cf->pool, paths->nelts,
2276 sizeof(ngx_ssl_session_ticket_key_t));
2277 if (keys == NULL) {
2278 return NGX_ERROR;
2279 }
2280
2281 path = paths->elts;
2282 for (i = 0; i < paths->nelts; i++) {
2283
2284 if (ngx_conf_full_name(cf->cycle, &path[i], 1) != NGX_OK) {
2285 return NGX_ERROR;
2286 }
2287
2288 ngx_memzero(&file, sizeof(ngx_file_t));
2289 file.name = path[i];
2290 file.log = cf->log;
2291
2292 file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, 0, 0);
2293 if (file.fd == NGX_INVALID_FILE) {
2294 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
2295 ngx_open_file_n " \"%V\" failed", &file.name);
2296 return NGX_ERROR;
2297 }
2298
2299 if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) {
2300 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
2301 ngx_fd_info_n " \"%V\" failed", &file.name);
2302 goto failed;
2303 }
2304
2305 if (ngx_file_size(&fi) != 48) {
2306 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
2307 "\"%V\" must be 48 bytes", &file.name);
2308 goto failed;
2309 }
2310
2311 n = ngx_read_file(&file, buf, 48, 0);
2312
2313 if (n == NGX_ERROR) {
2314 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno,
2315 ngx_read_file_n " \"%V\" failed", &file.name);
2316 goto failed;
2317 }
2318
2319 if (n != 48) {
2320 ngx_conf_log_error(NGX_LOG_CRIT, cf, 0,
2321 ngx_read_file_n " \"%V\" returned only "
2322 "%z bytes instead of 48", &file.name, n);
2323 goto failed;
2324 }
2325
2326 key = ngx_array_push(keys);
2327 if (key == NULL) {
2328 goto failed;
2329 }
2330
2331 ngx_memcpy(key->name, buf, 16);
2332 ngx_memcpy(key->aes_key, buf + 16, 16);
2333 ngx_memcpy(key->hmac_key, buf + 32, 16);
2334
2335 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
2336 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
2337 ngx_close_file_n " \"%V\" failed", &file.name);
2338 }
2339 }
2340
2341 if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys)
2342 == 0)
2343 {
2344 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
2345 "SSL_CTX_set_ex_data() failed");
2346 return NGX_ERROR;
2347 }
2348
2349 if (SSL_CTX_set_tlsext_ticket_key_cb(ssl->ctx,
2350 ngx_ssl_session_ticket_key_callback)
2351 == 0)
2352 {
2353 ngx_log_error(NGX_LOG_WARN, cf->log, 0,
2354 "nginx was built with Session Tickets support, however, "
2355 "now it is linked dynamically to an OpenSSL library "
2356 "which has no tlsext support, therefore Session Tickets "
2357 "are not available");
2358 }
2359
2360 return NGX_OK;
2361
2362 failed:
2363
2364 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) {
2365 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
2366 ngx_close_file_n " \"%V\" failed", &file.name);
2367 }
2368
2369 return NGX_ERROR;
2370 }
2371
2372
2373 #ifdef OPENSSL_NO_SHA256
2374 #define ngx_ssl_session_ticket_md EVP_sha1
2375 #else
2376 #define ngx_ssl_session_ticket_md EVP_sha256
2377 #endif
2378
2379
2380 static int
2381 ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
2382 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
2383 HMAC_CTX *hctx, int enc)
2384 {
2385 SSL_CTX *ssl_ctx;
2386 ngx_uint_t i;
2387 ngx_array_t *keys;
2388 ngx_ssl_session_ticket_key_t *key;
2389 #if (NGX_DEBUG)
2390 u_char buf[32];
2391 ngx_connection_t *c;
2392 #endif
2393
2394 ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
2395
2396 keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index);
2397 if (keys == NULL) {
2398 return -1;
2399 }
2400
2401 key = keys->elts;
2402
2403 #if (NGX_DEBUG)
2404 c = ngx_ssl_get_connection(ssl_conn);
2405 #endif
2406
2407 if (enc == 1) {
2408 /* encrypt session ticket */
2409
2410 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
2411 "ssl session ticket encrypt, key: \"%*s\" (%s session)",
2412 ngx_hex_dump(buf, key[0].name, 16) - buf, buf,
2413 SSL_session_reused(ssl_conn) ? "reused" : "new");
2414
2415 RAND_pseudo_bytes(iv, 16);
2416 EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[0].aes_key, iv);
2417 HMAC_Init_ex(hctx, key[0].hmac_key, 16,
2418 ngx_ssl_session_ticket_md(), NULL);
2419 memcpy(name, key[0].name, 16);
2420
2421 return 0;
2422
2423 } else {
2424 /* decrypt session ticket */
2425
2426 for (i = 0; i < keys->nelts; i++) {
2427 if (ngx_memcmp(name, key[i].name, 16) == 0) {
2428 goto found;
2429 }
2430 }
2431
2432 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
2433 "ssl session ticket decrypt, key: \"%*s\" not found",
2434 ngx_hex_dump(buf, name, 16) - buf, buf);
2435
2436 return 0;
2437
2438 found:
2439
2440 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
2441 "ssl session ticket decrypt, key: \"%*s\"%s",
2442 ngx_hex_dump(buf, key[i].name, 16) - buf, buf,
2443 (i == 0) ? " (default)" : "");
2444
2445 HMAC_Init_ex(hctx, key[i].hmac_key, 16,
2446 ngx_ssl_session_ticket_md(), NULL);
2447 EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[i].aes_key, iv);
2448
2449 return (i == 0) ? 1 : 2 /* renew */;
2450 }
2451 }
2452
2453 #else
2454
2455 ngx_int_t
2456 ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths)
2457 {
2458 if (paths) {
2459 ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
2460 "\"ssl_session_ticket_keys\" ignored, not supported");
2461 }
2462
2463 return NGX_OK;
2464 }
2465
2466 #endif
2467
2468
22422469 void
22432470 ngx_ssl_cleanup_ctx(void *data)
22442471 {
8282 } ngx_ssl_session_cache_t;
8383
8484
85 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB
86
87 typedef struct {
88 u_char name[16];
89 u_char aes_key[16];
90 u_char hmac_key[16];
91 } ngx_ssl_session_ticket_key_t;
92
93 #endif
94
8595
8696 #define NGX_SSL_SSLv2 0x0002
8797 #define NGX_SSL_SSLv3 0x0004
115125 ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
116126 ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
117127 ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout);
128 ngx_int_t ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl,
129 ngx_array_t *paths);
118130 ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
119131 ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c,
120132 ngx_uint_t flags);
172184 extern int ngx_ssl_connection_index;
173185 extern int ngx_ssl_server_conf_index;
174186 extern int ngx_ssl_session_cache_index;
187 extern int ngx_ssl_session_ticket_keys_index;
175188 extern int ngx_ssl_certificate_index;
176189 extern int ngx_ssl_stapling_index;
177190
150150 ngx_http_ssl_session_cache,
151151 NGX_HTTP_SRV_CONF_OFFSET,
152152 0,
153 NULL },
154
155 { ngx_string("ssl_session_ticket_key"),
156 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
157 ngx_conf_set_str_array_slot,
158 NGX_HTTP_SRV_CONF_OFFSET,
159 offsetof(ngx_http_ssl_srv_conf_t, session_ticket_keys),
153160 NULL },
154161
155162 { ngx_string("ssl_session_timeout"),
420427 sscf->verify_depth = NGX_CONF_UNSET_UINT;
421428 sscf->builtin_session_cache = NGX_CONF_UNSET;
422429 sscf->session_timeout = NGX_CONF_UNSET;
430 sscf->session_ticket_keys = NGX_CONF_UNSET_PTR;
423431 sscf->stapling = NGX_CONF_UNSET;
424432 sscf->stapling_verify = NGX_CONF_UNSET;
425433
622630 return NGX_CONF_ERROR;
623631 }
624632
633 ngx_conf_merge_ptr_value(conf->session_ticket_keys,
634 prev->session_ticket_keys, NULL);
635
636 if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys)
637 != NGX_OK)
638 {
639 return NGX_CONF_ERROR;
640 }
641
625642 if (conf->stapling) {
626643
627644 if (ngx_ssl_stapling(cf, &conf->ssl, &conf->stapling_file,
4141
4242 ngx_shm_zone_t *shm_zone;
4343
44 ngx_array_t *session_ticket_keys;
45
4446 ngx_flag_t stapling;
4547 ngx_flag_t stapling_verify;
4648 ngx_str_t stapling_file;
113113 ngx_mail_ssl_session_cache,
114114 NGX_MAIL_SRV_CONF_OFFSET,
115115 0,
116 NULL },
117
118 { ngx_string("ssl_session_ticket_key"),
119 NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
120 ngx_conf_set_str_array_slot,
121 NGX_MAIL_SRV_CONF_OFFSET,
122 offsetof(ngx_mail_ssl_conf_t, session_ticket_keys),
116123 NULL },
117124
118125 { ngx_string("ssl_session_timeout"),
183190 scf->prefer_server_ciphers = NGX_CONF_UNSET;
184191 scf->builtin_session_cache = NGX_CONF_UNSET;
185192 scf->session_timeout = NGX_CONF_UNSET;
193 scf->session_ticket_keys = NGX_CONF_UNSET_PTR;
186194
187195 return scf;
188196 }
330338 return NGX_CONF_ERROR;
331339 }
332340
341 ngx_conf_merge_ptr_value(conf->session_ticket_keys,
342 prev->session_ticket_keys, NULL);
343
344 if (ngx_ssl_session_ticket_keys(cf, &conf->ssl, conf->session_ticket_keys)
345 != NGX_OK)
346 {
347 return NGX_CONF_ERROR;
348 }
349
333350 return NGX_CONF_OK;
334351 }
335352
4040
4141 ngx_shm_zone_t *shm_zone;
4242
43 ngx_array_t *session_ticket_keys;
44
4345 u_char *file;
4446 ngx_uint_t line;
4547 } ngx_mail_ssl_conf_t;