Mercurial > hg > nginx-quic
comparison src/event/ngx_event_openssl.c @ 974:8dfb3aa75de2
move the session cache callbacks to the ngx_openssl_module
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Wed, 03 Jan 2007 15:25:40 +0000 |
parents | 065b39794fff |
children | 5595e47d4f17 |
comparison
equal
deleted
inserted
replaced
973:e1ede83911ef | 974:8dfb3aa75de2 |
---|---|
20 static void ngx_ssl_write_handler(ngx_event_t *wev); | 20 static void ngx_ssl_write_handler(ngx_event_t *wev); |
21 static void ngx_ssl_read_handler(ngx_event_t *rev); | 21 static void ngx_ssl_read_handler(ngx_event_t *rev); |
22 static void ngx_ssl_shutdown_handler(ngx_event_t *ev); | 22 static void ngx_ssl_shutdown_handler(ngx_event_t *ev); |
23 static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, | 23 static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, |
24 ngx_err_t err, char *text); | 24 ngx_err_t err, char *text); |
25 | |
26 static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone); | |
27 static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, | |
28 ngx_ssl_session_t *sess); | |
29 static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, | |
30 u_char *id, int len, int *copy); | |
31 static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess); | |
32 static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, | |
33 ngx_slab_pool_t *shpool, ngx_uint_t n); | |
34 | |
25 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); | 35 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); |
26 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf); | 36 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf); |
27 static void ngx_openssl_exit(ngx_cycle_t *cycle); | 37 static void ngx_openssl_exit(ngx_cycle_t *cycle); |
28 | 38 |
29 #if !(NGX_SSL_ENGINE) | 39 #if !(NGX_SSL_ENGINE) |
84 }; | 94 }; |
85 | 95 |
86 | 96 |
87 int ngx_ssl_connection_index; | 97 int ngx_ssl_connection_index; |
88 int ngx_ssl_server_conf_index; | 98 int ngx_ssl_server_conf_index; |
99 int ngx_ssl_session_cache_index; | |
89 | 100 |
90 | 101 |
91 ngx_int_t | 102 ngx_int_t |
92 ngx_ssl_init(ngx_log_t *log) | 103 ngx_ssl_init(ngx_log_t *log) |
93 { | 104 { |
110 } | 121 } |
111 | 122 |
112 ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, | 123 ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, |
113 NULL); | 124 NULL); |
114 if (ngx_ssl_server_conf_index == -1) { | 125 if (ngx_ssl_server_conf_index == -1) { |
126 ngx_ssl_error(NGX_LOG_ALERT, log, 0, | |
127 "SSL_CTX_get_ex_new_index() failed"); | |
128 return NGX_ERROR; | |
129 } | |
130 | |
131 ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, | |
132 NULL); | |
133 if (ngx_ssl_session_cache_index == -1) { | |
115 ngx_ssl_error(NGX_LOG_ALERT, log, 0, | 134 ngx_ssl_error(NGX_LOG_ALERT, log, 0, |
116 "SSL_CTX_get_ex_new_index() failed"); | 135 "SSL_CTX_get_ex_new_index() failed"); |
117 return NGX_ERROR; | 136 return NGX_ERROR; |
118 } | 137 } |
119 | 138 |
277 subject = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; | 296 subject = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; |
278 | 297 |
279 name = X509_get_issuer_name(cert); | 298 name = X509_get_issuer_name(cert); |
280 issuer = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; | 299 issuer = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; |
281 | 300 |
282 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, | 301 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, |
283 "verify:%d, error:%d, depth:%d, " | 302 "verify:%d, error:%d, depth:%d, " |
284 "subject:\"%s\",issuer: \"%s\"", | 303 "subject:\"%s\",issuer: \"%s\"", |
285 ok, err, depth, subject, issuer); | 304 ok, err, depth, subject, issuer); |
286 | 305 |
287 return 1; | 306 return 1; |
1031 | 1050 |
1032 if (ev->timedout) { | 1051 if (ev->timedout) { |
1033 c->timedout = 1; | 1052 c->timedout = 1; |
1034 } | 1053 } |
1035 | 1054 |
1036 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "SSL shutdown handler"); | 1055 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler"); |
1037 | 1056 |
1038 if (ngx_ssl_shutdown(c) == NGX_AGAIN) { | 1057 if (ngx_ssl_shutdown(c) == NGX_AGAIN) { |
1039 return; | 1058 return; |
1040 } | 1059 } |
1041 | 1060 |
1117 | 1136 |
1118 ngx_log_error(level, log, err, "%s)", errstr); | 1137 ngx_log_error(level, log, err, "%s)", errstr); |
1119 } | 1138 } |
1120 | 1139 |
1121 | 1140 |
1141 ngx_int_t | |
1142 ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, | |
1143 ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout) | |
1144 { | |
1145 long cache_mode; | |
1146 | |
1147 cache_mode = SSL_SESS_CACHE_SERVER; | |
1148 | |
1149 if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) { | |
1150 cache_mode |= SSL_SESS_CACHE_NO_INTERNAL; | |
1151 } | |
1152 | |
1153 SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode); | |
1154 | |
1155 SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len); | |
1156 | |
1157 if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) { | |
1158 | |
1159 if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) { | |
1160 SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache); | |
1161 } | |
1162 | |
1163 SSL_CTX_set_timeout(ssl->ctx, timeout); | |
1164 } | |
1165 | |
1166 if (shm_zone) { | |
1167 shm_zone->init = ngx_ssl_session_cache_init; | |
1168 | |
1169 SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session); | |
1170 SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session); | |
1171 SSL_CTX_sess_set_remove_cb(ssl->ctx, ngx_ssl_remove_session); | |
1172 | |
1173 if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_cache_index, shm_zone) | |
1174 == 0) | |
1175 { | |
1176 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, | |
1177 "SSL_CTX_set_ex_data() failed"); | |
1178 return NGX_ERROR; | |
1179 } | |
1180 } | |
1181 | |
1182 return NGX_OK; | |
1183 } | |
1184 | |
1185 | |
1186 static ngx_int_t | |
1187 ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone) | |
1188 { | |
1189 ngx_slab_pool_t *shpool; | |
1190 ngx_rbtree_node_t *sentinel; | |
1191 ngx_ssl_session_cache_t *cache; | |
1192 | |
1193 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; | |
1194 | |
1195 cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t)); | |
1196 if (cache == NULL) { | |
1197 return NGX_ERROR; | |
1198 } | |
1199 | |
1200 cache->session_cache_head.prev = NULL; | |
1201 cache->session_cache_head.next = &cache->session_cache_tail; | |
1202 | |
1203 cache->session_cache_tail.prev = &cache->session_cache_head; | |
1204 cache->session_cache_tail.next = NULL; | |
1205 | |
1206 cache->session_rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); | |
1207 if (cache->session_rbtree == NULL) { | |
1208 return NGX_ERROR; | |
1209 } | |
1210 | |
1211 sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); | |
1212 if (sentinel == NULL) { | |
1213 return NGX_ERROR; | |
1214 } | |
1215 | |
1216 ngx_rbtree_sentinel_init(sentinel); | |
1217 | |
1218 cache->session_rbtree->root = sentinel; | |
1219 cache->session_rbtree->sentinel = sentinel; | |
1220 cache->session_rbtree->insert = ngx_rbtree_insert_value; | |
1221 | |
1222 shm_zone->data = cache; | |
1223 | |
1224 return NGX_OK; | |
1225 } | |
1226 | |
1227 | |
1228 /* | |
1229 * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, | |
1230 * so they are outside the code locked by shared pool mutex | |
1231 */ | |
1232 | |
1233 static int | |
1234 ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) | |
1235 { | |
1236 int len; | |
1237 u_char *p, *id; | |
1238 uint32_t hash; | |
1239 SSL_CTX *ssl_ctx; | |
1240 ngx_time_t *tp; | |
1241 ngx_shm_zone_t *shm_zone; | |
1242 ngx_connection_t *c; | |
1243 ngx_slab_pool_t *shpool; | |
1244 ngx_ssl_sess_id_t *sess_id; | |
1245 ngx_ssl_cached_sess_t *cached_sess; | |
1246 ngx_ssl_session_cache_t *cache; | |
1247 u_char buf[NGX_SSL_MAX_SESSION_SIZE]; | |
1248 | |
1249 len = i2d_SSL_SESSION(sess, NULL); | |
1250 | |
1251 /* do not cache too big session */ | |
1252 | |
1253 if (len > (int) NGX_SSL_MAX_SESSION_SIZE) { | |
1254 return 0; | |
1255 } | |
1256 | |
1257 p = buf; | |
1258 i2d_SSL_SESSION(sess, &p); | |
1259 | |
1260 c = ngx_ssl_get_connection(ssl_conn); | |
1261 | |
1262 ssl_ctx = SSL_get_SSL_CTX(ssl_conn); | |
1263 shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index); | |
1264 | |
1265 cache = shm_zone->data; | |
1266 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; | |
1267 | |
1268 ngx_shmtx_lock(&shpool->mutex); | |
1269 | |
1270 /* drop one or two expired sessions */ | |
1271 ngx_ssl_expire_sessions(cache, shpool, 1); | |
1272 | |
1273 cached_sess = ngx_slab_alloc_locked(shpool, | |
1274 offsetof(ngx_ssl_cached_sess_t, asn1) + len); | |
1275 | |
1276 if (cached_sess == NULL) { | |
1277 | |
1278 /* drop the oldest non-expired session and try once more */ | |
1279 | |
1280 ngx_ssl_expire_sessions(cache, shpool, 0); | |
1281 | |
1282 cached_sess = ngx_slab_alloc_locked(shpool, | |
1283 offsetof(ngx_ssl_cached_sess_t, asn1) + len); | |
1284 | |
1285 if (cached_sess == NULL) { | |
1286 id = NULL; | |
1287 goto failed; | |
1288 } | |
1289 } | |
1290 | |
1291 id = ngx_slab_alloc_locked(shpool, sess->session_id_length); | |
1292 if (id == NULL) { | |
1293 goto failed; | |
1294 } | |
1295 | |
1296 sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t)); | |
1297 if (sess_id == NULL) { | |
1298 goto failed; | |
1299 } | |
1300 | |
1301 ngx_memcpy(&cached_sess->asn1[0], buf, len); | |
1302 | |
1303 ngx_memcpy(id, sess->session_id, sess->session_id_length); | |
1304 | |
1305 hash = ngx_crc32_short(sess->session_id, sess->session_id_length); | |
1306 | |
1307 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1308 "http ssl new session: %08XD:%d:%d", | |
1309 hash, sess->session_id_length, len); | |
1310 | |
1311 sess_id->node.key = hash; | |
1312 sess_id->node.data = (u_char) sess->session_id_length; | |
1313 sess_id->id = id; | |
1314 sess_id->len = len; | |
1315 sess_id->session = cached_sess; | |
1316 | |
1317 tp = ngx_timeofday(); | |
1318 | |
1319 cached_sess->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx); | |
1320 cached_sess->sess_id = sess_id; | |
1321 | |
1322 cached_sess->next = cache->session_cache_head.next; | |
1323 cached_sess->next->prev = cached_sess; | |
1324 cached_sess->prev = &cache->session_cache_head; | |
1325 cache->session_cache_head.next = cached_sess; | |
1326 | |
1327 ngx_rbtree_insert(cache->session_rbtree, &sess_id->node); | |
1328 | |
1329 ngx_shmtx_unlock(&shpool->mutex); | |
1330 | |
1331 return 0; | |
1332 | |
1333 failed: | |
1334 | |
1335 if (cached_sess) { | |
1336 ngx_slab_free_locked(shpool, cached_sess); | |
1337 } | |
1338 | |
1339 if (id) { | |
1340 ngx_slab_free_locked(shpool, id); | |
1341 } | |
1342 | |
1343 ngx_shmtx_unlock(&shpool->mutex); | |
1344 | |
1345 ngx_log_error(NGX_LOG_ALERT, c->log, 0, | |
1346 "could not add new SSL session to the session cache"); | |
1347 | |
1348 return 0; | |
1349 } | |
1350 | |
1351 | |
1352 static ngx_ssl_session_t * | |
1353 ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len, | |
1354 int *copy) | |
1355 { | |
1356 #if OPENSSL_VERSION_NUMBER >= 0x00908000 | |
1357 const | |
1358 #endif | |
1359 u_char *p; | |
1360 uint32_t hash; | |
1361 ngx_time_t *tp; | |
1362 ngx_shm_zone_t *shm_zone; | |
1363 ngx_slab_pool_t *shpool; | |
1364 ngx_connection_t *c; | |
1365 ngx_rbtree_node_t *node, *sentinel; | |
1366 ngx_ssl_session_t *sess; | |
1367 ngx_ssl_sess_id_t *sess_id; | |
1368 ngx_ssl_cached_sess_t *cached_sess; | |
1369 ngx_ssl_session_cache_t *cache; | |
1370 u_char buf[NGX_SSL_MAX_SESSION_SIZE]; | |
1371 | |
1372 c = ngx_ssl_get_connection(ssl_conn); | |
1373 | |
1374 hash = ngx_crc32_short(id, len); | |
1375 *copy = 0; | |
1376 | |
1377 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1378 "http ssl get session: %08XD:%d", hash, len); | |
1379 | |
1380 shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn), | |
1381 ngx_ssl_session_cache_index); | |
1382 | |
1383 cache = shm_zone->data; | |
1384 | |
1385 if (cache->session_rbtree == NULL) { | |
1386 return NULL; | |
1387 } | |
1388 | |
1389 sess = NULL; | |
1390 | |
1391 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; | |
1392 | |
1393 ngx_shmtx_lock(&shpool->mutex); | |
1394 | |
1395 node = cache->session_rbtree->root; | |
1396 sentinel = cache->session_rbtree->sentinel; | |
1397 | |
1398 while (node != sentinel) { | |
1399 | |
1400 if (hash < node->key) { | |
1401 node = node->left; | |
1402 continue; | |
1403 } | |
1404 | |
1405 if (hash > node->key) { | |
1406 node = node->right; | |
1407 continue; | |
1408 } | |
1409 | |
1410 if (hash == node->key && (u_char) len == node->data) { | |
1411 sess_id = (ngx_ssl_sess_id_t *) node; | |
1412 | |
1413 if (ngx_strncmp(id, sess_id->id, len) == 0) { | |
1414 | |
1415 cached_sess = sess_id->session; | |
1416 | |
1417 tp = ngx_timeofday(); | |
1418 | |
1419 if (cached_sess->expire > tp->sec) { | |
1420 ngx_memcpy(buf, &cached_sess->asn1[0], sess_id->len); | |
1421 | |
1422 ngx_shmtx_unlock(&shpool->mutex); | |
1423 | |
1424 p = buf; | |
1425 sess = d2i_SSL_SESSION(NULL, &p, sess_id->len); | |
1426 | |
1427 return sess; | |
1428 } | |
1429 | |
1430 cached_sess->next->prev = cached_sess->prev; | |
1431 cached_sess->prev->next = cached_sess->next; | |
1432 | |
1433 ngx_rbtree_delete(cache->session_rbtree, node); | |
1434 | |
1435 ngx_slab_free_locked(shpool, cached_sess); | |
1436 ngx_slab_free_locked(shpool, sess_id->id); | |
1437 ngx_slab_free_locked(shpool, sess_id); | |
1438 | |
1439 sess = NULL; | |
1440 | |
1441 break; | |
1442 } | |
1443 } | |
1444 | |
1445 node = node->right; | |
1446 } | |
1447 | |
1448 ngx_shmtx_unlock(&shpool->mutex); | |
1449 | |
1450 return sess; | |
1451 } | |
1452 | |
1453 | |
1454 static void | |
1455 ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) | |
1456 { | |
1457 u_char *id, len; | |
1458 uint32_t hash; | |
1459 ngx_shm_zone_t *shm_zone; | |
1460 ngx_slab_pool_t *shpool; | |
1461 ngx_rbtree_node_t *node, *sentinel; | |
1462 ngx_ssl_sess_id_t *sess_id; | |
1463 ngx_ssl_cached_sess_t *cached_sess; | |
1464 ngx_ssl_session_cache_t *cache; | |
1465 | |
1466 shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index); | |
1467 | |
1468 cache = shm_zone->data; | |
1469 | |
1470 id = sess->session_id; | |
1471 len = (u_char) sess->session_id_length; | |
1472 | |
1473 hash = ngx_crc32_short(id, (size_t) len); | |
1474 | |
1475 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, | |
1476 "http ssl remove session: %08XD:%d", hash, len); | |
1477 | |
1478 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; | |
1479 | |
1480 ngx_shmtx_lock(&shpool->mutex); | |
1481 | |
1482 node = cache->session_rbtree->root; | |
1483 sentinel = cache->session_rbtree->sentinel; | |
1484 | |
1485 while (node != sentinel) { | |
1486 | |
1487 if (hash < node->key) { | |
1488 node = node->left; | |
1489 continue; | |
1490 } | |
1491 | |
1492 if (hash > node->key) { | |
1493 node = node->right; | |
1494 continue; | |
1495 } | |
1496 | |
1497 if (hash == node->key && len == node->data) { | |
1498 sess_id = (ngx_ssl_sess_id_t *) node; | |
1499 | |
1500 if (ngx_strncmp(id, sess_id->id, (size_t) len) == 0) { | |
1501 | |
1502 cached_sess = sess_id->session; | |
1503 | |
1504 cached_sess->next->prev = cached_sess->prev; | |
1505 cached_sess->prev->next = cached_sess->next; | |
1506 | |
1507 ngx_rbtree_delete(cache->session_rbtree, node); | |
1508 | |
1509 ngx_slab_free_locked(shpool, cached_sess); | |
1510 ngx_slab_free_locked(shpool, sess_id->id); | |
1511 ngx_slab_free_locked(shpool, sess_id); | |
1512 | |
1513 break; | |
1514 } | |
1515 } | |
1516 | |
1517 node = node->right; | |
1518 } | |
1519 | |
1520 ngx_shmtx_unlock(&shpool->mutex); | |
1521 } | |
1522 | |
1523 | |
1524 static void | |
1525 ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache, | |
1526 ngx_slab_pool_t *shpool, ngx_uint_t n) | |
1527 { | |
1528 ngx_time_t *tp; | |
1529 ngx_ssl_sess_id_t *sess_id; | |
1530 ngx_ssl_cached_sess_t *sess; | |
1531 | |
1532 tp = ngx_timeofday(); | |
1533 | |
1534 while (n < 3) { | |
1535 | |
1536 sess = cache->session_cache_tail.prev; | |
1537 | |
1538 if (sess == &cache->session_cache_head) { | |
1539 return; | |
1540 } | |
1541 | |
1542 if (n++ != 0 && sess->expire > tp->sec) { | |
1543 break; | |
1544 } | |
1545 | |
1546 sess->next->prev = sess->prev; | |
1547 sess->prev->next = sess->next; | |
1548 | |
1549 sess_id = sess->sess_id; | |
1550 | |
1551 ngx_rbtree_delete(cache->session_rbtree, &sess_id->node); | |
1552 | |
1553 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, | |
1554 "expire session: %08Xi", sess_id->node.key); | |
1555 | |
1556 ngx_slab_free_locked(shpool, sess); | |
1557 ngx_slab_free_locked(shpool, sess_id->id); | |
1558 ngx_slab_free_locked(shpool, sess_id); | |
1559 } | |
1560 } | |
1561 | |
1562 | |
1122 void | 1563 void |
1123 ngx_ssl_cleanup_ctx(void *data) | 1564 ngx_ssl_cleanup_ctx(void *data) |
1124 { | 1565 { |
1125 ngx_ssl_t *ssl = data; | 1566 ngx_ssl_t *ssl = data; |
1126 | 1567 |