comparison src/event/ngx_event_openssl.c @ 272:29a6403156b0 NGINX_0_5_6

nginx 0.5.6 *) Change: now the ngx_http_index_module ignores all methods except the GET, HEAD, and POST methods. *) Feature: the ngx_http_limit_zone_module. *) Feature: the $binary_remote_addr variable. *) Feature: the "ssl_session_cache" directives of the ngx_http_ssl_module and ngx_imap_ssl_module. *) Feature: the DELETE method supports recursive removal. *) Bugfix: the byte-ranges were transferred incorrectly if the $r->sendfile() was used.
author Igor Sysoev <http://sysoev.ru>
date Tue, 09 Jan 2007 00:00:00 +0300
parents 559bc7ec214e
children 052a7b1d40e5
comparison
equal deleted inserted replaced
271:fcbee7dacf2b 272:29a6403156b0
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 void *data);
28 static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,
29 ngx_ssl_session_t *sess);
30 static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
31 u_char *id, int len, int *copy);
32 static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
33 static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
34 ngx_slab_pool_t *shpool, ngx_uint_t n);
35
25 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); 36 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
26 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf); 37 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf);
27 static void ngx_openssl_exit(ngx_cycle_t *cycle); 38 static void ngx_openssl_exit(ngx_cycle_t *cycle);
28 39
29 #if !(NGX_SSL_ENGINE) 40 #if !(NGX_SSL_ENGINE)
82 SSL_OP_NO_SSLv2, 93 SSL_OP_NO_SSLv2,
83 0, 94 0,
84 }; 95 };
85 96
86 97
87 int ngx_connection_index; 98 int ngx_ssl_connection_index;
99 int ngx_ssl_server_conf_index;
100 int ngx_ssl_session_cache_index;
88 101
89 102
90 ngx_int_t 103 ngx_int_t
91 ngx_ssl_init(ngx_log_t *log) 104 ngx_ssl_init(ngx_log_t *log)
92 { 105 {
106 #if OPENSSL_VERSION_NUMBER >= 0x00907000
107 OPENSSL_config(NULL);
108 #endif
109
93 SSL_library_init(); 110 SSL_library_init();
94 SSL_load_error_strings(); 111 SSL_load_error_strings();
95 112
96 #if (NGX_SSL_ENGINE) 113 #if (NGX_SSL_ENGINE)
97 ENGINE_load_builtin_engines(); 114 ENGINE_load_builtin_engines();
98 #endif 115 #endif
99 116
100 ngx_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 117 ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
101 118
102 if (ngx_connection_index == -1) { 119 if (ngx_ssl_connection_index == -1) {
103 ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed"); 120 ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed");
104 return NGX_ERROR; 121 return NGX_ERROR;
105 } 122 }
106 123
124 ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
125 NULL);
126 if (ngx_ssl_server_conf_index == -1) {
127 ngx_ssl_error(NGX_LOG_ALERT, log, 0,
128 "SSL_CTX_get_ex_new_index() failed");
129 return NGX_ERROR;
130 }
131
132 ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
133 NULL);
134 if (ngx_ssl_session_cache_index == -1) {
135 ngx_ssl_error(NGX_LOG_ALERT, log, 0,
136 "SSL_CTX_get_ex_new_index() failed");
137 return NGX_ERROR;
138 }
139
107 return NGX_OK; 140 return NGX_OK;
108 } 141 }
109 142
110 143
111 ngx_int_t 144 ngx_int_t
112 ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols) 145 ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
113 { 146 {
114 ssl->ctx = SSL_CTX_new(SSLv23_method()); 147 ssl->ctx = SSL_CTX_new(SSLv23_method());
115 148
116 if (ssl->ctx == NULL) { 149 if (ssl->ctx == NULL) {
117 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed"); 150 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed");
151 return NGX_ERROR;
152 }
153
154 if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_server_conf_index, data) == 0) {
155 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
156 "SSL_CTX_set_ex_data() failed");
118 return NGX_ERROR; 157 return NGX_ERROR;
119 } 158 }
120 159
121 /* client side options */ 160 /* client side options */
122 161
258 subject = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; 297 subject = name ? X509_NAME_oneline(name, NULL, 0) : "(none)";
259 298
260 name = X509_get_issuer_name(cert); 299 name = X509_get_issuer_name(cert);
261 issuer = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; 300 issuer = name ? X509_NAME_oneline(name, NULL, 0) : "(none)";
262 301
263 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0, 302 ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
264 "verify:%d, error:%d, depth:%d, " 303 "verify:%d, error:%d, depth:%d, "
265 "subject:\"%s\",issuer: \"%s\"", 304 "subject:\"%s\",issuer: \"%s\"",
266 ok, err, depth, subject, issuer); 305 ok, err, depth, subject, issuer);
267 306
268 return 1; 307 return 1;
330 369
331 } else { 370 } else {
332 SSL_set_accept_state(sc->connection); 371 SSL_set_accept_state(sc->connection);
333 } 372 }
334 373
335 if (SSL_set_ex_data(sc->connection, ngx_connection_index, c) == 0) { 374 if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) {
336 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed"); 375 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed");
337 return NGX_ERROR; 376 return NGX_ERROR;
338 } 377 }
339 378
340 c->ssl = sc; 379 c->ssl = sc;
1012 1051
1013 if (ev->timedout) { 1052 if (ev->timedout) {
1014 c->timedout = 1; 1053 c->timedout = 1;
1015 } 1054 }
1016 1055
1017 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "SSL shutdown handler"); 1056 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler");
1018 1057
1019 if (ngx_ssl_shutdown(c) == NGX_AGAIN) { 1058 if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
1020 return; 1059 return;
1021 } 1060 }
1022 1061
1098 1137
1099 ngx_log_error(level, log, err, "%s)", errstr); 1138 ngx_log_error(level, log, err, "%s)", errstr);
1100 } 1139 }
1101 1140
1102 1141
1142 ngx_int_t
1143 ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
1144 ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout)
1145 {
1146 long cache_mode;
1147
1148 cache_mode = SSL_SESS_CACHE_SERVER;
1149
1150 if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) {
1151 cache_mode |= SSL_SESS_CACHE_NO_INTERNAL;
1152 }
1153
1154 SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode);
1155
1156 SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len);
1157
1158 if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) {
1159
1160 if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) {
1161 SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache);
1162 }
1163
1164 SSL_CTX_set_timeout(ssl->ctx, timeout);
1165 }
1166
1167 if (shm_zone) {
1168 shm_zone->init = ngx_ssl_session_cache_init;
1169
1170 SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session);
1171 SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session);
1172 SSL_CTX_sess_set_remove_cb(ssl->ctx, ngx_ssl_remove_session);
1173
1174 if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_cache_index, shm_zone)
1175 == 0)
1176 {
1177 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
1178 "SSL_CTX_set_ex_data() failed");
1179 return NGX_ERROR;
1180 }
1181 }
1182
1183 return NGX_OK;
1184 }
1185
1186
1187 static ngx_int_t
1188 ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
1189 {
1190 ngx_slab_pool_t *shpool;
1191 ngx_rbtree_node_t *sentinel;
1192 ngx_ssl_session_cache_t *cache;
1193
1194 if (data) {
1195 shm_zone->data = data;
1196 return NGX_OK;
1197 }
1198
1199 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
1200
1201 cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));
1202 if (cache == NULL) {
1203 return NGX_ERROR;
1204 }
1205
1206 cache->session_cache_head.prev = NULL;
1207 cache->session_cache_head.next = &cache->session_cache_tail;
1208
1209 cache->session_cache_tail.prev = &cache->session_cache_head;
1210 cache->session_cache_tail.next = NULL;
1211
1212 cache->session_rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
1213 if (cache->session_rbtree == NULL) {
1214 return NGX_ERROR;
1215 }
1216
1217 sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
1218 if (sentinel == NULL) {
1219 return NGX_ERROR;
1220 }
1221
1222 ngx_rbtree_sentinel_init(sentinel);
1223
1224 cache->session_rbtree->root = sentinel;
1225 cache->session_rbtree->sentinel = sentinel;
1226 cache->session_rbtree->insert = ngx_rbtree_insert_value;
1227
1228 shm_zone->data = cache;
1229
1230 return NGX_OK;
1231 }
1232
1233
1234 /*
1235 * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow,
1236 * so they are outside the code locked by shared pool mutex
1237 */
1238
1239 static int
1240 ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess)
1241 {
1242 int len;
1243 u_char *p, *id;
1244 uint32_t hash;
1245 SSL_CTX *ssl_ctx;
1246 ngx_time_t *tp;
1247 ngx_shm_zone_t *shm_zone;
1248 ngx_connection_t *c;
1249 ngx_slab_pool_t *shpool;
1250 ngx_ssl_sess_id_t *sess_id;
1251 ngx_ssl_cached_sess_t *cached_sess;
1252 ngx_ssl_session_cache_t *cache;
1253 u_char buf[NGX_SSL_MAX_SESSION_SIZE];
1254
1255 len = i2d_SSL_SESSION(sess, NULL);
1256
1257 /* do not cache too big session */
1258
1259 if (len > (int) NGX_SSL_MAX_SESSION_SIZE) {
1260 return 0;
1261 }
1262
1263 p = buf;
1264 i2d_SSL_SESSION(sess, &p);
1265
1266 c = ngx_ssl_get_connection(ssl_conn);
1267
1268 ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
1269 shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index);
1270
1271 cache = shm_zone->data;
1272 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
1273
1274 ngx_shmtx_lock(&shpool->mutex);
1275
1276 /* drop one or two expired sessions */
1277 ngx_ssl_expire_sessions(cache, shpool, 1);
1278
1279 cached_sess = ngx_slab_alloc_locked(shpool,
1280 offsetof(ngx_ssl_cached_sess_t, asn1) + len);
1281
1282 if (cached_sess == NULL) {
1283
1284 /* drop the oldest non-expired session and try once more */
1285
1286 ngx_ssl_expire_sessions(cache, shpool, 0);
1287
1288 cached_sess = ngx_slab_alloc_locked(shpool,
1289 offsetof(ngx_ssl_cached_sess_t, asn1) + len);
1290
1291 if (cached_sess == NULL) {
1292 id = NULL;
1293 goto failed;
1294 }
1295 }
1296
1297 id = ngx_slab_alloc_locked(shpool, sess->session_id_length);
1298 if (id == NULL) {
1299 goto failed;
1300 }
1301
1302 sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
1303 if (sess_id == NULL) {
1304 goto failed;
1305 }
1306
1307 ngx_memcpy(&cached_sess->asn1[0], buf, len);
1308
1309 ngx_memcpy(id, sess->session_id, sess->session_id_length);
1310
1311 hash = ngx_crc32_short(sess->session_id, sess->session_id_length);
1312
1313 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
1314 "http ssl new session: %08XD:%d:%d",
1315 hash, sess->session_id_length, len);
1316
1317 sess_id->node.key = hash;
1318 sess_id->node.data = (u_char) sess->session_id_length;
1319 sess_id->id = id;
1320 sess_id->len = len;
1321 sess_id->session = cached_sess;
1322
1323 tp = ngx_timeofday();
1324
1325 cached_sess->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx);
1326 cached_sess->sess_id = sess_id;
1327
1328 cached_sess->next = cache->session_cache_head.next;
1329 cached_sess->next->prev = cached_sess;
1330 cached_sess->prev = &cache->session_cache_head;
1331 cache->session_cache_head.next = cached_sess;
1332
1333 ngx_rbtree_insert(cache->session_rbtree, &sess_id->node);
1334
1335 ngx_shmtx_unlock(&shpool->mutex);
1336
1337 return 0;
1338
1339 failed:
1340
1341 if (cached_sess) {
1342 ngx_slab_free_locked(shpool, cached_sess);
1343 }
1344
1345 if (id) {
1346 ngx_slab_free_locked(shpool, id);
1347 }
1348
1349 ngx_shmtx_unlock(&shpool->mutex);
1350
1351 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
1352 "could not add new SSL session to the session cache");
1353
1354 return 0;
1355 }
1356
1357
1358 static ngx_ssl_session_t *
1359 ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len,
1360 int *copy)
1361 {
1362 #if OPENSSL_VERSION_NUMBER >= 0x0090707fL
1363 const
1364 #endif
1365 u_char *p;
1366 uint32_t hash;
1367 ngx_time_t *tp;
1368 ngx_shm_zone_t *shm_zone;
1369 ngx_slab_pool_t *shpool;
1370 ngx_connection_t *c;
1371 ngx_rbtree_node_t *node, *sentinel;
1372 ngx_ssl_session_t *sess;
1373 ngx_ssl_sess_id_t *sess_id;
1374 ngx_ssl_cached_sess_t *cached_sess;
1375 ngx_ssl_session_cache_t *cache;
1376 u_char buf[NGX_SSL_MAX_SESSION_SIZE];
1377
1378 c = ngx_ssl_get_connection(ssl_conn);
1379
1380 hash = ngx_crc32_short(id, len);
1381 *copy = 0;
1382
1383 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1384 "http ssl get session: %08XD:%d", hash, len);
1385
1386 shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn),
1387 ngx_ssl_session_cache_index);
1388
1389 cache = shm_zone->data;
1390
1391 if (cache->session_rbtree == NULL) {
1392 return NULL;
1393 }
1394
1395 sess = NULL;
1396
1397 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
1398
1399 ngx_shmtx_lock(&shpool->mutex);
1400
1401 node = cache->session_rbtree->root;
1402 sentinel = cache->session_rbtree->sentinel;
1403
1404 while (node != sentinel) {
1405
1406 if (hash < node->key) {
1407 node = node->left;
1408 continue;
1409 }
1410
1411 if (hash > node->key) {
1412 node = node->right;
1413 continue;
1414 }
1415
1416 if (hash == node->key && (u_char) len == node->data) {
1417 sess_id = (ngx_ssl_sess_id_t *) node;
1418
1419 if (ngx_strncmp(id, sess_id->id, len) == 0) {
1420
1421 cached_sess = sess_id->session;
1422
1423 tp = ngx_timeofday();
1424
1425 if (cached_sess->expire > tp->sec) {
1426 ngx_memcpy(buf, &cached_sess->asn1[0], sess_id->len);
1427
1428 ngx_shmtx_unlock(&shpool->mutex);
1429
1430 p = buf;
1431 sess = d2i_SSL_SESSION(NULL, &p, sess_id->len);
1432
1433 return sess;
1434 }
1435
1436 cached_sess->next->prev = cached_sess->prev;
1437 cached_sess->prev->next = cached_sess->next;
1438
1439 ngx_rbtree_delete(cache->session_rbtree, node);
1440
1441 ngx_slab_free_locked(shpool, cached_sess);
1442 ngx_slab_free_locked(shpool, sess_id->id);
1443 ngx_slab_free_locked(shpool, sess_id);
1444
1445 sess = NULL;
1446
1447 break;
1448 }
1449 }
1450
1451 node = node->right;
1452 }
1453
1454 ngx_shmtx_unlock(&shpool->mutex);
1455
1456 return sess;
1457 }
1458
1459
1460 static void
1461 ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
1462 {
1463 u_char *id, len;
1464 uint32_t hash;
1465 ngx_shm_zone_t *shm_zone;
1466 ngx_slab_pool_t *shpool;
1467 ngx_rbtree_node_t *node, *sentinel;
1468 ngx_ssl_sess_id_t *sess_id;
1469 ngx_ssl_cached_sess_t *cached_sess;
1470 ngx_ssl_session_cache_t *cache;
1471
1472 shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index);
1473
1474 cache = shm_zone->data;
1475
1476 id = sess->session_id;
1477 len = (u_char) sess->session_id_length;
1478
1479 hash = ngx_crc32_short(id, (size_t) len);
1480
1481 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
1482 "http ssl remove session: %08XD:%d", hash, len);
1483
1484 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
1485
1486 ngx_shmtx_lock(&shpool->mutex);
1487
1488 node = cache->session_rbtree->root;
1489 sentinel = cache->session_rbtree->sentinel;
1490
1491 while (node != sentinel) {
1492
1493 if (hash < node->key) {
1494 node = node->left;
1495 continue;
1496 }
1497
1498 if (hash > node->key) {
1499 node = node->right;
1500 continue;
1501 }
1502
1503 if (hash == node->key && len == node->data) {
1504 sess_id = (ngx_ssl_sess_id_t *) node;
1505
1506 if (ngx_strncmp(id, sess_id->id, (size_t) len) == 0) {
1507
1508 cached_sess = sess_id->session;
1509
1510 cached_sess->next->prev = cached_sess->prev;
1511 cached_sess->prev->next = cached_sess->next;
1512
1513 ngx_rbtree_delete(cache->session_rbtree, node);
1514
1515 ngx_slab_free_locked(shpool, cached_sess);
1516 ngx_slab_free_locked(shpool, sess_id->id);
1517 ngx_slab_free_locked(shpool, sess_id);
1518
1519 break;
1520 }
1521 }
1522
1523 node = node->right;
1524 }
1525
1526 ngx_shmtx_unlock(&shpool->mutex);
1527 }
1528
1529
1530 static void
1531 ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
1532 ngx_slab_pool_t *shpool, ngx_uint_t n)
1533 {
1534 ngx_time_t *tp;
1535 ngx_ssl_sess_id_t *sess_id;
1536 ngx_ssl_cached_sess_t *sess;
1537
1538 tp = ngx_timeofday();
1539
1540 while (n < 3) {
1541
1542 sess = cache->session_cache_tail.prev;
1543
1544 if (sess == &cache->session_cache_head) {
1545 return;
1546 }
1547
1548 if (n++ != 0 && sess->expire > tp->sec) {
1549 break;
1550 }
1551
1552 sess->next->prev = sess->prev;
1553 sess->prev->next = sess->next;
1554
1555 sess_id = sess->sess_id;
1556
1557 ngx_rbtree_delete(cache->session_rbtree, &sess_id->node);
1558
1559 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
1560 "expire session: %08Xi", sess_id->node.key);
1561
1562 ngx_slab_free_locked(shpool, sess);
1563 ngx_slab_free_locked(shpool, sess_id->id);
1564 ngx_slab_free_locked(shpool, sess_id);
1565 }
1566 }
1567
1568
1103 void 1569 void
1104 ngx_ssl_cleanup_ctx(void *data) 1570 ngx_ssl_cleanup_ctx(void *data)
1105 { 1571 {
1106 ngx_ssl_t *ssl = data; 1572 ngx_ssl_t *ssl = data;
1107 1573