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