Annotation of embedaddon/nginx/src/event/ngx_event_openssl.c, revision 1.1

1.1     ! misho       1: 
        !             2: /*
        !             3:  * Copyright (C) Igor Sysoev
        !             4:  * Copyright (C) Nginx, Inc.
        !             5:  */
        !             6: 
        !             7: 
        !             8: #include <ngx_config.h>
        !             9: #include <ngx_core.h>
        !            10: #include <ngx_event.h>
        !            11: 
        !            12: 
        !            13: typedef struct {
        !            14:     ngx_uint_t  engine;   /* unsigned  engine:1; */
        !            15: } ngx_openssl_conf_t;
        !            16: 
        !            17: 
        !            18: static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store);
        !            19: static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where,
        !            20:     int ret);
        !            21: static void ngx_ssl_handshake_handler(ngx_event_t *ev);
        !            22: static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n);
        !            23: static void ngx_ssl_write_handler(ngx_event_t *wev);
        !            24: static void ngx_ssl_read_handler(ngx_event_t *rev);
        !            25: static void ngx_ssl_shutdown_handler(ngx_event_t *ev);
        !            26: static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
        !            27:     ngx_err_t err, char *text);
        !            28: static void ngx_ssl_clear_error(ngx_log_t *log);
        !            29: 
        !            30: ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data);
        !            31: static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,
        !            32:     ngx_ssl_session_t *sess);
        !            33: static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
        !            34:     u_char *id, int len, int *copy);
        !            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,
        !            37:     ngx_slab_pool_t *shpool, ngx_uint_t n);
        !            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);
        !            40: 
        !            41: 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);
        !            43: static void ngx_openssl_exit(ngx_cycle_t *cycle);
        !            44: 
        !            45: 
        !            46: static ngx_command_t  ngx_openssl_commands[] = {
        !            47: 
        !            48:     { ngx_string("ssl_engine"),
        !            49:       NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
        !            50:       ngx_openssl_engine,
        !            51:       0,
        !            52:       0,
        !            53:       NULL },
        !            54: 
        !            55:       ngx_null_command
        !            56: };
        !            57: 
        !            58: 
        !            59: static ngx_core_module_t  ngx_openssl_module_ctx = {
        !            60:     ngx_string("openssl"),
        !            61:     ngx_openssl_create_conf,
        !            62:     NULL
        !            63: };
        !            64: 
        !            65: 
        !            66: ngx_module_t  ngx_openssl_module = {
        !            67:     NGX_MODULE_V1,
        !            68:     &ngx_openssl_module_ctx,               /* module context */
        !            69:     ngx_openssl_commands,                  /* module directives */
        !            70:     NGX_CORE_MODULE,                       /* module type */
        !            71:     NULL,                                  /* init master */
        !            72:     NULL,                                  /* init module */
        !            73:     NULL,                                  /* init process */
        !            74:     NULL,                                  /* init thread */
        !            75:     NULL,                                  /* exit thread */
        !            76:     NULL,                                  /* exit process */
        !            77:     ngx_openssl_exit,                      /* exit master */
        !            78:     NGX_MODULE_V1_PADDING
        !            79: };
        !            80: 
        !            81: 
        !            82: int  ngx_ssl_connection_index;
        !            83: int  ngx_ssl_server_conf_index;
        !            84: int  ngx_ssl_session_cache_index;
        !            85: int  ngx_ssl_certificate_index;
        !            86: int  ngx_ssl_stapling_index;
        !            87: 
        !            88: 
        !            89: ngx_int_t
        !            90: ngx_ssl_init(ngx_log_t *log)
        !            91: {
        !            92:     OPENSSL_config(NULL);
        !            93: 
        !            94:     SSL_library_init();
        !            95:     SSL_load_error_strings();
        !            96: 
        !            97:     OpenSSL_add_all_algorithms();
        !            98: 
        !            99: #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
        !           100: #ifndef SSL_OP_NO_COMPRESSION
        !           101:     {
        !           102:     /*
        !           103:      * Disable gzip compression in OpenSSL prior to 1.0.0 version,
        !           104:      * this saves about 522K per connection.
        !           105:      */
        !           106:     int                  n;
        !           107:     STACK_OF(SSL_COMP)  *ssl_comp_methods;
        !           108: 
        !           109:     ssl_comp_methods = SSL_COMP_get_compression_methods();
        !           110:     n = sk_SSL_COMP_num(ssl_comp_methods);
        !           111: 
        !           112:     while (n--) {
        !           113:         (void) sk_SSL_COMP_pop(ssl_comp_methods);
        !           114:     }
        !           115:     }
        !           116: #endif
        !           117: #endif
        !           118: 
        !           119:     ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
        !           120: 
        !           121:     if (ngx_ssl_connection_index == -1) {
        !           122:         ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed");
        !           123:         return NGX_ERROR;
        !           124:     }
        !           125: 
        !           126:     ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
        !           127:                                                          NULL);
        !           128:     if (ngx_ssl_server_conf_index == -1) {
        !           129:         ngx_ssl_error(NGX_LOG_ALERT, log, 0,
        !           130:                       "SSL_CTX_get_ex_new_index() failed");
        !           131:         return NGX_ERROR;
        !           132:     }
        !           133: 
        !           134:     ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
        !           135:                                                            NULL);
        !           136:     if (ngx_ssl_session_cache_index == -1) {
        !           137:         ngx_ssl_error(NGX_LOG_ALERT, log, 0,
        !           138:                       "SSL_CTX_get_ex_new_index() failed");
        !           139:         return NGX_ERROR;
        !           140:     }
        !           141: 
        !           142:     ngx_ssl_certificate_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
        !           143:                                                          NULL);
        !           144:     if (ngx_ssl_certificate_index == -1) {
        !           145:         ngx_ssl_error(NGX_LOG_ALERT, log, 0,
        !           146:                       "SSL_CTX_get_ex_new_index() failed");
        !           147:         return NGX_ERROR;
        !           148:     }
        !           149: 
        !           150:     ngx_ssl_stapling_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
        !           151:                                                       NULL);
        !           152:     if (ngx_ssl_stapling_index == -1) {
        !           153:         ngx_ssl_error(NGX_LOG_ALERT, log, 0,
        !           154:                       "SSL_CTX_get_ex_new_index() failed");
        !           155:         return NGX_ERROR;
        !           156:     }
        !           157: 
        !           158:     return NGX_OK;
        !           159: }
        !           160: 
        !           161: 
        !           162: ngx_int_t
        !           163: ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
        !           164: {
        !           165:     ssl->ctx = SSL_CTX_new(SSLv23_method());
        !           166: 
        !           167:     if (ssl->ctx == NULL) {
        !           168:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed");
        !           169:         return NGX_ERROR;
        !           170:     }
        !           171: 
        !           172:     if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_server_conf_index, data) == 0) {
        !           173:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           174:                       "SSL_CTX_set_ex_data() failed");
        !           175:         return NGX_ERROR;
        !           176:     }
        !           177: 
        !           178:     /* client side options */
        !           179: 
        !           180:     SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
        !           181:     SSL_CTX_set_options(ssl->ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
        !           182: 
        !           183:     /* server side options */
        !           184: 
        !           185:     SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
        !           186:     SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
        !           187: 
        !           188:     /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
        !           189:     SSL_CTX_set_options(ssl->ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
        !           190: 
        !           191:     SSL_CTX_set_options(ssl->ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
        !           192:     SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG);
        !           193:     SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
        !           194: 
        !           195:     SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
        !           196: 
        !           197:     SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
        !           198: 
        !           199:     if (!(protocols & NGX_SSL_SSLv2)) {
        !           200:         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2);
        !           201:     }
        !           202:     if (!(protocols & NGX_SSL_SSLv3)) {
        !           203:         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv3);
        !           204:     }
        !           205:     if (!(protocols & NGX_SSL_TLSv1)) {
        !           206:         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1);
        !           207:     }
        !           208: #ifdef SSL_OP_NO_TLSv1_1
        !           209:     if (!(protocols & NGX_SSL_TLSv1_1)) {
        !           210:         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_1);
        !           211:     }
        !           212: #endif
        !           213: #ifdef SSL_OP_NO_TLSv1_2
        !           214:     if (!(protocols & NGX_SSL_TLSv1_2)) {
        !           215:         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
        !           216:     }
        !           217: #endif
        !           218: 
        !           219: #ifdef SSL_OP_NO_COMPRESSION
        !           220:     SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION);
        !           221: #endif
        !           222: 
        !           223: #ifdef SSL_MODE_RELEASE_BUFFERS
        !           224:     SSL_CTX_set_mode(ssl->ctx, SSL_MODE_RELEASE_BUFFERS);
        !           225: #endif
        !           226: 
        !           227:     SSL_CTX_set_read_ahead(ssl->ctx, 1);
        !           228: 
        !           229:     SSL_CTX_set_info_callback(ssl->ctx, ngx_ssl_info_callback);
        !           230: 
        !           231:     return NGX_OK;
        !           232: }
        !           233: 
        !           234: 
        !           235: ngx_int_t
        !           236: ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
        !           237:     ngx_str_t *key)
        !           238: {
        !           239:     BIO     *bio;
        !           240:     X509    *x509;
        !           241:     u_long   n;
        !           242: 
        !           243:     if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
        !           244:         return NGX_ERROR;
        !           245:     }
        !           246: 
        !           247:     /*
        !           248:      * we can't use SSL_CTX_use_certificate_chain_file() as it doesn't
        !           249:      * allow to access certificate later from SSL_CTX, so we reimplement
        !           250:      * it here
        !           251:      */
        !           252: 
        !           253:     bio = BIO_new_file((char *) cert->data, "r");
        !           254:     if (bio == NULL) {
        !           255:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           256:                       "BIO_new_file(\"%s\") failed", cert->data);
        !           257:         return NGX_ERROR;
        !           258:     }
        !           259: 
        !           260:     x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
        !           261:     if (x509 == NULL) {
        !           262:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           263:                       "PEM_read_bio_X509_AUX(\"%s\") failed", cert->data);
        !           264:         BIO_free(bio);
        !           265:         return NGX_ERROR;
        !           266:     }
        !           267: 
        !           268:     if (SSL_CTX_use_certificate(ssl->ctx, x509) == 0) {
        !           269:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           270:                       "SSL_CTX_use_certificate(\"%s\") failed", cert->data);
        !           271:         X509_free(x509);
        !           272:         BIO_free(bio);
        !           273:         return NGX_ERROR;
        !           274:     }
        !           275: 
        !           276:     if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_certificate_index, x509)
        !           277:         == 0)
        !           278:     {
        !           279:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           280:                       "SSL_CTX_set_ex_data() failed");
        !           281:         return NGX_ERROR;
        !           282:     }
        !           283: 
        !           284:     X509_free(x509);
        !           285: 
        !           286:     /* read rest of the chain */
        !           287: 
        !           288:     for ( ;; ) {
        !           289: 
        !           290:         x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
        !           291:         if (x509 == NULL) {
        !           292:             n = ERR_peek_last_error();
        !           293: 
        !           294:             if (ERR_GET_LIB(n) == ERR_LIB_PEM
        !           295:                 && ERR_GET_REASON(n) == PEM_R_NO_START_LINE)
        !           296:             {
        !           297:                 /* end of file */
        !           298:                 ERR_clear_error();
        !           299:                 break;
        !           300:             }
        !           301: 
        !           302:             /* some real error */
        !           303: 
        !           304:             ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           305:                           "PEM_read_bio_X509(\"%s\") failed", cert->data);
        !           306:             BIO_free(bio);
        !           307:             return NGX_ERROR;
        !           308:         }
        !           309: 
        !           310:         if (SSL_CTX_add_extra_chain_cert(ssl->ctx, x509) == 0) {
        !           311:             ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           312:                           "SSL_CTX_add_extra_chain_cert(\"%s\") failed",
        !           313:                           cert->data);
        !           314:             X509_free(x509);
        !           315:             BIO_free(bio);
        !           316:             return NGX_ERROR;
        !           317:         }
        !           318:     }
        !           319: 
        !           320:     BIO_free(bio);
        !           321: 
        !           322:     if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) {
        !           323:         return NGX_ERROR;
        !           324:     }
        !           325: 
        !           326:     if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data,
        !           327:                                     SSL_FILETYPE_PEM)
        !           328:         == 0)
        !           329:     {
        !           330:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           331:                       "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data);
        !           332:         return NGX_ERROR;
        !           333:     }
        !           334: 
        !           335:     return NGX_OK;
        !           336: }
        !           337: 
        !           338: 
        !           339: ngx_int_t
        !           340: ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
        !           341:     ngx_int_t depth)
        !           342: {
        !           343:     STACK_OF(X509_NAME)  *list;
        !           344: 
        !           345:     SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ngx_http_ssl_verify_callback);
        !           346: 
        !           347:     SSL_CTX_set_verify_depth(ssl->ctx, depth);
        !           348: 
        !           349:     if (cert->len == 0) {
        !           350:         return NGX_OK;
        !           351:     }
        !           352: 
        !           353:     if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
        !           354:         return NGX_ERROR;
        !           355:     }
        !           356: 
        !           357:     if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)
        !           358:         == 0)
        !           359:     {
        !           360:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           361:                       "SSL_CTX_load_verify_locations(\"%s\") failed",
        !           362:                       cert->data);
        !           363:         return NGX_ERROR;
        !           364:     }
        !           365: 
        !           366:     list = SSL_load_client_CA_file((char *) cert->data);
        !           367: 
        !           368:     if (list == NULL) {
        !           369:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           370:                       "SSL_load_client_CA_file(\"%s\") failed", cert->data);
        !           371:         return NGX_ERROR;
        !           372:     }
        !           373: 
        !           374:     /*
        !           375:      * before 0.9.7h and 0.9.8 SSL_load_client_CA_file()
        !           376:      * always leaved an error in the error queue
        !           377:      */
        !           378: 
        !           379:     ERR_clear_error();
        !           380: 
        !           381:     SSL_CTX_set_client_CA_list(ssl->ctx, list);
        !           382: 
        !           383:     return NGX_OK;
        !           384: }
        !           385: 
        !           386: 
        !           387: ngx_int_t
        !           388: ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
        !           389:     ngx_int_t depth)
        !           390: {
        !           391:     SSL_CTX_set_verify_depth(ssl->ctx, depth);
        !           392: 
        !           393:     if (cert->len == 0) {
        !           394:         return NGX_OK;
        !           395:     }
        !           396: 
        !           397:     if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) {
        !           398:         return NGX_ERROR;
        !           399:     }
        !           400: 
        !           401:     if (SSL_CTX_load_verify_locations(ssl->ctx, (char *) cert->data, NULL)
        !           402:         == 0)
        !           403:     {
        !           404:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           405:                       "SSL_CTX_load_verify_locations(\"%s\") failed",
        !           406:                       cert->data);
        !           407:         return NGX_ERROR;
        !           408:     }
        !           409: 
        !           410:     return NGX_OK;
        !           411: }
        !           412: 
        !           413: 
        !           414: ngx_int_t
        !           415: ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl)
        !           416: {
        !           417:     X509_STORE   *store;
        !           418:     X509_LOOKUP  *lookup;
        !           419: 
        !           420:     if (crl->len == 0) {
        !           421:         return NGX_OK;
        !           422:     }
        !           423: 
        !           424:     if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) {
        !           425:         return NGX_ERROR;
        !           426:     }
        !           427: 
        !           428:     store = SSL_CTX_get_cert_store(ssl->ctx);
        !           429: 
        !           430:     if (store == NULL) {
        !           431:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           432:                       "SSL_CTX_get_cert_store() failed");
        !           433:         return NGX_ERROR;
        !           434:     }
        !           435: 
        !           436:     lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
        !           437: 
        !           438:     if (lookup == NULL) {
        !           439:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           440:                       "X509_STORE_add_lookup() failed");
        !           441:         return NGX_ERROR;
        !           442:     }
        !           443: 
        !           444:     if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM)
        !           445:         == 0)
        !           446:     {
        !           447:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           448:                       "X509_LOOKUP_load_file(\"%s\") failed", crl->data);
        !           449:         return NGX_ERROR;
        !           450:     }
        !           451: 
        !           452:     X509_STORE_set_flags(store,
        !           453:                          X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
        !           454: 
        !           455:     return NGX_OK;
        !           456: }
        !           457: 
        !           458: 
        !           459: static int
        !           460: ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
        !           461: {
        !           462: #if (NGX_DEBUG)
        !           463:     char              *subject, *issuer;
        !           464:     int                err, depth;
        !           465:     X509              *cert;
        !           466:     X509_NAME         *sname, *iname;
        !           467:     ngx_connection_t  *c;
        !           468:     ngx_ssl_conn_t    *ssl_conn;
        !           469: 
        !           470:     ssl_conn = X509_STORE_CTX_get_ex_data(x509_store,
        !           471:                                           SSL_get_ex_data_X509_STORE_CTX_idx());
        !           472: 
        !           473:     c = ngx_ssl_get_connection(ssl_conn);
        !           474: 
        !           475:     cert = X509_STORE_CTX_get_current_cert(x509_store);
        !           476:     err = X509_STORE_CTX_get_error(x509_store);
        !           477:     depth = X509_STORE_CTX_get_error_depth(x509_store);
        !           478: 
        !           479:     sname = X509_get_subject_name(cert);
        !           480:     subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)";
        !           481: 
        !           482:     iname = X509_get_issuer_name(cert);
        !           483:     issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)";
        !           484: 
        !           485:     ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !           486:                    "verify:%d, error:%d, depth:%d, "
        !           487:                    "subject:\"%s\",issuer: \"%s\"",
        !           488:                    ok, err, depth, subject, issuer);
        !           489: 
        !           490:     if (sname) {
        !           491:         OPENSSL_free(subject);
        !           492:     }
        !           493: 
        !           494:     if (iname) {
        !           495:         OPENSSL_free(issuer);
        !           496:     }
        !           497: #endif
        !           498: 
        !           499:     return 1;
        !           500: }
        !           501: 
        !           502: 
        !           503: static void
        !           504: ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, int ret)
        !           505: {
        !           506:     ngx_connection_t  *c;
        !           507: 
        !           508:     if (where & SSL_CB_HANDSHAKE_START) {
        !           509:         c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
        !           510: 
        !           511:         if (c->ssl->handshaked) {
        !           512:             c->ssl->renegotiation = 1;
        !           513:             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL renegotiation");
        !           514:         }
        !           515:     }
        !           516: }
        !           517: 
        !           518: 
        !           519: RSA *
        !           520: ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length)
        !           521: {
        !           522:     static RSA  *key;
        !           523: 
        !           524:     if (key_length == 512) {
        !           525:         if (key == NULL) {
        !           526:             key = RSA_generate_key(512, RSA_F4, NULL, NULL);
        !           527:         }
        !           528:     }
        !           529: 
        !           530:     return key;
        !           531: }
        !           532: 
        !           533: 
        !           534: ngx_int_t
        !           535: ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
        !           536: {
        !           537:     DH   *dh;
        !           538:     BIO  *bio;
        !           539: 
        !           540:     /*
        !           541:      * -----BEGIN DH PARAMETERS-----
        !           542:      * MIGHAoGBALu8LcrYRnSQfEP89YDpz9vZWKP1aLQtSwju1OsPs1BMbAMCducQgAxc
        !           543:      * y7qokiYUxb7spWWl/fHSh6K8BJvmd4Bg6RqSp1fjBI9osHb302zI8pul34HcLKcl
        !           544:      * 7OZicMyaUDXYzs7vnqAnSmOrHlj6/UmI0PZdFGdX2gcd8EXP4WubAgEC
        !           545:      * -----END DH PARAMETERS-----
        !           546:      */
        !           547: 
        !           548:     static unsigned char dh1024_p[] = {
        !           549:         0xBB, 0xBC, 0x2D, 0xCA, 0xD8, 0x46, 0x74, 0x90, 0x7C, 0x43, 0xFC, 0xF5,
        !           550:         0x80, 0xE9, 0xCF, 0xDB, 0xD9, 0x58, 0xA3, 0xF5, 0x68, 0xB4, 0x2D, 0x4B,
        !           551:         0x08, 0xEE, 0xD4, 0xEB, 0x0F, 0xB3, 0x50, 0x4C, 0x6C, 0x03, 0x02, 0x76,
        !           552:         0xE7, 0x10, 0x80, 0x0C, 0x5C, 0xCB, 0xBA, 0xA8, 0x92, 0x26, 0x14, 0xC5,
        !           553:         0xBE, 0xEC, 0xA5, 0x65, 0xA5, 0xFD, 0xF1, 0xD2, 0x87, 0xA2, 0xBC, 0x04,
        !           554:         0x9B, 0xE6, 0x77, 0x80, 0x60, 0xE9, 0x1A, 0x92, 0xA7, 0x57, 0xE3, 0x04,
        !           555:         0x8F, 0x68, 0xB0, 0x76, 0xF7, 0xD3, 0x6C, 0xC8, 0xF2, 0x9B, 0xA5, 0xDF,
        !           556:         0x81, 0xDC, 0x2C, 0xA7, 0x25, 0xEC, 0xE6, 0x62, 0x70, 0xCC, 0x9A, 0x50,
        !           557:         0x35, 0xD8, 0xCE, 0xCE, 0xEF, 0x9E, 0xA0, 0x27, 0x4A, 0x63, 0xAB, 0x1E,
        !           558:         0x58, 0xFA, 0xFD, 0x49, 0x88, 0xD0, 0xF6, 0x5D, 0x14, 0x67, 0x57, 0xDA,
        !           559:         0x07, 0x1D, 0xF0, 0x45, 0xCF, 0xE1, 0x6B, 0x9B
        !           560:     };
        !           561: 
        !           562:     static unsigned char dh1024_g[] = { 0x02 };
        !           563: 
        !           564: 
        !           565:     if (file->len == 0) {
        !           566: 
        !           567:         dh = DH_new();
        !           568:         if (dh == NULL) {
        !           569:             ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "DH_new() failed");
        !           570:             return NGX_ERROR;
        !           571:         }
        !           572: 
        !           573:         dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
        !           574:         dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
        !           575: 
        !           576:         if (dh->p == NULL || dh->g == NULL) {
        !           577:             ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "BN_bin2bn() failed");
        !           578:             DH_free(dh);
        !           579:             return NGX_ERROR;
        !           580:         }
        !           581: 
        !           582:         SSL_CTX_set_tmp_dh(ssl->ctx, dh);
        !           583: 
        !           584:         DH_free(dh);
        !           585: 
        !           586:         return NGX_OK;
        !           587:     }
        !           588: 
        !           589:     if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
        !           590:         return NGX_ERROR;
        !           591:     }
        !           592: 
        !           593:     bio = BIO_new_file((char *) file->data, "r");
        !           594:     if (bio == NULL) {
        !           595:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           596:                       "BIO_new_file(\"%s\") failed", file->data);
        !           597:         return NGX_ERROR;
        !           598:     }
        !           599: 
        !           600:     dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
        !           601:     if (dh == NULL) {
        !           602:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           603:                       "PEM_read_bio_DHparams(\"%s\") failed", file->data);
        !           604:         BIO_free(bio);
        !           605:         return NGX_ERROR;
        !           606:     }
        !           607: 
        !           608:     SSL_CTX_set_tmp_dh(ssl->ctx, dh);
        !           609: 
        !           610:     DH_free(dh);
        !           611:     BIO_free(bio);
        !           612: 
        !           613:     return NGX_OK;
        !           614: }
        !           615: 
        !           616: 
        !           617: ngx_int_t
        !           618: ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name)
        !           619: {
        !           620: #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
        !           621: #ifndef OPENSSL_NO_ECDH
        !           622:     int      nid;
        !           623:     EC_KEY  *ecdh;
        !           624: 
        !           625:     /*
        !           626:      * Elliptic-Curve Diffie-Hellman parameters are either "named curves"
        !           627:      * from RFC 4492 section 5.1.1, or explicitly described curves over
        !           628:      * binary fields. OpenSSL only supports the "named curves", which provide
        !           629:      * maximum interoperability.
        !           630:      */
        !           631: 
        !           632:     nid = OBJ_sn2nid((const char *) name->data);
        !           633:     if (nid == 0) {
        !           634:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           635:                       "Unknown curve name \"%s\"", name->data);
        !           636:         return NGX_ERROR;
        !           637:     }
        !           638: 
        !           639:     ecdh = EC_KEY_new_by_curve_name(nid);
        !           640:     if (ecdh == NULL) {
        !           641:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !           642:                       "Unable to create curve \"%s\"", name->data);
        !           643:         return NGX_ERROR;
        !           644:     }
        !           645: 
        !           646:     SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_ECDH_USE);
        !           647: 
        !           648:     SSL_CTX_set_tmp_ecdh(ssl->ctx, ecdh);
        !           649: 
        !           650:     EC_KEY_free(ecdh);
        !           651: #endif
        !           652: #endif
        !           653: 
        !           654:     return NGX_OK;
        !           655: }
        !           656: 
        !           657: 
        !           658: ngx_int_t
        !           659: ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
        !           660: {
        !           661:     ngx_ssl_connection_t  *sc;
        !           662: 
        !           663:     sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t));
        !           664:     if (sc == NULL) {
        !           665:         return NGX_ERROR;
        !           666:     }
        !           667: 
        !           668:     sc->buffer = ((flags & NGX_SSL_BUFFER) != 0);
        !           669: 
        !           670:     sc->connection = SSL_new(ssl->ctx);
        !           671: 
        !           672:     if (sc->connection == NULL) {
        !           673:         ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed");
        !           674:         return NGX_ERROR;
        !           675:     }
        !           676: 
        !           677:     if (SSL_set_fd(sc->connection, c->fd) == 0) {
        !           678:         ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed");
        !           679:         return NGX_ERROR;
        !           680:     }
        !           681: 
        !           682:     if (flags & NGX_SSL_CLIENT) {
        !           683:         SSL_set_connect_state(sc->connection);
        !           684: 
        !           685:     } else {
        !           686:         SSL_set_accept_state(sc->connection);
        !           687:     }
        !           688: 
        !           689:     if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) {
        !           690:         ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed");
        !           691:         return NGX_ERROR;
        !           692:     }
        !           693: 
        !           694:     c->ssl = sc;
        !           695: 
        !           696:     return NGX_OK;
        !           697: }
        !           698: 
        !           699: 
        !           700: ngx_int_t
        !           701: ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session)
        !           702: {
        !           703:     if (session) {
        !           704:         if (SSL_set_session(c->ssl->connection, session) == 0) {
        !           705:             ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_session() failed");
        !           706:             return NGX_ERROR;
        !           707:         }
        !           708:     }
        !           709: 
        !           710:     return NGX_OK;
        !           711: }
        !           712: 
        !           713: 
        !           714: ngx_int_t
        !           715: ngx_ssl_handshake(ngx_connection_t *c)
        !           716: {
        !           717:     int        n, sslerr;
        !           718:     ngx_err_t  err;
        !           719: 
        !           720:     ngx_ssl_clear_error(c->log);
        !           721: 
        !           722:     n = SSL_do_handshake(c->ssl->connection);
        !           723: 
        !           724:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
        !           725: 
        !           726:     if (n == 1) {
        !           727: 
        !           728:         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        !           729:             return NGX_ERROR;
        !           730:         }
        !           731: 
        !           732:         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
        !           733:             return NGX_ERROR;
        !           734:         }
        !           735: 
        !           736: #if (NGX_DEBUG)
        !           737:         {
        !           738:         char         buf[129], *s, *d;
        !           739: #if OPENSSL_VERSION_NUMBER >= 0x10000000L
        !           740:         const
        !           741: #endif
        !           742:         SSL_CIPHER  *cipher;
        !           743: 
        !           744:         cipher = SSL_get_current_cipher(c->ssl->connection);
        !           745: 
        !           746:         if (cipher) {
        !           747:             SSL_CIPHER_description(cipher, &buf[1], 128);
        !           748: 
        !           749:             for (s = &buf[1], d = buf; *s; s++) {
        !           750:                 if (*s == ' ' && *d == ' ') {
        !           751:                     continue;
        !           752:                 }
        !           753: 
        !           754:                 if (*s == LF || *s == CR) {
        !           755:                     continue;
        !           756:                 }
        !           757: 
        !           758:                 *++d = *s;
        !           759:             }
        !           760: 
        !           761:             if (*d != ' ') {
        !           762:                 d++;
        !           763:             }
        !           764: 
        !           765:             *d = '\0';
        !           766: 
        !           767:             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !           768:                            "SSL: %s, cipher: \"%s\"",
        !           769:                            SSL_get_version(c->ssl->connection), &buf[1]);
        !           770: 
        !           771:             if (SSL_session_reused(c->ssl->connection)) {
        !           772:                 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !           773:                                "SSL reused session");
        !           774:             }
        !           775: 
        !           776:         } else {
        !           777:             ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !           778:                            "SSL no shared ciphers");
        !           779:         }
        !           780:         }
        !           781: #endif
        !           782: 
        !           783:         c->ssl->handshaked = 1;
        !           784: 
        !           785:         c->recv = ngx_ssl_recv;
        !           786:         c->send = ngx_ssl_write;
        !           787:         c->recv_chain = ngx_ssl_recv_chain;
        !           788:         c->send_chain = ngx_ssl_send_chain;
        !           789: 
        !           790:         /* initial handshake done, disable renegotiation (CVE-2009-3555) */
        !           791:         if (c->ssl->connection->s3) {
        !           792:             c->ssl->connection->s3->flags |= SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS;
        !           793:         }
        !           794: 
        !           795:         return NGX_OK;
        !           796:     }
        !           797: 
        !           798:     sslerr = SSL_get_error(c->ssl->connection, n);
        !           799: 
        !           800:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
        !           801: 
        !           802:     if (sslerr == SSL_ERROR_WANT_READ) {
        !           803:         c->read->ready = 0;
        !           804:         c->read->handler = ngx_ssl_handshake_handler;
        !           805:         c->write->handler = ngx_ssl_handshake_handler;
        !           806: 
        !           807:         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        !           808:             return NGX_ERROR;
        !           809:         }
        !           810: 
        !           811:         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
        !           812:             return NGX_ERROR;
        !           813:         }
        !           814: 
        !           815:         return NGX_AGAIN;
        !           816:     }
        !           817: 
        !           818:     if (sslerr == SSL_ERROR_WANT_WRITE) {
        !           819:         c->write->ready = 0;
        !           820:         c->read->handler = ngx_ssl_handshake_handler;
        !           821:         c->write->handler = ngx_ssl_handshake_handler;
        !           822: 
        !           823:         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        !           824:             return NGX_ERROR;
        !           825:         }
        !           826: 
        !           827:         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
        !           828:             return NGX_ERROR;
        !           829:         }
        !           830: 
        !           831:         return NGX_AGAIN;
        !           832:     }
        !           833: 
        !           834:     err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
        !           835: 
        !           836:     c->ssl->no_wait_shutdown = 1;
        !           837:     c->ssl->no_send_shutdown = 1;
        !           838:     c->read->eof = 1;
        !           839: 
        !           840:     if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
        !           841:         ngx_log_error(NGX_LOG_INFO, c->log, err,
        !           842:                       "peer closed connection in SSL handshake");
        !           843: 
        !           844:         return NGX_ERROR;
        !           845:     }
        !           846: 
        !           847:     c->read->error = 1;
        !           848: 
        !           849:     ngx_ssl_connection_error(c, sslerr, err, "SSL_do_handshake() failed");
        !           850: 
        !           851:     return NGX_ERROR;
        !           852: }
        !           853: 
        !           854: 
        !           855: static void
        !           856: ngx_ssl_handshake_handler(ngx_event_t *ev)
        !           857: {
        !           858:     ngx_connection_t  *c;
        !           859: 
        !           860:     c = ev->data;
        !           861: 
        !           862:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !           863:                    "SSL handshake handler: %d", ev->write);
        !           864: 
        !           865:     if (ev->timedout) {
        !           866:         c->ssl->handler(c);
        !           867:         return;
        !           868:     }
        !           869: 
        !           870:     if (ngx_ssl_handshake(c) == NGX_AGAIN) {
        !           871:         return;
        !           872:     }
        !           873: 
        !           874:     c->ssl->handler(c);
        !           875: }
        !           876: 
        !           877: 
        !           878: ssize_t
        !           879: ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl)
        !           880: {
        !           881:     u_char     *last;
        !           882:     ssize_t     n, bytes;
        !           883:     ngx_buf_t  *b;
        !           884: 
        !           885:     bytes = 0;
        !           886: 
        !           887:     b = cl->buf;
        !           888:     last = b->last;
        !           889: 
        !           890:     for ( ;; ) {
        !           891: 
        !           892:         n = ngx_ssl_recv(c, last, b->end - last);
        !           893: 
        !           894:         if (n > 0) {
        !           895:             last += n;
        !           896:             bytes += n;
        !           897: 
        !           898:             if (last == b->end) {
        !           899:                 cl = cl->next;
        !           900: 
        !           901:                 if (cl == NULL) {
        !           902:                     return bytes;
        !           903:                 }
        !           904: 
        !           905:                 b = cl->buf;
        !           906:                 last = b->last;
        !           907:             }
        !           908: 
        !           909:             continue;
        !           910:         }
        !           911: 
        !           912:         if (bytes) {
        !           913: 
        !           914:             if (n == 0 || n == NGX_ERROR) {
        !           915:                 c->read->ready = 1;
        !           916:             }
        !           917: 
        !           918:             return bytes;
        !           919:         }
        !           920: 
        !           921:         return n;
        !           922:     }
        !           923: }
        !           924: 
        !           925: 
        !           926: ssize_t
        !           927: ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size)
        !           928: {
        !           929:     int  n, bytes;
        !           930: 
        !           931:     if (c->ssl->last == NGX_ERROR) {
        !           932:         c->read->error = 1;
        !           933:         return NGX_ERROR;
        !           934:     }
        !           935: 
        !           936:     if (c->ssl->last == NGX_DONE) {
        !           937:         c->read->ready = 0;
        !           938:         c->read->eof = 1;
        !           939:         return 0;
        !           940:     }
        !           941: 
        !           942:     bytes = 0;
        !           943: 
        !           944:     ngx_ssl_clear_error(c->log);
        !           945: 
        !           946:     /*
        !           947:      * SSL_read() may return data in parts, so try to read
        !           948:      * until SSL_read() would return no data
        !           949:      */
        !           950: 
        !           951:     for ( ;; ) {
        !           952: 
        !           953:         n = SSL_read(c->ssl->connection, buf, size);
        !           954: 
        !           955:         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n);
        !           956: 
        !           957:         if (n > 0) {
        !           958:             bytes += n;
        !           959:         }
        !           960: 
        !           961:         c->ssl->last = ngx_ssl_handle_recv(c, n);
        !           962: 
        !           963:         if (c->ssl->last == NGX_OK) {
        !           964: 
        !           965:             size -= n;
        !           966: 
        !           967:             if (size == 0) {
        !           968:                 return bytes;
        !           969:             }
        !           970: 
        !           971:             buf += n;
        !           972: 
        !           973:             continue;
        !           974:         }
        !           975: 
        !           976:         if (bytes) {
        !           977:             return bytes;
        !           978:         }
        !           979: 
        !           980:         switch (c->ssl->last) {
        !           981: 
        !           982:         case NGX_DONE:
        !           983:             c->read->ready = 0;
        !           984:             c->read->eof = 1;
        !           985:             return 0;
        !           986: 
        !           987:         case NGX_ERROR:
        !           988:             c->read->error = 1;
        !           989: 
        !           990:             /* fall through */
        !           991: 
        !           992:         case NGX_AGAIN:
        !           993:             return c->ssl->last;
        !           994:         }
        !           995:     }
        !           996: }
        !           997: 
        !           998: 
        !           999: static ngx_int_t
        !          1000: ngx_ssl_handle_recv(ngx_connection_t *c, int n)
        !          1001: {
        !          1002:     int        sslerr;
        !          1003:     ngx_err_t  err;
        !          1004: 
        !          1005:     if (c->ssl->renegotiation) {
        !          1006:         /*
        !          1007:          * disable renegotiation (CVE-2009-3555):
        !          1008:          * OpenSSL (at least up to 0.9.8l) does not handle disabled
        !          1009:          * renegotiation gracefully, so drop connection here
        !          1010:          */
        !          1011: 
        !          1012:         ngx_log_error(NGX_LOG_NOTICE, c->log, 0, "SSL renegotiation disabled");
        !          1013: 
        !          1014:         while (ERR_peek_error()) {
        !          1015:             ngx_ssl_error(NGX_LOG_DEBUG, c->log, 0,
        !          1016:                           "ignoring stale global SSL error");
        !          1017:         }
        !          1018: 
        !          1019:         ERR_clear_error();
        !          1020: 
        !          1021:         c->ssl->no_wait_shutdown = 1;
        !          1022:         c->ssl->no_send_shutdown = 1;
        !          1023: 
        !          1024:         return NGX_ERROR;
        !          1025:     }
        !          1026: 
        !          1027:     if (n > 0) {
        !          1028: 
        !          1029:         if (c->ssl->saved_write_handler) {
        !          1030: 
        !          1031:             c->write->handler = c->ssl->saved_write_handler;
        !          1032:             c->ssl->saved_write_handler = NULL;
        !          1033:             c->write->ready = 1;
        !          1034: 
        !          1035:             if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
        !          1036:                 return NGX_ERROR;
        !          1037:             }
        !          1038: 
        !          1039:             ngx_post_event(c->write, &ngx_posted_events);
        !          1040:         }
        !          1041: 
        !          1042:         return NGX_OK;
        !          1043:     }
        !          1044: 
        !          1045:     sslerr = SSL_get_error(c->ssl->connection, n);
        !          1046: 
        !          1047:     err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
        !          1048: 
        !          1049:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
        !          1050: 
        !          1051:     if (sslerr == SSL_ERROR_WANT_READ) {
        !          1052:         c->read->ready = 0;
        !          1053:         return NGX_AGAIN;
        !          1054:     }
        !          1055: 
        !          1056:     if (sslerr == SSL_ERROR_WANT_WRITE) {
        !          1057: 
        !          1058:         ngx_log_error(NGX_LOG_INFO, c->log, 0,
        !          1059:                       "peer started SSL renegotiation");
        !          1060: 
        !          1061:         c->write->ready = 0;
        !          1062: 
        !          1063:         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
        !          1064:             return NGX_ERROR;
        !          1065:         }
        !          1066: 
        !          1067:         /*
        !          1068:          * we do not set the timer because there is already the read event timer
        !          1069:          */
        !          1070: 
        !          1071:         if (c->ssl->saved_write_handler == NULL) {
        !          1072:             c->ssl->saved_write_handler = c->write->handler;
        !          1073:             c->write->handler = ngx_ssl_write_handler;
        !          1074:         }
        !          1075: 
        !          1076:         return NGX_AGAIN;
        !          1077:     }
        !          1078: 
        !          1079:     c->ssl->no_wait_shutdown = 1;
        !          1080:     c->ssl->no_send_shutdown = 1;
        !          1081: 
        !          1082:     if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
        !          1083:         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !          1084:                        "peer shutdown SSL cleanly");
        !          1085:         return NGX_DONE;
        !          1086:     }
        !          1087: 
        !          1088:     ngx_ssl_connection_error(c, sslerr, err, "SSL_read() failed");
        !          1089: 
        !          1090:     return NGX_ERROR;
        !          1091: }
        !          1092: 
        !          1093: 
        !          1094: static void
        !          1095: ngx_ssl_write_handler(ngx_event_t *wev)
        !          1096: {
        !          1097:     ngx_connection_t  *c;
        !          1098: 
        !          1099:     c = wev->data;
        !          1100: 
        !          1101:     c->read->handler(c->read);
        !          1102: }
        !          1103: 
        !          1104: 
        !          1105: /*
        !          1106:  * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer
        !          1107:  * before the SSL_write() call to decrease a SSL overhead.
        !          1108:  *
        !          1109:  * Besides for protocols such as HTTP it is possible to always buffer
        !          1110:  * the output to decrease a SSL overhead some more.
        !          1111:  */
        !          1112: 
        !          1113: ngx_chain_t *
        !          1114: ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
        !          1115: {
        !          1116:     int          n;
        !          1117:     ngx_uint_t   flush;
        !          1118:     ssize_t      send, size;
        !          1119:     ngx_buf_t   *buf;
        !          1120: 
        !          1121:     if (!c->ssl->buffer) {
        !          1122: 
        !          1123:         while (in) {
        !          1124:             if (ngx_buf_special(in->buf)) {
        !          1125:                 in = in->next;
        !          1126:                 continue;
        !          1127:             }
        !          1128: 
        !          1129:             n = ngx_ssl_write(c, in->buf->pos, in->buf->last - in->buf->pos);
        !          1130: 
        !          1131:             if (n == NGX_ERROR) {
        !          1132:                 return NGX_CHAIN_ERROR;
        !          1133:             }
        !          1134: 
        !          1135:             if (n == NGX_AGAIN) {
        !          1136:                 return in;
        !          1137:             }
        !          1138: 
        !          1139:             in->buf->pos += n;
        !          1140:             c->sent += n;
        !          1141: 
        !          1142:             if (in->buf->pos == in->buf->last) {
        !          1143:                 in = in->next;
        !          1144:             }
        !          1145:         }
        !          1146: 
        !          1147:         return in;
        !          1148:     }
        !          1149: 
        !          1150: 
        !          1151:     /* the maximum limit size is the maximum int32_t value - the page size */
        !          1152: 
        !          1153:     if (limit == 0 || limit > (off_t) (NGX_MAX_INT32_VALUE - ngx_pagesize)) {
        !          1154:         limit = NGX_MAX_INT32_VALUE - ngx_pagesize;
        !          1155:     }
        !          1156: 
        !          1157:     buf = c->ssl->buf;
        !          1158: 
        !          1159:     if (buf == NULL) {
        !          1160:         buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE);
        !          1161:         if (buf == NULL) {
        !          1162:             return NGX_CHAIN_ERROR;
        !          1163:         }
        !          1164: 
        !          1165:         c->ssl->buf = buf;
        !          1166:     }
        !          1167: 
        !          1168:     if (buf->start == NULL) {
        !          1169:         buf->start = ngx_palloc(c->pool, NGX_SSL_BUFSIZE);
        !          1170:         if (buf->start == NULL) {
        !          1171:             return NGX_CHAIN_ERROR;
        !          1172:         }
        !          1173: 
        !          1174:         buf->pos = buf->start;
        !          1175:         buf->last = buf->start;
        !          1176:         buf->end = buf->start + NGX_SSL_BUFSIZE;
        !          1177:     }
        !          1178: 
        !          1179:     send = buf->last - buf->pos;
        !          1180:     flush = (in == NULL) ? 1 : buf->flush;
        !          1181: 
        !          1182:     for ( ;; ) {
        !          1183: 
        !          1184:         while (in && buf->last < buf->end && send < limit) {
        !          1185:             if (in->buf->last_buf || in->buf->flush) {
        !          1186:                 flush = 1;
        !          1187:             }
        !          1188: 
        !          1189:             if (ngx_buf_special(in->buf)) {
        !          1190:                 in = in->next;
        !          1191:                 continue;
        !          1192:             }
        !          1193: 
        !          1194:             size = in->buf->last - in->buf->pos;
        !          1195: 
        !          1196:             if (size > buf->end - buf->last) {
        !          1197:                 size = buf->end - buf->last;
        !          1198:             }
        !          1199: 
        !          1200:             if (send + size > limit) {
        !          1201:                 size = (ssize_t) (limit - send);
        !          1202:             }
        !          1203: 
        !          1204:             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !          1205:                            "SSL buf copy: %d", size);
        !          1206: 
        !          1207:             ngx_memcpy(buf->last, in->buf->pos, size);
        !          1208: 
        !          1209:             buf->last += size;
        !          1210:             in->buf->pos += size;
        !          1211:             send += size;
        !          1212: 
        !          1213:             if (in->buf->pos == in->buf->last) {
        !          1214:                 in = in->next;
        !          1215:             }
        !          1216:         }
        !          1217: 
        !          1218:         if (!flush && send < limit && buf->last < buf->end) {
        !          1219:             break;
        !          1220:         }
        !          1221: 
        !          1222:         size = buf->last - buf->pos;
        !          1223: 
        !          1224:         if (size == 0) {
        !          1225:             buf->flush = 0;
        !          1226:             c->buffered &= ~NGX_SSL_BUFFERED;
        !          1227:             return in;
        !          1228:         }
        !          1229: 
        !          1230:         n = ngx_ssl_write(c, buf->pos, size);
        !          1231: 
        !          1232:         if (n == NGX_ERROR) {
        !          1233:             return NGX_CHAIN_ERROR;
        !          1234:         }
        !          1235: 
        !          1236:         if (n == NGX_AGAIN) {
        !          1237:             break;
        !          1238:         }
        !          1239: 
        !          1240:         buf->pos += n;
        !          1241:         c->sent += n;
        !          1242: 
        !          1243:         if (n < size) {
        !          1244:             break;
        !          1245:         }
        !          1246: 
        !          1247:         flush = 0;
        !          1248: 
        !          1249:         buf->pos = buf->start;
        !          1250:         buf->last = buf->start;
        !          1251: 
        !          1252:         if (in == NULL || send == limit) {
        !          1253:             break;
        !          1254:         }
        !          1255:     }
        !          1256: 
        !          1257:     buf->flush = flush;
        !          1258: 
        !          1259:     if (buf->pos < buf->last) {
        !          1260:         c->buffered |= NGX_SSL_BUFFERED;
        !          1261: 
        !          1262:     } else {
        !          1263:         c->buffered &= ~NGX_SSL_BUFFERED;
        !          1264:     }
        !          1265: 
        !          1266:     return in;
        !          1267: }
        !          1268: 
        !          1269: 
        !          1270: ssize_t
        !          1271: ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size)
        !          1272: {
        !          1273:     int        n, sslerr;
        !          1274:     ngx_err_t  err;
        !          1275: 
        !          1276:     ngx_ssl_clear_error(c->log);
        !          1277: 
        !          1278:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size);
        !          1279: 
        !          1280:     n = SSL_write(c->ssl->connection, data, size);
        !          1281: 
        !          1282:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n);
        !          1283: 
        !          1284:     if (n > 0) {
        !          1285: 
        !          1286:         if (c->ssl->saved_read_handler) {
        !          1287: 
        !          1288:             c->read->handler = c->ssl->saved_read_handler;
        !          1289:             c->ssl->saved_read_handler = NULL;
        !          1290:             c->read->ready = 1;
        !          1291: 
        !          1292:             if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        !          1293:                 return NGX_ERROR;
        !          1294:             }
        !          1295: 
        !          1296:             ngx_post_event(c->read, &ngx_posted_events);
        !          1297:         }
        !          1298: 
        !          1299:         return n;
        !          1300:     }
        !          1301: 
        !          1302:     sslerr = SSL_get_error(c->ssl->connection, n);
        !          1303: 
        !          1304:     err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
        !          1305: 
        !          1306:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
        !          1307: 
        !          1308:     if (sslerr == SSL_ERROR_WANT_WRITE) {
        !          1309:         c->write->ready = 0;
        !          1310:         return NGX_AGAIN;
        !          1311:     }
        !          1312: 
        !          1313:     if (sslerr == SSL_ERROR_WANT_READ) {
        !          1314: 
        !          1315:         ngx_log_error(NGX_LOG_INFO, c->log, 0,
        !          1316:                       "peer started SSL renegotiation");
        !          1317: 
        !          1318:         c->read->ready = 0;
        !          1319: 
        !          1320:         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        !          1321:             return NGX_ERROR;
        !          1322:         }
        !          1323: 
        !          1324:         /*
        !          1325:          * we do not set the timer because there is already
        !          1326:          * the write event timer
        !          1327:          */
        !          1328: 
        !          1329:         if (c->ssl->saved_read_handler == NULL) {
        !          1330:             c->ssl->saved_read_handler = c->read->handler;
        !          1331:             c->read->handler = ngx_ssl_read_handler;
        !          1332:         }
        !          1333: 
        !          1334:         return NGX_AGAIN;
        !          1335:     }
        !          1336: 
        !          1337:     c->ssl->no_wait_shutdown = 1;
        !          1338:     c->ssl->no_send_shutdown = 1;
        !          1339:     c->write->error = 1;
        !          1340: 
        !          1341:     ngx_ssl_connection_error(c, sslerr, err, "SSL_write() failed");
        !          1342: 
        !          1343:     return NGX_ERROR;
        !          1344: }
        !          1345: 
        !          1346: 
        !          1347: static void
        !          1348: ngx_ssl_read_handler(ngx_event_t *rev)
        !          1349: {
        !          1350:     ngx_connection_t  *c;
        !          1351: 
        !          1352:     c = rev->data;
        !          1353: 
        !          1354:     c->write->handler(c->write);
        !          1355: }
        !          1356: 
        !          1357: 
        !          1358: void
        !          1359: ngx_ssl_free_buffer(ngx_connection_t *c)
        !          1360: {
        !          1361:     if (c->ssl->buf && c->ssl->buf->start) {
        !          1362:         if (ngx_pfree(c->pool, c->ssl->buf->start) == NGX_OK) {
        !          1363:             c->ssl->buf->start = NULL;
        !          1364:         }
        !          1365:     }
        !          1366: }
        !          1367: 
        !          1368: 
        !          1369: ngx_int_t
        !          1370: ngx_ssl_shutdown(ngx_connection_t *c)
        !          1371: {
        !          1372:     int        n, sslerr, mode;
        !          1373:     ngx_err_t  err;
        !          1374: 
        !          1375:     if (c->timedout) {
        !          1376:         mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
        !          1377:         SSL_set_quiet_shutdown(c->ssl->connection, 1);
        !          1378: 
        !          1379:     } else {
        !          1380:         mode = SSL_get_shutdown(c->ssl->connection);
        !          1381: 
        !          1382:         if (c->ssl->no_wait_shutdown) {
        !          1383:             mode |= SSL_RECEIVED_SHUTDOWN;
        !          1384:         }
        !          1385: 
        !          1386:         if (c->ssl->no_send_shutdown) {
        !          1387:             mode |= SSL_SENT_SHUTDOWN;
        !          1388:         }
        !          1389: 
        !          1390:         if (c->ssl->no_wait_shutdown && c->ssl->no_send_shutdown) {
        !          1391:             SSL_set_quiet_shutdown(c->ssl->connection, 1);
        !          1392:         }
        !          1393:     }
        !          1394: 
        !          1395:     SSL_set_shutdown(c->ssl->connection, mode);
        !          1396: 
        !          1397:     ngx_ssl_clear_error(c->log);
        !          1398: 
        !          1399:     n = SSL_shutdown(c->ssl->connection);
        !          1400: 
        !          1401:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n);
        !          1402: 
        !          1403:     sslerr = 0;
        !          1404: 
        !          1405:     /* SSL_shutdown() never returns -1, on error it returns 0 */
        !          1406: 
        !          1407:     if (n != 1 && ERR_peek_error()) {
        !          1408:         sslerr = SSL_get_error(c->ssl->connection, n);
        !          1409: 
        !          1410:         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !          1411:                        "SSL_get_error: %d", sslerr);
        !          1412:     }
        !          1413: 
        !          1414:     if (n == 1 || sslerr == 0 || sslerr == SSL_ERROR_ZERO_RETURN) {
        !          1415:         SSL_free(c->ssl->connection);
        !          1416:         c->ssl = NULL;
        !          1417: 
        !          1418:         return NGX_OK;
        !          1419:     }
        !          1420: 
        !          1421:     if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) {
        !          1422:         c->read->handler = ngx_ssl_shutdown_handler;
        !          1423:         c->write->handler = ngx_ssl_shutdown_handler;
        !          1424: 
        !          1425:         if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        !          1426:             return NGX_ERROR;
        !          1427:         }
        !          1428: 
        !          1429:         if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
        !          1430:             return NGX_ERROR;
        !          1431:         }
        !          1432: 
        !          1433:         if (sslerr == SSL_ERROR_WANT_READ) {
        !          1434:             ngx_add_timer(c->read, 30000);
        !          1435:         }
        !          1436: 
        !          1437:         return NGX_AGAIN;
        !          1438:     }
        !          1439: 
        !          1440:     err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
        !          1441: 
        !          1442:     ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed");
        !          1443: 
        !          1444:     SSL_free(c->ssl->connection);
        !          1445:     c->ssl = NULL;
        !          1446: 
        !          1447:     return NGX_ERROR;
        !          1448: }
        !          1449: 
        !          1450: 
        !          1451: static void
        !          1452: ngx_ssl_shutdown_handler(ngx_event_t *ev)
        !          1453: {
        !          1454:     ngx_connection_t           *c;
        !          1455:     ngx_connection_handler_pt   handler;
        !          1456: 
        !          1457:     c = ev->data;
        !          1458:     handler = c->ssl->handler;
        !          1459: 
        !          1460:     if (ev->timedout) {
        !          1461:         c->timedout = 1;
        !          1462:     }
        !          1463: 
        !          1464:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler");
        !          1465: 
        !          1466:     if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
        !          1467:         return;
        !          1468:     }
        !          1469: 
        !          1470:     handler(c);
        !          1471: }
        !          1472: 
        !          1473: 
        !          1474: static void
        !          1475: ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
        !          1476:     char *text)
        !          1477: {
        !          1478:     int         n;
        !          1479:     ngx_uint_t  level;
        !          1480: 
        !          1481:     level = NGX_LOG_CRIT;
        !          1482: 
        !          1483:     if (sslerr == SSL_ERROR_SYSCALL) {
        !          1484: 
        !          1485:         if (err == NGX_ECONNRESET
        !          1486:             || err == NGX_EPIPE
        !          1487:             || err == NGX_ENOTCONN
        !          1488:             || err == NGX_ETIMEDOUT
        !          1489:             || err == NGX_ECONNREFUSED
        !          1490:             || err == NGX_ENETDOWN
        !          1491:             || err == NGX_ENETUNREACH
        !          1492:             || err == NGX_EHOSTDOWN
        !          1493:             || err == NGX_EHOSTUNREACH)
        !          1494:         {
        !          1495:             switch (c->log_error) {
        !          1496: 
        !          1497:             case NGX_ERROR_IGNORE_ECONNRESET:
        !          1498:             case NGX_ERROR_INFO:
        !          1499:                 level = NGX_LOG_INFO;
        !          1500:                 break;
        !          1501: 
        !          1502:             case NGX_ERROR_ERR:
        !          1503:                 level = NGX_LOG_ERR;
        !          1504:                 break;
        !          1505: 
        !          1506:             default:
        !          1507:                 break;
        !          1508:             }
        !          1509:         }
        !          1510: 
        !          1511:     } else if (sslerr == SSL_ERROR_SSL) {
        !          1512: 
        !          1513:         n = ERR_GET_REASON(ERR_peek_error());
        !          1514: 
        !          1515:             /* handshake failures */
        !          1516:         if (n == SSL_R_BAD_CHANGE_CIPHER_SPEC                        /*  103 */
        !          1517:             || n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG                  /*  129 */
        !          1518:             || n == SSL_R_DIGEST_CHECK_FAILED                        /*  149 */
        !          1519:             || n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST              /*  151 */
        !          1520:             || n == SSL_R_EXCESSIVE_MESSAGE_SIZE                     /*  152 */
        !          1521:             || n == SSL_R_LENGTH_MISMATCH                            /*  159 */
        !          1522:             || n == SSL_R_NO_CIPHERS_PASSED                          /*  182 */
        !          1523:             || n == SSL_R_NO_CIPHERS_SPECIFIED                       /*  183 */
        !          1524:             || n == SSL_R_NO_COMPRESSION_SPECIFIED                   /*  187 */
        !          1525:             || n == SSL_R_NO_SHARED_CIPHER                           /*  193 */
        !          1526:             || n == SSL_R_RECORD_LENGTH_MISMATCH                     /*  213 */
        !          1527: #ifdef SSL_R_PARSE_TLSEXT
        !          1528:             || n == SSL_R_PARSE_TLSEXT                               /*  227 */
        !          1529: #endif
        !          1530:             || n == SSL_R_UNEXPECTED_MESSAGE                         /*  244 */
        !          1531:             || n == SSL_R_UNEXPECTED_RECORD                          /*  245 */
        !          1532:             || n == SSL_R_UNKNOWN_ALERT_TYPE                         /*  246 */
        !          1533:             || n == SSL_R_UNKNOWN_PROTOCOL                           /*  252 */
        !          1534:             || n == SSL_R_WRONG_VERSION_NUMBER                       /*  267 */
        !          1535:             || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC        /*  281 */
        !          1536: #ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG
        !          1537:             || n == SSL_R_RENEGOTIATE_EXT_TOO_LONG                   /*  335 */
        !          1538:             || n == SSL_R_RENEGOTIATION_ENCODING_ERR                 /*  336 */
        !          1539:             || n == SSL_R_RENEGOTIATION_MISMATCH                     /*  337 */
        !          1540: #endif
        !          1541: #ifdef SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED
        !          1542:             || n == SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED       /*  338 */
        !          1543: #endif
        !          1544: #ifdef SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING
        !          1545:             || n == SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING           /*  345 */
        !          1546: #endif
        !          1547:             || n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
        !          1548:             || n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE             /* 1010 */
        !          1549:             || n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC                 /* 1020 */
        !          1550:             || n == SSL_R_TLSV1_ALERT_DECRYPTION_FAILED              /* 1021 */
        !          1551:             || n == SSL_R_TLSV1_ALERT_RECORD_OVERFLOW                /* 1022 */
        !          1552:             || n == SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE          /* 1030 */
        !          1553:             || n == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE              /* 1040 */
        !          1554:             || n == SSL_R_SSLV3_ALERT_NO_CERTIFICATE                 /* 1041 */
        !          1555:             || n == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE                /* 1042 */
        !          1556:             || n == SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE        /* 1043 */
        !          1557:             || n == SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED            /* 1044 */
        !          1558:             || n == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED            /* 1045 */
        !          1559:             || n == SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN            /* 1046 */
        !          1560:             || n == SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER              /* 1047 */
        !          1561:             || n == SSL_R_TLSV1_ALERT_UNKNOWN_CA                     /* 1048 */
        !          1562:             || n == SSL_R_TLSV1_ALERT_ACCESS_DENIED                  /* 1049 */
        !          1563:             || n == SSL_R_TLSV1_ALERT_DECODE_ERROR                   /* 1050 */
        !          1564:             || n == SSL_R_TLSV1_ALERT_DECRYPT_ERROR                  /* 1051 */
        !          1565:             || n == SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION             /* 1060 */
        !          1566:             || n == SSL_R_TLSV1_ALERT_PROTOCOL_VERSION               /* 1070 */
        !          1567:             || n == SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY          /* 1071 */
        !          1568:             || n == SSL_R_TLSV1_ALERT_INTERNAL_ERROR                 /* 1080 */
        !          1569:             || n == SSL_R_TLSV1_ALERT_USER_CANCELLED                 /* 1090 */
        !          1570:             || n == SSL_R_TLSV1_ALERT_NO_RENEGOTIATION)              /* 1100 */
        !          1571:         {
        !          1572:             switch (c->log_error) {
        !          1573: 
        !          1574:             case NGX_ERROR_IGNORE_ECONNRESET:
        !          1575:             case NGX_ERROR_INFO:
        !          1576:                 level = NGX_LOG_INFO;
        !          1577:                 break;
        !          1578: 
        !          1579:             case NGX_ERROR_ERR:
        !          1580:                 level = NGX_LOG_ERR;
        !          1581:                 break;
        !          1582: 
        !          1583:             default:
        !          1584:                 break;
        !          1585:             }
        !          1586:         }
        !          1587:     }
        !          1588: 
        !          1589:     ngx_ssl_error(level, c->log, err, text);
        !          1590: }
        !          1591: 
        !          1592: 
        !          1593: static void
        !          1594: ngx_ssl_clear_error(ngx_log_t *log)
        !          1595: {
        !          1596:     while (ERR_peek_error()) {
        !          1597:         ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error");
        !          1598:     }
        !          1599: 
        !          1600:     ERR_clear_error();
        !          1601: }
        !          1602: 
        !          1603: 
        !          1604: void ngx_cdecl
        !          1605: ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
        !          1606: {
        !          1607:     int          flags;
        !          1608:     u_long       n;
        !          1609:     va_list      args;
        !          1610:     u_char      *p, *last;
        !          1611:     u_char       errstr[NGX_MAX_CONF_ERRSTR];
        !          1612:     const char  *data;
        !          1613: 
        !          1614:     last = errstr + NGX_MAX_CONF_ERRSTR;
        !          1615: 
        !          1616:     va_start(args, fmt);
        !          1617:     p = ngx_vslprintf(errstr, last - 1, fmt, args);
        !          1618:     va_end(args);
        !          1619: 
        !          1620:     p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p);
        !          1621: 
        !          1622:     for ( ;; ) {
        !          1623: 
        !          1624:         n = ERR_peek_error_line_data(NULL, NULL, &data, &flags);
        !          1625: 
        !          1626:         if (n == 0) {
        !          1627:             break;
        !          1628:         }
        !          1629: 
        !          1630:         if (p >= last) {
        !          1631:             goto next;
        !          1632:         }
        !          1633: 
        !          1634:         *p++ = ' ';
        !          1635: 
        !          1636:         ERR_error_string_n(n, (char *) p, last - p);
        !          1637: 
        !          1638:         while (p < last && *p) {
        !          1639:             p++;
        !          1640:         }
        !          1641: 
        !          1642:         if (p < last && *data && (flags & ERR_TXT_STRING)) {
        !          1643:             *p++ = ':';
        !          1644:             p = ngx_cpystrn(p, (u_char *) data, last - p);
        !          1645:         }
        !          1646: 
        !          1647:     next:
        !          1648: 
        !          1649:         (void) ERR_get_error();
        !          1650:     }
        !          1651: 
        !          1652:     ngx_log_error(level, log, err, "%s)", errstr);
        !          1653: }
        !          1654: 
        !          1655: 
        !          1656: ngx_int_t
        !          1657: ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
        !          1658:     ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout)
        !          1659: {
        !          1660:     long  cache_mode;
        !          1661: 
        !          1662:     if (builtin_session_cache == NGX_SSL_NO_SCACHE) {
        !          1663:         SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF);
        !          1664:         return NGX_OK;
        !          1665:     }
        !          1666: 
        !          1667:     SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len);
        !          1668: 
        !          1669:     if (builtin_session_cache == NGX_SSL_NONE_SCACHE) {
        !          1670: 
        !          1671:         /*
        !          1672:          * If the server explicitly says that it does not support
        !          1673:          * session reuse (see SSL_SESS_CACHE_OFF above), then
        !          1674:          * Outlook Express fails to upload a sent email to
        !          1675:          * the Sent Items folder on the IMAP server via a separate IMAP
        !          1676:          * connection in the background. Therefore we have a special
        !          1677:          * mode (SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_INTERNAL_STORE)
        !          1678:          * where the server pretends that it supports session reuse,
        !          1679:          * but it does not actually store any session.
        !          1680:          */
        !          1681: 
        !          1682:         SSL_CTX_set_session_cache_mode(ssl->ctx,
        !          1683:                                        SSL_SESS_CACHE_SERVER
        !          1684:                                        |SSL_SESS_CACHE_NO_AUTO_CLEAR
        !          1685:                                        |SSL_SESS_CACHE_NO_INTERNAL_STORE);
        !          1686: 
        !          1687:         SSL_CTX_sess_set_cache_size(ssl->ctx, 1);
        !          1688: 
        !          1689:         return NGX_OK;
        !          1690:     }
        !          1691: 
        !          1692:     cache_mode = SSL_SESS_CACHE_SERVER;
        !          1693: 
        !          1694:     if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) {
        !          1695:         cache_mode |= SSL_SESS_CACHE_NO_INTERNAL;
        !          1696:     }
        !          1697: 
        !          1698:     SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode);
        !          1699: 
        !          1700:     if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) {
        !          1701: 
        !          1702:         if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) {
        !          1703:             SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache);
        !          1704:         }
        !          1705:     }
        !          1706: 
        !          1707:     SSL_CTX_set_timeout(ssl->ctx, (long) timeout);
        !          1708: 
        !          1709:     if (shm_zone) {
        !          1710:         SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session);
        !          1711:         SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session);
        !          1712:         SSL_CTX_sess_set_remove_cb(ssl->ctx, ngx_ssl_remove_session);
        !          1713: 
        !          1714:         if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_cache_index, shm_zone)
        !          1715:             == 0)
        !          1716:         {
        !          1717:             ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
        !          1718:                           "SSL_CTX_set_ex_data() failed");
        !          1719:             return NGX_ERROR;
        !          1720:         }
        !          1721:     }
        !          1722: 
        !          1723:     return NGX_OK;
        !          1724: }
        !          1725: 
        !          1726: 
        !          1727: ngx_int_t
        !          1728: ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
        !          1729: {
        !          1730:     size_t                    len;
        !          1731:     ngx_slab_pool_t          *shpool;
        !          1732:     ngx_ssl_session_cache_t  *cache;
        !          1733: 
        !          1734:     if (data) {
        !          1735:         shm_zone->data = data;
        !          1736:         return NGX_OK;
        !          1737:     }
        !          1738: 
        !          1739:     if (shm_zone->shm.exists) {
        !          1740:         shm_zone->data = data;
        !          1741:         return NGX_OK;
        !          1742:     }
        !          1743: 
        !          1744:     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
        !          1745: 
        !          1746:     cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));
        !          1747:     if (cache == NULL) {
        !          1748:         return NGX_ERROR;
        !          1749:     }
        !          1750: 
        !          1751:     shpool->data = cache;
        !          1752:     shm_zone->data = cache;
        !          1753: 
        !          1754:     ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel,
        !          1755:                     ngx_ssl_session_rbtree_insert_value);
        !          1756: 
        !          1757:     ngx_queue_init(&cache->expire_queue);
        !          1758: 
        !          1759:     len = sizeof(" in SSL session shared cache \"\"") + shm_zone->shm.name.len;
        !          1760: 
        !          1761:     shpool->log_ctx = ngx_slab_alloc(shpool, len);
        !          1762:     if (shpool->log_ctx == NULL) {
        !          1763:         return NGX_ERROR;
        !          1764:     }
        !          1765: 
        !          1766:     ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z",
        !          1767:                 &shm_zone->shm.name);
        !          1768: 
        !          1769:     return NGX_OK;
        !          1770: }
        !          1771: 
        !          1772: 
        !          1773: /*
        !          1774:  * The length of the session id is 16 bytes for SSLv2 sessions and
        !          1775:  * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes.
        !          1776:  * It seems that the typical length of the external ASN1 representation
        !          1777:  * of a session is 118 or 119 bytes for SSLv3/TSLv1.
        !          1778:  *
        !          1779:  * Thus on 32-bit platforms we allocate separately an rbtree node,
        !          1780:  * a session id, and an ASN1 representation, they take accordingly
        !          1781:  * 64, 32, and 128 bytes.
        !          1782:  *
        !          1783:  * On 64-bit platforms we allocate separately an rbtree node + session_id,
        !          1784:  * and an ASN1 representation, they take accordingly 128 and 128 bytes.
        !          1785:  *
        !          1786:  * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow,
        !          1787:  * so they are outside the code locked by shared pool mutex
        !          1788:  */
        !          1789: 
        !          1790: static int
        !          1791: ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess)
        !          1792: {
        !          1793:     int                       len;
        !          1794:     u_char                   *p, *id, *cached_sess;
        !          1795:     uint32_t                  hash;
        !          1796:     SSL_CTX                  *ssl_ctx;
        !          1797:     ngx_shm_zone_t           *shm_zone;
        !          1798:     ngx_connection_t         *c;
        !          1799:     ngx_slab_pool_t          *shpool;
        !          1800:     ngx_ssl_sess_id_t        *sess_id;
        !          1801:     ngx_ssl_session_cache_t  *cache;
        !          1802:     u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];
        !          1803: 
        !          1804:     len = i2d_SSL_SESSION(sess, NULL);
        !          1805: 
        !          1806:     /* do not cache too big session */
        !          1807: 
        !          1808:     if (len > (int) NGX_SSL_MAX_SESSION_SIZE) {
        !          1809:         return 0;
        !          1810:     }
        !          1811: 
        !          1812:     p = buf;
        !          1813:     i2d_SSL_SESSION(sess, &p);
        !          1814: 
        !          1815:     c = ngx_ssl_get_connection(ssl_conn);
        !          1816: 
        !          1817:     ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
        !          1818:     shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index);
        !          1819: 
        !          1820:     cache = shm_zone->data;
        !          1821:     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
        !          1822: 
        !          1823:     ngx_shmtx_lock(&shpool->mutex);
        !          1824: 
        !          1825:     /* drop one or two expired sessions */
        !          1826:     ngx_ssl_expire_sessions(cache, shpool, 1);
        !          1827: 
        !          1828:     cached_sess = ngx_slab_alloc_locked(shpool, len);
        !          1829: 
        !          1830:     if (cached_sess == NULL) {
        !          1831: 
        !          1832:         /* drop the oldest non-expired session and try once more */
        !          1833: 
        !          1834:         ngx_ssl_expire_sessions(cache, shpool, 0);
        !          1835: 
        !          1836:         cached_sess = ngx_slab_alloc_locked(shpool, len);
        !          1837: 
        !          1838:         if (cached_sess == NULL) {
        !          1839:             sess_id = NULL;
        !          1840:             goto failed;
        !          1841:         }
        !          1842:     }
        !          1843: 
        !          1844:     sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
        !          1845: 
        !          1846:     if (sess_id == NULL) {
        !          1847: 
        !          1848:         /* drop the oldest non-expired session and try once more */
        !          1849: 
        !          1850:         ngx_ssl_expire_sessions(cache, shpool, 0);
        !          1851: 
        !          1852:         sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
        !          1853: 
        !          1854:         if (sess_id == NULL) {
        !          1855:             goto failed;
        !          1856:         }
        !          1857:     }
        !          1858: 
        !          1859: #if (NGX_PTR_SIZE == 8)
        !          1860: 
        !          1861:     id = sess_id->sess_id;
        !          1862: 
        !          1863: #else
        !          1864: 
        !          1865:     id = ngx_slab_alloc_locked(shpool, sess->session_id_length);
        !          1866: 
        !          1867:     if (id == NULL) {
        !          1868: 
        !          1869:         /* drop the oldest non-expired session and try once more */
        !          1870: 
        !          1871:         ngx_ssl_expire_sessions(cache, shpool, 0);
        !          1872: 
        !          1873:         id = ngx_slab_alloc_locked(shpool, sess->session_id_length);
        !          1874: 
        !          1875:         if (id == NULL) {
        !          1876:             goto failed;
        !          1877:         }
        !          1878:     }
        !          1879: 
        !          1880: #endif
        !          1881: 
        !          1882:     ngx_memcpy(cached_sess, buf, len);
        !          1883: 
        !          1884:     ngx_memcpy(id, sess->session_id, sess->session_id_length);
        !          1885: 
        !          1886:     hash = ngx_crc32_short(sess->session_id, sess->session_id_length);
        !          1887: 
        !          1888:     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !          1889:                    "ssl new session: %08XD:%d:%d",
        !          1890:                    hash, sess->session_id_length, len);
        !          1891: 
        !          1892:     sess_id->node.key = hash;
        !          1893:     sess_id->node.data = (u_char) sess->session_id_length;
        !          1894:     sess_id->id = id;
        !          1895:     sess_id->len = len;
        !          1896:     sess_id->session = cached_sess;
        !          1897: 
        !          1898:     sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx);
        !          1899: 
        !          1900:     ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue);
        !          1901: 
        !          1902:     ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node);
        !          1903: 
        !          1904:     ngx_shmtx_unlock(&shpool->mutex);
        !          1905: 
        !          1906:     return 0;
        !          1907: 
        !          1908: failed:
        !          1909: 
        !          1910:     if (cached_sess) {
        !          1911:         ngx_slab_free_locked(shpool, cached_sess);
        !          1912:     }
        !          1913: 
        !          1914:     if (sess_id) {
        !          1915:         ngx_slab_free_locked(shpool, sess_id);
        !          1916:     }
        !          1917: 
        !          1918:     ngx_shmtx_unlock(&shpool->mutex);
        !          1919: 
        !          1920:     ngx_log_error(NGX_LOG_ALERT, c->log, 0,
        !          1921:                   "could not add new SSL session to the session cache");
        !          1922: 
        !          1923:     return 0;
        !          1924: }
        !          1925: 
        !          1926: 
        !          1927: static ngx_ssl_session_t *
        !          1928: ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len,
        !          1929:     int *copy)
        !          1930: {
        !          1931: #if OPENSSL_VERSION_NUMBER >= 0x0090707fL
        !          1932:     const
        !          1933: #endif
        !          1934:     u_char                   *p;
        !          1935:     uint32_t                  hash;
        !          1936:     ngx_int_t                 rc;
        !          1937:     ngx_shm_zone_t           *shm_zone;
        !          1938:     ngx_slab_pool_t          *shpool;
        !          1939:     ngx_rbtree_node_t        *node, *sentinel;
        !          1940:     ngx_ssl_session_t        *sess;
        !          1941:     ngx_ssl_sess_id_t        *sess_id;
        !          1942:     ngx_ssl_session_cache_t  *cache;
        !          1943:     u_char                    buf[NGX_SSL_MAX_SESSION_SIZE];
        !          1944: #if (NGX_DEBUG)
        !          1945:     ngx_connection_t         *c;
        !          1946: #endif
        !          1947: 
        !          1948:     hash = ngx_crc32_short(id, (size_t) len);
        !          1949:     *copy = 0;
        !          1950: 
        !          1951: #if (NGX_DEBUG)
        !          1952:     c = ngx_ssl_get_connection(ssl_conn);
        !          1953: 
        !          1954:     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
        !          1955:                    "ssl get session: %08XD:%d", hash, len);
        !          1956: #endif
        !          1957: 
        !          1958:     shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn),
        !          1959:                                    ngx_ssl_session_cache_index);
        !          1960: 
        !          1961:     cache = shm_zone->data;
        !          1962: 
        !          1963:     sess = NULL;
        !          1964: 
        !          1965:     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
        !          1966: 
        !          1967:     ngx_shmtx_lock(&shpool->mutex);
        !          1968: 
        !          1969:     node = cache->session_rbtree.root;
        !          1970:     sentinel = cache->session_rbtree.sentinel;
        !          1971: 
        !          1972:     while (node != sentinel) {
        !          1973: 
        !          1974:         if (hash < node->key) {
        !          1975:             node = node->left;
        !          1976:             continue;
        !          1977:         }
        !          1978: 
        !          1979:         if (hash > node->key) {
        !          1980:             node = node->right;
        !          1981:             continue;
        !          1982:         }
        !          1983: 
        !          1984:         /* hash == node->key */
        !          1985: 
        !          1986:         sess_id = (ngx_ssl_sess_id_t *) node;
        !          1987: 
        !          1988:         rc = ngx_memn2cmp(id, sess_id->id, (size_t) len, (size_t) node->data);
        !          1989: 
        !          1990:         if (rc == 0) {
        !          1991: 
        !          1992:             if (sess_id->expire > ngx_time()) {
        !          1993:                 ngx_memcpy(buf, sess_id->session, sess_id->len);
        !          1994: 
        !          1995:                 ngx_shmtx_unlock(&shpool->mutex);
        !          1996: 
        !          1997:                 p = buf;
        !          1998:                 sess = d2i_SSL_SESSION(NULL, &p, sess_id->len);
        !          1999: 
        !          2000:                 return sess;
        !          2001:             }
        !          2002: 
        !          2003:             ngx_queue_remove(&sess_id->queue);
        !          2004: 
        !          2005:             ngx_rbtree_delete(&cache->session_rbtree, node);
        !          2006: 
        !          2007:             ngx_slab_free_locked(shpool, sess_id->session);
        !          2008: #if (NGX_PTR_SIZE == 4)
        !          2009:             ngx_slab_free_locked(shpool, sess_id->id);
        !          2010: #endif
        !          2011:             ngx_slab_free_locked(shpool, sess_id);
        !          2012: 
        !          2013:             sess = NULL;
        !          2014: 
        !          2015:             goto done;
        !          2016:         }
        !          2017: 
        !          2018:         node = (rc < 0) ? node->left : node->right;
        !          2019:     }
        !          2020: 
        !          2021: done:
        !          2022: 
        !          2023:     ngx_shmtx_unlock(&shpool->mutex);
        !          2024: 
        !          2025:     return sess;
        !          2026: }
        !          2027: 
        !          2028: 
        !          2029: void
        !          2030: ngx_ssl_remove_cached_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
        !          2031: {
        !          2032:      SSL_CTX_remove_session(ssl, sess);
        !          2033: 
        !          2034:      ngx_ssl_remove_session(ssl, sess);
        !          2035: }
        !          2036: 
        !          2037: 
        !          2038: static void
        !          2039: ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
        !          2040: {
        !          2041:     size_t                    len;
        !          2042:     u_char                   *id;
        !          2043:     uint32_t                  hash;
        !          2044:     ngx_int_t                 rc;
        !          2045:     ngx_shm_zone_t           *shm_zone;
        !          2046:     ngx_slab_pool_t          *shpool;
        !          2047:     ngx_rbtree_node_t        *node, *sentinel;
        !          2048:     ngx_ssl_sess_id_t        *sess_id;
        !          2049:     ngx_ssl_session_cache_t  *cache;
        !          2050: 
        !          2051:     shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index);
        !          2052: 
        !          2053:     if (shm_zone == NULL) {
        !          2054:         return;
        !          2055:     }
        !          2056: 
        !          2057:     cache = shm_zone->data;
        !          2058: 
        !          2059:     id = sess->session_id;
        !          2060:     len = (size_t) sess->session_id_length;
        !          2061: 
        !          2062:     hash = ngx_crc32_short(id, len);
        !          2063: 
        !          2064:     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
        !          2065:                    "ssl remove session: %08XD:%uz", hash, len);
        !          2066: 
        !          2067:     shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
        !          2068: 
        !          2069:     ngx_shmtx_lock(&shpool->mutex);
        !          2070: 
        !          2071:     node = cache->session_rbtree.root;
        !          2072:     sentinel = cache->session_rbtree.sentinel;
        !          2073: 
        !          2074:     while (node != sentinel) {
        !          2075: 
        !          2076:         if (hash < node->key) {
        !          2077:             node = node->left;
        !          2078:             continue;
        !          2079:         }
        !          2080: 
        !          2081:         if (hash > node->key) {
        !          2082:             node = node->right;
        !          2083:             continue;
        !          2084:         }
        !          2085: 
        !          2086:         /* hash == node->key */
        !          2087: 
        !          2088:         sess_id = (ngx_ssl_sess_id_t *) node;
        !          2089: 
        !          2090:         rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data);
        !          2091: 
        !          2092:         if (rc == 0) {
        !          2093: 
        !          2094:             ngx_queue_remove(&sess_id->queue);
        !          2095: 
        !          2096:             ngx_rbtree_delete(&cache->session_rbtree, node);
        !          2097: 
        !          2098:             ngx_slab_free_locked(shpool, sess_id->session);
        !          2099: #if (NGX_PTR_SIZE == 4)
        !          2100:             ngx_slab_free_locked(shpool, sess_id->id);
        !          2101: #endif
        !          2102:             ngx_slab_free_locked(shpool, sess_id);
        !          2103: 
        !          2104:             goto done;
        !          2105:         }
        !          2106: 
        !          2107:         node = (rc < 0) ? node->left : node->right;
        !          2108:     }
        !          2109: 
        !          2110: done:
        !          2111: 
        !          2112:     ngx_shmtx_unlock(&shpool->mutex);
        !          2113: }
        !          2114: 
        !          2115: 
        !          2116: static void
        !          2117: ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
        !          2118:     ngx_slab_pool_t *shpool, ngx_uint_t n)
        !          2119: {
        !          2120:     time_t              now;
        !          2121:     ngx_queue_t        *q;
        !          2122:     ngx_ssl_sess_id_t  *sess_id;
        !          2123: 
        !          2124:     now = ngx_time();
        !          2125: 
        !          2126:     while (n < 3) {
        !          2127: 
        !          2128:         if (ngx_queue_empty(&cache->expire_queue)) {
        !          2129:             return;
        !          2130:         }
        !          2131: 
        !          2132:         q = ngx_queue_last(&cache->expire_queue);
        !          2133: 
        !          2134:         sess_id = ngx_queue_data(q, ngx_ssl_sess_id_t, queue);
        !          2135: 
        !          2136:         if (n++ != 0 && sess_id->expire > now) {
        !          2137:             return;
        !          2138:         }
        !          2139: 
        !          2140:         ngx_queue_remove(q);
        !          2141: 
        !          2142:         ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
        !          2143:                        "expire session: %08Xi", sess_id->node.key);
        !          2144: 
        !          2145:         ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node);
        !          2146: 
        !          2147:         ngx_slab_free_locked(shpool, sess_id->session);
        !          2148: #if (NGX_PTR_SIZE == 4)
        !          2149:         ngx_slab_free_locked(shpool, sess_id->id);
        !          2150: #endif
        !          2151:         ngx_slab_free_locked(shpool, sess_id);
        !          2152:     }
        !          2153: }
        !          2154: 
        !          2155: 
        !          2156: static void
        !          2157: ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
        !          2158:     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
        !          2159: {
        !          2160:     ngx_rbtree_node_t  **p;
        !          2161:     ngx_ssl_sess_id_t   *sess_id, *sess_id_temp;
        !          2162: 
        !          2163:     for ( ;; ) {
        !          2164: 
        !          2165:         if (node->key < temp->key) {
        !          2166: 
        !          2167:             p = &temp->left;
        !          2168: 
        !          2169:         } else if (node->key > temp->key) {
        !          2170: 
        !          2171:             p = &temp->right;
        !          2172: 
        !          2173:         } else { /* node->key == temp->key */
        !          2174: 
        !          2175:             sess_id = (ngx_ssl_sess_id_t *) node;
        !          2176:             sess_id_temp = (ngx_ssl_sess_id_t *) temp;
        !          2177: 
        !          2178:             p = (ngx_memn2cmp(sess_id->id, sess_id_temp->id,
        !          2179:                               (size_t) node->data, (size_t) temp->data)
        !          2180:                  < 0) ? &temp->left : &temp->right;
        !          2181:         }
        !          2182: 
        !          2183:         if (*p == sentinel) {
        !          2184:             break;
        !          2185:         }
        !          2186: 
        !          2187:         temp = *p;
        !          2188:     }
        !          2189: 
        !          2190:     *p = node;
        !          2191:     node->parent = temp;
        !          2192:     node->left = sentinel;
        !          2193:     node->right = sentinel;
        !          2194:     ngx_rbt_red(node);
        !          2195: }
        !          2196: 
        !          2197: 
        !          2198: void
        !          2199: ngx_ssl_cleanup_ctx(void *data)
        !          2200: {
        !          2201:     ngx_ssl_t  *ssl = data;
        !          2202: 
        !          2203:     SSL_CTX_free(ssl->ctx);
        !          2204: }
        !          2205: 
        !          2206: 
        !          2207: ngx_int_t
        !          2208: ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
        !          2209: {
        !          2210:     s->data = (u_char *) SSL_get_version(c->ssl->connection);
        !          2211:     return NGX_OK;
        !          2212: }
        !          2213: 
        !          2214: 
        !          2215: ngx_int_t
        !          2216: ngx_ssl_get_cipher_name(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
        !          2217: {
        !          2218:     s->data = (u_char *) SSL_get_cipher_name(c->ssl->connection);
        !          2219:     return NGX_OK;
        !          2220: }
        !          2221: 
        !          2222: 
        !          2223: ngx_int_t
        !          2224: ngx_ssl_get_session_id(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
        !          2225: {
        !          2226:     int           len;
        !          2227:     u_char       *p, *buf;
        !          2228:     SSL_SESSION  *sess;
        !          2229: 
        !          2230:     sess = SSL_get0_session(c->ssl->connection);
        !          2231: 
        !          2232:     len = i2d_SSL_SESSION(sess, NULL);
        !          2233: 
        !          2234:     buf = ngx_alloc(len, c->log);
        !          2235:     if (buf == NULL) {
        !          2236:         return NGX_ERROR;
        !          2237:     }
        !          2238: 
        !          2239:     s->len = 2 * len;
        !          2240:     s->data = ngx_pnalloc(pool, 2 * len);
        !          2241:     if (s->data == NULL) {
        !          2242:         ngx_free(buf);
        !          2243:         return NGX_ERROR;
        !          2244:     }
        !          2245: 
        !          2246:     p = buf;
        !          2247:     i2d_SSL_SESSION(sess, &p);
        !          2248: 
        !          2249:     ngx_hex_dump(s->data, buf, len);
        !          2250: 
        !          2251:     ngx_free(buf);
        !          2252: 
        !          2253:     return NGX_OK;
        !          2254: }
        !          2255: 
        !          2256: 
        !          2257: ngx_int_t
        !          2258: ngx_ssl_get_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
        !          2259: {
        !          2260:     size_t   len;
        !          2261:     BIO     *bio;
        !          2262:     X509    *cert;
        !          2263: 
        !          2264:     s->len = 0;
        !          2265: 
        !          2266:     cert = SSL_get_peer_certificate(c->ssl->connection);
        !          2267:     if (cert == NULL) {
        !          2268:         return NGX_OK;
        !          2269:     }
        !          2270: 
        !          2271:     bio = BIO_new(BIO_s_mem());
        !          2272:     if (bio == NULL) {
        !          2273:         ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed");
        !          2274:         X509_free(cert);
        !          2275:         return NGX_ERROR;
        !          2276:     }
        !          2277: 
        !          2278:     if (PEM_write_bio_X509(bio, cert) == 0) {
        !          2279:         ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "PEM_write_bio_X509() failed");
        !          2280:         goto failed;
        !          2281:     }
        !          2282: 
        !          2283:     len = BIO_pending(bio);
        !          2284:     s->len = len;
        !          2285: 
        !          2286:     s->data = ngx_pnalloc(pool, len);
        !          2287:     if (s->data == NULL) {
        !          2288:         goto failed;
        !          2289:     }
        !          2290: 
        !          2291:     BIO_read(bio, s->data, len);
        !          2292: 
        !          2293:     BIO_free(bio);
        !          2294:     X509_free(cert);
        !          2295: 
        !          2296:     return NGX_OK;
        !          2297: 
        !          2298: failed:
        !          2299: 
        !          2300:     BIO_free(bio);
        !          2301:     X509_free(cert);
        !          2302: 
        !          2303:     return NGX_ERROR;
        !          2304: }
        !          2305: 
        !          2306: 
        !          2307: ngx_int_t
        !          2308: ngx_ssl_get_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
        !          2309: {
        !          2310:     u_char      *p;
        !          2311:     size_t       len;
        !          2312:     ngx_uint_t   i;
        !          2313:     ngx_str_t    cert;
        !          2314: 
        !          2315:     if (ngx_ssl_get_raw_certificate(c, pool, &cert) != NGX_OK) {
        !          2316:         return NGX_ERROR;
        !          2317:     }
        !          2318: 
        !          2319:     if (cert.len == 0) {
        !          2320:         s->len = 0;
        !          2321:         return NGX_OK;
        !          2322:     }
        !          2323: 
        !          2324:     len = cert.len - 1;
        !          2325: 
        !          2326:     for (i = 0; i < cert.len - 1; i++) {
        !          2327:         if (cert.data[i] == LF) {
        !          2328:             len++;
        !          2329:         }
        !          2330:     }
        !          2331: 
        !          2332:     s->len = len;
        !          2333:     s->data = ngx_pnalloc(pool, len);
        !          2334:     if (s->data == NULL) {
        !          2335:         return NGX_ERROR;
        !          2336:     }
        !          2337: 
        !          2338:     p = s->data;
        !          2339: 
        !          2340:     for (i = 0; i < cert.len - 1; i++) {
        !          2341:         *p++ = cert.data[i];
        !          2342:         if (cert.data[i] == LF) {
        !          2343:             *p++ = '\t';
        !          2344:         }
        !          2345:     }
        !          2346: 
        !          2347:     return NGX_OK;
        !          2348: }
        !          2349: 
        !          2350: 
        !          2351: ngx_int_t
        !          2352: ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
        !          2353: {
        !          2354:     char       *p;
        !          2355:     size_t      len;
        !          2356:     X509       *cert;
        !          2357:     X509_NAME  *name;
        !          2358: 
        !          2359:     s->len = 0;
        !          2360: 
        !          2361:     cert = SSL_get_peer_certificate(c->ssl->connection);
        !          2362:     if (cert == NULL) {
        !          2363:         return NGX_OK;
        !          2364:     }
        !          2365: 
        !          2366:     name = X509_get_subject_name(cert);
        !          2367:     if (name == NULL) {
        !          2368:         X509_free(cert);
        !          2369:         return NGX_ERROR;
        !          2370:     }
        !          2371: 
        !          2372:     p = X509_NAME_oneline(name, NULL, 0);
        !          2373: 
        !          2374:     for (len = 0; p[len]; len++) { /* void */ }
        !          2375: 
        !          2376:     s->len = len;
        !          2377:     s->data = ngx_pnalloc(pool, len);
        !          2378:     if (s->data == NULL) {
        !          2379:         OPENSSL_free(p);
        !          2380:         X509_free(cert);
        !          2381:         return NGX_ERROR;
        !          2382:     }
        !          2383: 
        !          2384:     ngx_memcpy(s->data, p, len);
        !          2385: 
        !          2386:     OPENSSL_free(p);
        !          2387:     X509_free(cert);
        !          2388: 
        !          2389:     return NGX_OK;
        !          2390: }
        !          2391: 
        !          2392: 
        !          2393: ngx_int_t
        !          2394: ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
        !          2395: {
        !          2396:     char       *p;
        !          2397:     size_t      len;
        !          2398:     X509       *cert;
        !          2399:     X509_NAME  *name;
        !          2400: 
        !          2401:     s->len = 0;
        !          2402: 
        !          2403:     cert = SSL_get_peer_certificate(c->ssl->connection);
        !          2404:     if (cert == NULL) {
        !          2405:         return NGX_OK;
        !          2406:     }
        !          2407: 
        !          2408:     name = X509_get_issuer_name(cert);
        !          2409:     if (name == NULL) {
        !          2410:         X509_free(cert);
        !          2411:         return NGX_ERROR;
        !          2412:     }
        !          2413: 
        !          2414:     p = X509_NAME_oneline(name, NULL, 0);
        !          2415: 
        !          2416:     for (len = 0; p[len]; len++) { /* void */ }
        !          2417: 
        !          2418:     s->len = len;
        !          2419:     s->data = ngx_pnalloc(pool, len);
        !          2420:     if (s->data == NULL) {
        !          2421:         OPENSSL_free(p);
        !          2422:         X509_free(cert);
        !          2423:         return NGX_ERROR;
        !          2424:     }
        !          2425: 
        !          2426:     ngx_memcpy(s->data, p, len);
        !          2427: 
        !          2428:     OPENSSL_free(p);
        !          2429:     X509_free(cert);
        !          2430: 
        !          2431:     return NGX_OK;
        !          2432: }
        !          2433: 
        !          2434: 
        !          2435: ngx_int_t
        !          2436: ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
        !          2437: {
        !          2438:     size_t   len;
        !          2439:     X509    *cert;
        !          2440:     BIO     *bio;
        !          2441: 
        !          2442:     s->len = 0;
        !          2443: 
        !          2444:     cert = SSL_get_peer_certificate(c->ssl->connection);
        !          2445:     if (cert == NULL) {
        !          2446:         return NGX_OK;
        !          2447:     }
        !          2448: 
        !          2449:     bio = BIO_new(BIO_s_mem());
        !          2450:     if (bio == NULL) {
        !          2451:         X509_free(cert);
        !          2452:         return NGX_ERROR;
        !          2453:     }
        !          2454: 
        !          2455:     i2a_ASN1_INTEGER(bio, X509_get_serialNumber(cert));
        !          2456:     len = BIO_pending(bio);
        !          2457: 
        !          2458:     s->len = len;
        !          2459:     s->data = ngx_pnalloc(pool, len);
        !          2460:     if (s->data == NULL) {
        !          2461:         BIO_free(bio);
        !          2462:         X509_free(cert);
        !          2463:         return NGX_ERROR;
        !          2464:     }
        !          2465: 
        !          2466:     BIO_read(bio, s->data, len);
        !          2467:     BIO_free(bio);
        !          2468:     X509_free(cert);
        !          2469: 
        !          2470:     return NGX_OK;
        !          2471: }
        !          2472: 
        !          2473: 
        !          2474: ngx_int_t
        !          2475: ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
        !          2476: {
        !          2477:     X509  *cert;
        !          2478: 
        !          2479:     if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) {
        !          2480:         ngx_str_set(s, "FAILED");
        !          2481:         return NGX_OK;
        !          2482:     }
        !          2483: 
        !          2484:     cert = SSL_get_peer_certificate(c->ssl->connection);
        !          2485: 
        !          2486:     if (cert) {
        !          2487:         ngx_str_set(s, "SUCCESS");
        !          2488: 
        !          2489:     } else {
        !          2490:         ngx_str_set(s, "NONE");
        !          2491:     }
        !          2492: 
        !          2493:     X509_free(cert);
        !          2494: 
        !          2495:     return NGX_OK;
        !          2496: }
        !          2497: 
        !          2498: 
        !          2499: static void *
        !          2500: ngx_openssl_create_conf(ngx_cycle_t *cycle)
        !          2501: {
        !          2502:     ngx_openssl_conf_t  *oscf;
        !          2503: 
        !          2504:     oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t));
        !          2505:     if (oscf == NULL) {
        !          2506:         return NULL;
        !          2507:     }
        !          2508: 
        !          2509:     /*
        !          2510:      * set by ngx_pcalloc():
        !          2511:      *
        !          2512:      *     oscf->engine = 0;
        !          2513:      */
        !          2514: 
        !          2515:     return oscf;
        !          2516: }
        !          2517: 
        !          2518: 
        !          2519: static char *
        !          2520: ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
        !          2521: {
        !          2522:     ngx_openssl_conf_t *oscf = conf;
        !          2523: 
        !          2524:     ENGINE     *engine;
        !          2525:     ngx_str_t  *value;
        !          2526: 
        !          2527:     if (oscf->engine) {
        !          2528:         return "is duplicate";
        !          2529:     }
        !          2530: 
        !          2531:     oscf->engine = 1;
        !          2532: 
        !          2533:     value = cf->args->elts;
        !          2534: 
        !          2535:     engine = ENGINE_by_id((const char *) value[1].data);
        !          2536: 
        !          2537:     if (engine == NULL) {
        !          2538:         ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
        !          2539:                       "ENGINE_by_id(\"%V\") failed", &value[1]);
        !          2540:         return NGX_CONF_ERROR;
        !          2541:     }
        !          2542: 
        !          2543:     if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) {
        !          2544:         ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
        !          2545:                       "ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed",
        !          2546:                       &value[1]);
        !          2547: 
        !          2548:         ENGINE_free(engine);
        !          2549: 
        !          2550:         return NGX_CONF_ERROR;
        !          2551:     }
        !          2552: 
        !          2553:     ENGINE_free(engine);
        !          2554: 
        !          2555:     return NGX_CONF_OK;
        !          2556: }
        !          2557: 
        !          2558: 
        !          2559: static void
        !          2560: ngx_openssl_exit(ngx_cycle_t *cycle)
        !          2561: {
        !          2562:     EVP_cleanup();
        !          2563:     ENGINE_cleanup();
        !          2564: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>