Mercurial > hg > nginx
comparison src/event/ngx_event_openssl.c @ 5425:1356a3b96924
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>
author | Piotr Sikora <piotr@cloudflare.com> |
---|---|
date | Fri, 11 Oct 2013 16:05:24 -0700 |
parents | 767aa37f12de |
children | 9868c72f6f43 |
comparison
equal
deleted
inserted
replaced
5424:767aa37f12de | 5425:1356a3b96924 |
---|---|
35 static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); | 35 static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); |
36 static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, | 36 static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, |
37 ngx_slab_pool_t *shpool, ngx_uint_t n); | 37 ngx_slab_pool_t *shpool, ngx_uint_t n); |
38 static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, | 38 static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, |
39 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); | 39 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); |
40 | |
41 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB | |
42 static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, | |
43 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, | |
44 HMAC_CTX *hctx, int enc); | |
45 #endif | |
40 | 46 |
41 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); | 47 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); |
42 static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | 48 static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); |
43 static void ngx_openssl_exit(ngx_cycle_t *cycle); | 49 static void ngx_openssl_exit(ngx_cycle_t *cycle); |
44 | 50 |
80 | 86 |
81 | 87 |
82 int ngx_ssl_connection_index; | 88 int ngx_ssl_connection_index; |
83 int ngx_ssl_server_conf_index; | 89 int ngx_ssl_server_conf_index; |
84 int ngx_ssl_session_cache_index; | 90 int ngx_ssl_session_cache_index; |
91 int ngx_ssl_session_ticket_keys_index; | |
85 int ngx_ssl_certificate_index; | 92 int ngx_ssl_certificate_index; |
86 int ngx_ssl_stapling_index; | 93 int ngx_ssl_stapling_index; |
87 | 94 |
88 | 95 |
89 ngx_int_t | 96 ngx_int_t |
132 } | 139 } |
133 | 140 |
134 ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, | 141 ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, |
135 NULL); | 142 NULL); |
136 if (ngx_ssl_session_cache_index == -1) { | 143 if (ngx_ssl_session_cache_index == -1) { |
144 ngx_ssl_error(NGX_LOG_ALERT, log, 0, | |
145 "SSL_CTX_get_ex_new_index() failed"); | |
146 return NGX_ERROR; | |
147 } | |
148 | |
149 ngx_ssl_session_ticket_keys_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, | |
150 NULL, NULL); | |
151 if (ngx_ssl_session_ticket_keys_index == -1) { | |
137 ngx_ssl_error(NGX_LOG_ALERT, log, 0, | 152 ngx_ssl_error(NGX_LOG_ALERT, log, 0, |
138 "SSL_CTX_get_ex_new_index() failed"); | 153 "SSL_CTX_get_ex_new_index() failed"); |
139 return NGX_ERROR; | 154 return NGX_ERROR; |
140 } | 155 } |
141 | 156 |
2238 node->right = sentinel; | 2253 node->right = sentinel; |
2239 ngx_rbt_red(node); | 2254 ngx_rbt_red(node); |
2240 } | 2255 } |
2241 | 2256 |
2242 | 2257 |
2258 #ifdef SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB | |
2259 | |
2260 ngx_int_t | |
2261 ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) | |
2262 { | |
2263 u_char buf[48]; | |
2264 ssize_t n; | |
2265 ngx_str_t *path; | |
2266 ngx_file_t file; | |
2267 ngx_uint_t i; | |
2268 ngx_array_t *keys; | |
2269 ngx_file_info_t fi; | |
2270 ngx_ssl_session_ticket_key_t *key; | |
2271 | |
2272 if (paths == NULL) { | |
2273 return NGX_OK; | |
2274 } | |
2275 | |
2276 keys = ngx_array_create(cf->pool, paths->nelts, | |
2277 sizeof(ngx_ssl_session_ticket_key_t)); | |
2278 if (keys == NULL) { | |
2279 return NGX_ERROR; | |
2280 } | |
2281 | |
2282 path = paths->elts; | |
2283 for (i = 0; i < paths->nelts; i++) { | |
2284 | |
2285 if (ngx_conf_full_name(cf->cycle, &path[i], 1) != NGX_OK) { | |
2286 return NGX_ERROR; | |
2287 } | |
2288 | |
2289 ngx_memzero(&file, sizeof(ngx_file_t)); | |
2290 file.name = path[i]; | |
2291 file.log = cf->log; | |
2292 | |
2293 file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, 0, 0); | |
2294 if (file.fd == NGX_INVALID_FILE) { | |
2295 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, | |
2296 ngx_open_file_n " \"%V\" failed", &file.name); | |
2297 return NGX_ERROR; | |
2298 } | |
2299 | |
2300 if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { | |
2301 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, | |
2302 ngx_fd_info_n " \"%V\" failed", &file.name); | |
2303 goto failed; | |
2304 } | |
2305 | |
2306 if (ngx_file_size(&fi) != 48) { | |
2307 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2308 "\"%V\" must be 48 bytes", &file.name); | |
2309 goto failed; | |
2310 } | |
2311 | |
2312 n = ngx_read_file(&file, buf, 48, 0); | |
2313 | |
2314 if (n == NGX_ERROR) { | |
2315 ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, | |
2316 ngx_read_file_n " \"%V\" failed", &file.name); | |
2317 goto failed; | |
2318 } | |
2319 | |
2320 if (n != 48) { | |
2321 ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, | |
2322 ngx_read_file_n " \"%V\" returned only " | |
2323 "%z bytes instead of 48", &file.name, n); | |
2324 goto failed; | |
2325 } | |
2326 | |
2327 key = ngx_array_push(keys); | |
2328 if (key == NULL) { | |
2329 goto failed; | |
2330 } | |
2331 | |
2332 ngx_memcpy(key->name, buf, 16); | |
2333 ngx_memcpy(key->aes_key, buf + 16, 16); | |
2334 ngx_memcpy(key->hmac_key, buf + 32, 16); | |
2335 | |
2336 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { | |
2337 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
2338 ngx_close_file_n " \"%V\" failed", &file.name); | |
2339 } | |
2340 } | |
2341 | |
2342 if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_ticket_keys_index, keys) | |
2343 == 0) | |
2344 { | |
2345 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, | |
2346 "SSL_CTX_set_ex_data() failed"); | |
2347 return NGX_ERROR; | |
2348 } | |
2349 | |
2350 if (SSL_CTX_set_tlsext_ticket_key_cb(ssl->ctx, | |
2351 ngx_ssl_session_ticket_key_callback) | |
2352 == 0) | |
2353 { | |
2354 ngx_log_error(NGX_LOG_WARN, cf->log, 0, | |
2355 "nginx was built with Session Tickets support, however, " | |
2356 "now it is linked dynamically to an OpenSSL library " | |
2357 "which has no tlsext support, therefore Session Tickets " | |
2358 "are not available"); | |
2359 } | |
2360 | |
2361 return NGX_OK; | |
2362 | |
2363 failed: | |
2364 | |
2365 if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { | |
2366 ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, | |
2367 ngx_close_file_n " \"%V\" failed", &file.name); | |
2368 } | |
2369 | |
2370 return NGX_ERROR; | |
2371 } | |
2372 | |
2373 | |
2374 #ifdef OPENSSL_NO_SHA256 | |
2375 #define ngx_ssl_session_ticket_md EVP_sha1 | |
2376 #else | |
2377 #define ngx_ssl_session_ticket_md EVP_sha256 | |
2378 #endif | |
2379 | |
2380 | |
2381 static int | |
2382 ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn, | |
2383 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx, | |
2384 HMAC_CTX *hctx, int enc) | |
2385 { | |
2386 SSL_CTX *ssl_ctx; | |
2387 ngx_uint_t i; | |
2388 ngx_array_t *keys; | |
2389 ngx_ssl_session_ticket_key_t *key; | |
2390 #if (NGX_DEBUG) | |
2391 u_char buf[32]; | |
2392 ngx_connection_t *c; | |
2393 #endif | |
2394 | |
2395 ssl_ctx = SSL_get_SSL_CTX(ssl_conn); | |
2396 | |
2397 keys = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_ticket_keys_index); | |
2398 if (keys == NULL) { | |
2399 return -1; | |
2400 } | |
2401 | |
2402 key = keys->elts; | |
2403 | |
2404 #if (NGX_DEBUG) | |
2405 c = ngx_ssl_get_connection(ssl_conn); | |
2406 #endif | |
2407 | |
2408 if (enc == 1) { | |
2409 /* encrypt session ticket */ | |
2410 | |
2411 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
2412 "ssl session ticket encrypt, key: \"%*s\" (%s session)", | |
2413 ngx_hex_dump(buf, key[0].name, 16) - buf, buf, | |
2414 SSL_session_reused(ssl_conn) ? "reused" : "new"); | |
2415 | |
2416 RAND_pseudo_bytes(iv, 16); | |
2417 EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[0].aes_key, iv); | |
2418 HMAC_Init_ex(hctx, key[0].hmac_key, 16, | |
2419 ngx_ssl_session_ticket_md(), NULL); | |
2420 memcpy(name, key[0].name, 16); | |
2421 | |
2422 return 0; | |
2423 | |
2424 } else { | |
2425 /* decrypt session ticket */ | |
2426 | |
2427 for (i = 0; i < keys->nelts; i++) { | |
2428 if (ngx_memcmp(name, key[i].name, 16) == 0) { | |
2429 goto found; | |
2430 } | |
2431 } | |
2432 | |
2433 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
2434 "ssl session ticket decrypt, key: \"%*s\" not found", | |
2435 ngx_hex_dump(buf, name, 16) - buf, buf); | |
2436 | |
2437 return 0; | |
2438 | |
2439 found: | |
2440 | |
2441 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
2442 "ssl session ticket decrypt, key: \"%*s\"%s", | |
2443 ngx_hex_dump(buf, key[i].name, 16) - buf, buf, | |
2444 (i == 0) ? " (default)" : ""); | |
2445 | |
2446 HMAC_Init_ex(hctx, key[i].hmac_key, 16, | |
2447 ngx_ssl_session_ticket_md(), NULL); | |
2448 EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), NULL, key[i].aes_key, iv); | |
2449 | |
2450 return (i == 0) ? 1 : 2 /* renew */; | |
2451 } | |
2452 } | |
2453 | |
2454 #else | |
2455 | |
2456 ngx_int_t | |
2457 ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) | |
2458 { | |
2459 if (paths) { | |
2460 ngx_log_error(NGX_LOG_WARN, ssl->log, 0, | |
2461 "\"ssl_session_ticket_keys\" ignored, not supported"); | |
2462 } | |
2463 | |
2464 return NGX_OK; | |
2465 } | |
2466 | |
2467 #endif | |
2468 | |
2469 | |
2243 void | 2470 void |
2244 ngx_ssl_cleanup_ctx(void *data) | 2471 ngx_ssl_cleanup_ctx(void *data) |
2245 { | 2472 { |
2246 ngx_ssl_t *ssl = data; | 2473 ngx_ssl_t *ssl = data; |
2247 | 2474 |