Klaus Demo nginx / 27475dd
Upstream: proxy_ssl_verify and friends. Maxim Dounin 8 years ago
5 changed file(s) with 255 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
4141 static int ngx_ssl_session_ticket_key_callback(ngx_ssl_conn_t *ssl_conn,
4242 unsigned char *name, unsigned char *iv, EVP_CIPHER_CTX *ectx,
4343 HMAC_CTX *hctx, int enc);
44 #endif
45
46 #if OPENSSL_VERSION_NUMBER < 0x10002001L
47 static ngx_int_t ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *str);
4448 #endif
4549
4650 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
24862490
24872491
24882492 ngx_int_t
2493 ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name)
2494 {
2495 X509 *cert;
2496
2497 cert = SSL_get_peer_certificate(c->ssl->connection);
2498 if (cert == NULL) {
2499 return NGX_ERROR;
2500 }
2501
2502 #if OPENSSL_VERSION_NUMBER >= 0x10002001L
2503
2504 /* X509_check_host() is only available in OpenSSL 1.0.2+ */
2505
2506 if (X509_check_host(cert, name->data, name->len, 0) != 1) {
2507 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
2508 "X509_check_host(): no match");
2509 goto failed;
2510 }
2511
2512 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
2513 "X509_check_host(): match");
2514
2515 goto found;
2516
2517 #else
2518 {
2519 int n, i;
2520 X509_NAME *sname;
2521 ASN1_STRING *str;
2522 X509_NAME_ENTRY *entry;
2523 GENERAL_NAME *altname;
2524 STACK_OF(GENERAL_NAME) *altnames;
2525
2526 /*
2527 * As per RFC6125 and RFC2818, we check subjectAltName extension,
2528 * and if it's not present - commonName in Subject is checked.
2529 */
2530
2531 altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
2532
2533 if (altnames) {
2534 n = sk_GENERAL_NAME_num(altnames);
2535
2536 for (i = 0; i < n; i++) {
2537 altname = sk_GENERAL_NAME_value(altnames, i);
2538
2539 if (altname->type != GEN_DNS) {
2540 continue;
2541 }
2542
2543 str = altname->d.dNSName;
2544
2545 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
2546 "SSL subjectAltName: \"%*s\"",
2547 ASN1_STRING_length(str), ASN1_STRING_data(str));
2548
2549 if (ngx_ssl_check_name(name, str) == NGX_OK) {
2550 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
2551 "SSL subjectAltName: match");
2552 GENERAL_NAMES_free(altnames);
2553 goto found;
2554 }
2555 }
2556
2557 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
2558 "SSL subjectAltName: no match");
2559
2560 GENERAL_NAMES_free(altnames);
2561 goto failed;
2562 }
2563
2564 /*
2565 * If there is no subjectAltName extension, check commonName
2566 * in Subject. While RFC2818 requires to only check "most specific"
2567 * CN, both Apache and OpenSSL check all CNs, and so do we.
2568 */
2569
2570 sname = X509_get_subject_name(cert);
2571
2572 if (sname == NULL) {
2573 goto failed;
2574 }
2575
2576 i = -1;
2577 for ( ;; ) {
2578 i = X509_NAME_get_index_by_NID(sname, NID_commonName, i);
2579
2580 if (i < 0) {
2581 break;
2582 }
2583
2584 entry = X509_NAME_get_entry(sname, i);
2585 str = X509_NAME_ENTRY_get_data(entry);
2586
2587 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
2588 "SSL commonName: \"%*s\"",
2589 ASN1_STRING_length(str), ASN1_STRING_data(str));
2590
2591 if (ngx_ssl_check_name(name, str) == NGX_OK) {
2592 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
2593 "SSL commonName: match");
2594 goto found;
2595 }
2596 }
2597
2598 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
2599 "SSL commonName: no match");
2600 }
2601 #endif
2602
2603 failed:
2604
2605 X509_free(cert);
2606 return NGX_ERROR;
2607
2608 found:
2609
2610 X509_free(cert);
2611 return NGX_OK;
2612 }
2613
2614
2615 #if OPENSSL_VERSION_NUMBER < 0x10002001L
2616
2617 static ngx_int_t
2618 ngx_ssl_check_name(ngx_str_t *name, ASN1_STRING *pattern)
2619 {
2620 u_char *s, *p, *end;
2621 size_t slen, plen;
2622
2623 s = name->data;
2624 slen = name->len;
2625
2626 p = ASN1_STRING_data(pattern);
2627 plen = ASN1_STRING_length(pattern);
2628
2629 if (slen == plen && ngx_strncasecmp(s, p, plen) == 0) {
2630 return NGX_OK;
2631 }
2632
2633 if (plen > 2 && p[0] == '*' && p[1] == '.') {
2634 plen -= 1;
2635 p += 1;
2636
2637 end = s + slen;
2638 s = ngx_strlchr(s, end, '.');
2639 slen = end - s;
2640
2641 if (plen == slen && ngx_strncasecmp(s, p, plen) == 0) {
2642 return NGX_OK;
2643 }
2644 }
2645
2646 return NGX_ERROR;
2647 }
2648
2649 #endif
2650
2651
2652 ngx_int_t
24892653 ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
24902654 {
24912655 s->data = (u_char *) SSL_get_version(c->ssl->connection);
149149 || n == X509_V_ERR_CERT_UNTRUSTED \
150150 || n == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)
151151
152 ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name);
153
152154
153155 ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool,
154156 ngx_str_t *s);
8080 ngx_uint_t ssl;
8181 ngx_uint_t ssl_protocols;
8282 ngx_str_t ssl_ciphers;
83 ngx_uint_t ssl_verify_depth;
84 ngx_str_t ssl_trusted_certificate;
85 ngx_str_t ssl_crl;
8386 #endif
8487 } ngx_http_proxy_loc_conf_t;
8588
564567 ngx_conf_set_flag_slot,
565568 NGX_HTTP_LOC_CONF_OFFSET,
566569 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_server_name),
570 NULL },
571
572 { ngx_string("proxy_ssl_verify"),
573 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
574 ngx_conf_set_flag_slot,
575 NGX_HTTP_LOC_CONF_OFFSET,
576 offsetof(ngx_http_proxy_loc_conf_t, upstream.ssl_verify),
577 NULL },
578
579 { ngx_string("proxy_ssl_verify_depth"),
580 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
581 ngx_conf_set_num_slot,
582 NGX_HTTP_LOC_CONF_OFFSET,
583 offsetof(ngx_http_proxy_loc_conf_t, ssl_verify_depth),
584 NULL },
585
586 { ngx_string("proxy_ssl_trusted_certificate"),
587 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
588 ngx_conf_set_str_slot,
589 NGX_HTTP_LOC_CONF_OFFSET,
590 offsetof(ngx_http_proxy_loc_conf_t, ssl_trusted_certificate),
591 NULL },
592
593 { ngx_string("proxy_ssl_crl"),
594 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
595 ngx_conf_set_str_slot,
596 NGX_HTTP_LOC_CONF_OFFSET,
597 offsetof(ngx_http_proxy_loc_conf_t, ssl_crl),
567598 NULL },
568599
569600 #endif
24172448 * conf->ssl = 0;
24182449 * conf->ssl_protocols = 0;
24192450 * conf->ssl_ciphers = { 0, NULL };
2451 * conf->ssl_trusted_certificate = { 0, NULL };
2452 * conf->ssl_crl = { 0, NULL };
24202453 */
24212454
24222455 conf->upstream.store = NGX_CONF_UNSET;
24592492 #if (NGX_HTTP_SSL)
24602493 conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
24612494 conf->upstream.ssl_server_name = NGX_CONF_UNSET;
2495 conf->upstream.ssl_verify = NGX_CONF_UNSET;
2496 conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
24622497 #endif
24632498
24642499 /* "proxy_cyclic_temp_file" is disabled */
27482783
27492784 ngx_conf_merge_value(conf->upstream.ssl_server_name,
27502785 prev->upstream.ssl_server_name, 0);
2786 ngx_conf_merge_value(conf->upstream.ssl_verify,
2787 prev->upstream.ssl_verify, 0);
2788 ngx_conf_merge_uint_value(conf->ssl_verify_depth,
2789 prev->ssl_verify_depth, 1);
2790 ngx_conf_merge_str_value(conf->ssl_trusted_certificate,
2791 prev->ssl_trusted_certificate, "");
2792 ngx_conf_merge_str_value(conf->ssl_crl, prev->ssl_crl, "");
27512793
27522794 if (conf->ssl && ngx_http_proxy_set_ssl(cf, conf) != NGX_OK) {
27532795 return NGX_CONF_ERROR;
38173859 return NGX_ERROR;
38183860 }
38193861
3862 if (plcf->upstream.ssl_verify) {
3863 if (plcf->ssl_trusted_certificate.len == 0) {
3864 ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
3865 "no proxy_ssl_trusted_certificate for proxy_ssl_verify");
3866 return NGX_ERROR;
3867 }
3868
3869 if (ngx_ssl_trusted_certificate(cf, plcf->upstream.ssl,
3870 &plcf->ssl_trusted_certificate,
3871 plcf->ssl_verify_depth)
3872 != NGX_OK)
3873 {
3874 return NGX_ERROR;
3875 }
3876
3877 if (ngx_ssl_crl(cf, plcf->upstream.ssl, &plcf->ssl_crl) != NGX_OK) {
3878 return NGX_ERROR;
3879 }
3880 }
3881
38203882 return NGX_OK;
38213883 }
38223884
13631363 c->sendfile = 0;
13641364 u->output.sendfile = 0;
13651365
1366 if (u->conf->ssl_server_name) {
1366 if (u->conf->ssl_server_name || u->conf->ssl_verify) {
13671367 if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) {
13681368 ngx_http_upstream_finalize_request(r, u,
13691369 NGX_HTTP_INTERNAL_SERVER_ERROR);
13951395 static void
13961396 ngx_http_upstream_ssl_handshake(ngx_connection_t *c)
13971397 {
1398 long rc;
13981399 ngx_http_request_t *r;
13991400 ngx_http_upstream_t *u;
14001401
14031404
14041405 if (c->ssl->handshaked) {
14051406
1407 if (u->conf->ssl_verify) {
1408 rc = SSL_get_verify_result(c->ssl->connection);
1409
1410 if (rc != X509_V_OK) {
1411 ngx_log_error(NGX_LOG_ERR, c->log, 0,
1412 "upstream SSL certificate verify error: (%l:%s)",
1413 rc, X509_verify_cert_error_string(rc));
1414 goto failed;
1415 }
1416
1417 if (ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) {
1418 ngx_log_error(NGX_LOG_ERR, c->log, 0,
1419 "upstream SSL certificate does not match \"%V\"",
1420 &u->ssl_name);
1421 goto failed;
1422 }
1423 }
1424
14061425 if (u->conf->ssl_session_reuse) {
14071426 u->peer.save_session(&u->peer, u->peer.data);
14081427 }
14171436 ngx_http_run_posted_requests(c);
14181437 return;
14191438 }
1439
1440 failed:
14201441
14211442 c = r->connection;
14221443
14661487
14671488 if (p != NULL) {
14681489 name.len = p - name.data;
1490 }
1491
1492 if (!u->conf->ssl_server_name) {
1493 goto done;
14691494 }
14701495
14711496 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
197197
198198 ngx_http_complex_value_t *ssl_name;
199199 ngx_flag_t ssl_server_name;
200 ngx_flag_t ssl_verify;
200201 #endif
201202
202203 ngx_str_t module;