Annotation of embedaddon/nginx/src/event/ngx_event_openssl_stapling.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Maxim Dounin
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: #include <ngx_event.h>
                     11: #include <ngx_event_connect.h>
                     12: 
                     13: 
                     14: #ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB
                     15: 
                     16: 
                     17: typedef struct {
                     18:     ngx_str_t                    staple;
                     19:     ngx_msec_t                   timeout;
                     20: 
                     21:     ngx_resolver_t              *resolver;
                     22:     ngx_msec_t                   resolver_timeout;
                     23: 
                     24:     ngx_addr_t                  *addrs;
                     25:     ngx_str_t                    host;
                     26:     ngx_str_t                    uri;
                     27:     in_port_t                    port;
                     28: 
                     29:     SSL_CTX                     *ssl_ctx;
                     30: 
                     31:     X509                        *cert;
                     32:     X509                        *issuer;
                     33: 
                     34:     time_t                       valid;
                     35: 
                     36:     unsigned                     verify:1;
                     37:     unsigned                     loading:1;
                     38: } ngx_ssl_stapling_t;
                     39: 
                     40: 
                     41: typedef struct ngx_ssl_ocsp_ctx_s  ngx_ssl_ocsp_ctx_t;
                     42: 
                     43: struct ngx_ssl_ocsp_ctx_s {
                     44:     X509                        *cert;
                     45:     X509                        *issuer;
                     46: 
                     47:     ngx_uint_t                   naddrs;
                     48: 
                     49:     ngx_addr_t                  *addrs;
                     50:     ngx_str_t                    host;
                     51:     ngx_str_t                    uri;
                     52:     in_port_t                    port;
                     53: 
                     54:     ngx_resolver_t              *resolver;
                     55:     ngx_msec_t                   resolver_timeout;
                     56: 
                     57:     ngx_msec_t                   timeout;
                     58: 
                     59:     void                       (*handler)(ngx_ssl_ocsp_ctx_t *r);
                     60:     void                        *data;
                     61: 
                     62:     ngx_buf_t                   *request;
                     63:     ngx_buf_t                   *response;
                     64:     ngx_peer_connection_t        peer;
                     65: 
                     66:     ngx_int_t                  (*process)(ngx_ssl_ocsp_ctx_t *r);
                     67: 
                     68:     ngx_uint_t                   state;
                     69: 
                     70:     ngx_uint_t                   code;
                     71:     ngx_uint_t                   count;
                     72: 
                     73:     ngx_uint_t                   done;
                     74: 
                     75:     u_char                      *header_name_start;
                     76:     u_char                      *header_name_end;
                     77:     u_char                      *header_start;
                     78:     u_char                      *header_end;
                     79: 
                     80:     ngx_pool_t                  *pool;
                     81:     ngx_log_t                   *log;
                     82: };
                     83: 
                     84: 
                     85: static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
                     86:     ngx_str_t *file);
                     87: static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl);
                     88: static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
                     89:     ngx_str_t *responder);
                     90: 
                     91: static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
                     92:     void *data);
                     93: static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple);
                     94: static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx);
                     95: 
                     96: static void ngx_ssl_stapling_cleanup(void *data);
                     97: 
                     98: static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(void);
                     99: static void ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx);
                    100: static void ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx);
                    101: static void ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve);
                    102: static void ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx);
                    103: static void ngx_ssl_ocsp_write_handler(ngx_event_t *wev);
                    104: static void ngx_ssl_ocsp_read_handler(ngx_event_t *rev);
                    105: static void ngx_ssl_ocsp_dummy_handler(ngx_event_t *ev);
                    106: 
                    107: static ngx_int_t ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx);
                    108: static ngx_int_t ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx);
                    109: static ngx_int_t ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx);
                    110: static ngx_int_t ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx);
                    111: static ngx_int_t ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx);
                    112: static ngx_int_t ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx);
                    113: 
                    114: static u_char *ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len);
                    115: 
                    116: 
                    117: ngx_int_t
                    118: ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
                    119:     ngx_str_t *responder, ngx_uint_t verify)
                    120: {
                    121:     ngx_int_t                  rc;
                    122:     ngx_pool_cleanup_t        *cln;
                    123:     ngx_ssl_stapling_t        *staple;
                    124: 
                    125:     staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t));
                    126:     if (staple == NULL) {
                    127:         return NGX_ERROR;
                    128:     }
                    129: 
                    130:     cln = ngx_pool_cleanup_add(cf->pool, 0);
                    131:     if (cln == NULL) {
                    132:         return NGX_ERROR;
                    133:     }
                    134: 
                    135:     cln->handler = ngx_ssl_stapling_cleanup;
                    136:     cln->data = staple;
                    137: 
                    138:     if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staple)
                    139:         == 0)
                    140:     {
                    141:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                    142:                       "SSL_CTX_set_ex_data() failed");
                    143:         return NGX_ERROR;
                    144:     }
                    145: 
                    146:     staple->ssl_ctx = ssl->ctx;
                    147:     staple->timeout = 60000;
                    148:     staple->verify = verify;
                    149: 
                    150:     if (file->len) {
                    151:         /* use OCSP response from the file */
                    152: 
                    153:         if (ngx_ssl_stapling_file(cf, ssl, file) != NGX_OK) {
                    154:             return NGX_ERROR;
                    155:         }
                    156: 
                    157:         goto done;
                    158:     }
                    159: 
                    160:     rc = ngx_ssl_stapling_issuer(cf, ssl);
                    161: 
                    162:     if (rc == NGX_DECLINED) {
                    163:         return NGX_OK;
                    164:     }
                    165: 
                    166:     if (rc != NGX_OK) {
                    167:         return NGX_ERROR;
                    168:     }
                    169: 
                    170:     rc = ngx_ssl_stapling_responder(cf, ssl, responder);
                    171: 
                    172:     if (rc == NGX_DECLINED) {
                    173:         return NGX_OK;
                    174:     }
                    175: 
                    176:     if (rc != NGX_OK) {
                    177:         return NGX_ERROR;
                    178:     }
                    179: 
                    180: done:
                    181: 
                    182:     SSL_CTX_set_tlsext_status_cb(ssl->ctx, ngx_ssl_certificate_status_callback);
                    183:     SSL_CTX_set_tlsext_status_arg(ssl->ctx, staple);
                    184: 
                    185:     return NGX_OK;
                    186: }
                    187: 
                    188: 
                    189: static ngx_int_t
                    190: ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
                    191: {
                    192:     BIO                 *bio;
                    193:     int                  len;
                    194:     u_char              *p, *buf;
                    195:     OCSP_RESPONSE       *response;
                    196:     ngx_ssl_stapling_t  *staple;
                    197: 
                    198:     staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
                    199: 
                    200:     if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
                    201:         return NGX_ERROR;
                    202:     }
                    203: 
                    204:     bio = BIO_new_file((char *) file->data, "r");
                    205:     if (bio == NULL) {
                    206:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                    207:                       "BIO_new_file(\"%s\") failed", file->data);
                    208:         return NGX_ERROR;
                    209:     }
                    210: 
                    211:     response = d2i_OCSP_RESPONSE_bio(bio, NULL);
                    212:     if (response == NULL) {
                    213:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                    214:                       "d2i_OCSP_RESPONSE_bio(\"%s\") failed", file->data);
                    215:         BIO_free(bio);
                    216:         return NGX_ERROR;
                    217:     }
                    218: 
                    219:     len = i2d_OCSP_RESPONSE(response, NULL);
                    220:     if (len <= 0) {
                    221:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                    222:                       "i2d_OCSP_RESPONSE(\"%s\") failed", file->data);
                    223:         goto failed;
                    224:     }
                    225: 
                    226:     buf = ngx_alloc(len, ssl->log);
                    227:     if (buf == NULL) {
                    228:         goto failed;
                    229:     }
                    230: 
                    231:     p = buf;
                    232:     len = i2d_OCSP_RESPONSE(response, &p);
                    233:     if (len <= 0) {
                    234:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                    235:                       "i2d_OCSP_RESPONSE(\"%s\") failed", file->data);
                    236:         ngx_free(buf);
                    237:         goto failed;
                    238:     }
                    239: 
                    240:     OCSP_RESPONSE_free(response);
                    241:     BIO_free(bio);
                    242: 
                    243:     staple->staple.data = buf;
                    244:     staple->staple.len = len;
                    245: 
                    246:     return NGX_OK;
                    247: 
                    248: failed:
                    249: 
                    250:     OCSP_RESPONSE_free(response);
                    251:     BIO_free(bio);
                    252: 
                    253:     return NGX_ERROR;
                    254: }
                    255: 
                    256: 
                    257: static ngx_int_t
                    258: ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl)
                    259: {
                    260:     int                  i, n, rc;
                    261:     X509                *cert, *issuer;
                    262:     X509_STORE          *store;
                    263:     X509_STORE_CTX      *store_ctx;
                    264:     STACK_OF(X509)      *chain;
                    265:     ngx_ssl_stapling_t  *staple;
                    266: 
                    267:     staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
                    268:     cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index);
                    269: 
                    270: #if OPENSSL_VERSION_NUMBER >= 0x10001000L
                    271:     SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain);
                    272: #else
                    273:     chain = ssl->ctx->extra_certs;
                    274: #endif
                    275: 
                    276:     n = sk_X509_num(chain);
                    277: 
                    278:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
                    279:                    "SSL get issuer: %d extra certs", n);
                    280: 
                    281:     for (i = 0; i < n; i++) {
                    282:         issuer = sk_X509_value(chain, i);
                    283:         if (X509_check_issued(issuer, cert) == X509_V_OK) {
                    284:             CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509);
                    285: 
                    286:             ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
                    287:                            "SSL get issuer: found %p in extra certs", issuer);
                    288: 
                    289:             staple->cert = cert;
                    290:             staple->issuer = issuer;
                    291: 
                    292:             return NGX_OK;
                    293:         }
                    294:     }
                    295: 
                    296:     store = SSL_CTX_get_cert_store(ssl->ctx);
                    297:     if (store == NULL) {
                    298:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                    299:                       "SSL_CTX_get_cert_store() failed");
                    300:         return NGX_ERROR;
                    301:     }
                    302: 
                    303:     store_ctx = X509_STORE_CTX_new();
                    304:     if (store_ctx == NULL) {
                    305:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                    306:                       "X509_STORE_CTX_new() failed");
                    307:         return NGX_ERROR;
                    308:     }
                    309: 
                    310:     if (X509_STORE_CTX_init(store_ctx, store, NULL, NULL) == 0) {
                    311:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                    312:                       "X509_STORE_CTX_init() failed");
                    313:         return NGX_ERROR;
                    314:     }
                    315: 
                    316:     rc = X509_STORE_CTX_get1_issuer(&issuer, store_ctx, cert);
                    317: 
                    318:     if (rc == -1) {
                    319:         ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
                    320:                       "X509_STORE_CTX_get1_issuer() failed");
                    321:         X509_STORE_CTX_free(store_ctx);
                    322:         return NGX_ERROR;
                    323:     }
                    324: 
                    325:     if (rc == 0) {
                    326:         ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
                    327:                       "\"ssl_stapling\" ignored, issuer certificate not found");
                    328:         X509_STORE_CTX_free(store_ctx);
                    329:         return NGX_DECLINED;
                    330:     }
                    331: 
                    332:     X509_STORE_CTX_free(store_ctx);
                    333: 
                    334:     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0,
                    335:                    "SSL get issuer: found %p in cert store", issuer);
                    336: 
                    337:     staple->cert = cert;
                    338:     staple->issuer = issuer;
                    339: 
                    340:     return NGX_OK;
                    341: }
                    342: 
                    343: 
                    344: static ngx_int_t
                    345: ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder)
                    346: {
                    347:     ngx_url_t                  u;
                    348:     char                      *s;
                    349:     ngx_ssl_stapling_t        *staple;
                    350:     STACK_OF(OPENSSL_STRING)  *aia;
                    351: 
                    352:     staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
                    353: 
                    354:     if (responder->len == 0) {
                    355: 
                    356:         /* extract OCSP responder URL from certificate */
                    357: 
                    358:         aia = X509_get1_ocsp(staple->cert);
                    359:         if (aia == NULL) {
                    360:             ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
                    361:                           "\"ssl_stapling\" ignored, "
                    362:                           "no OCSP responder URL in the certificate");
                    363:             return NGX_DECLINED;
                    364:         }
                    365: 
                    366: #if OPENSSL_VERSION_NUMBER >= 0x10000000L
                    367:         s = sk_OPENSSL_STRING_value(aia, 0);
                    368: #else
                    369:         s = sk_value(aia, 0);
                    370: #endif
                    371:         if (s == NULL) {
                    372:             ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
                    373:                           "\"ssl_stapling\" ignored, "
                    374:                           "no OCSP responder URL in the certificate");
                    375:             X509_email_free(aia);
                    376:             return NGX_DECLINED;
                    377:         }
                    378: 
                    379:         responder->len = ngx_strlen(s);
                    380:         responder->data = ngx_palloc(cf->pool, responder->len);
                    381:         if (responder->data == NULL) {
                    382:             X509_email_free(aia);
                    383:             return NGX_ERROR;
                    384:         }
                    385: 
                    386:         ngx_memcpy(responder->data, s, responder->len);
                    387:         X509_email_free(aia);
                    388:     }
                    389: 
                    390:     ngx_memzero(&u, sizeof(ngx_url_t));
                    391: 
                    392:     u.url = *responder;
                    393:     u.default_port = 80;
                    394:     u.uri_part = 1;
                    395: 
                    396:     if (u.url.len > 7
                    397:         && ngx_strncasecmp(u.url.data, (u_char *) "http://", 7) == 0)
                    398:     {
                    399:         u.url.len -= 7;
                    400:         u.url.data += 7;
                    401: 
                    402:     } else {
                    403:         ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
                    404:                       "\"ssl_stapling\" ignored, "
                    405:                       "invalid URL prefix in OCSP responder \"%V\"", &u.url);
                    406:         return NGX_DECLINED;
                    407:     }
                    408: 
                    409:     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
                    410:         if (u.err) {
                    411:             ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
                    412:                           "\"ssl_stapling\" ignored, "
                    413:                           "%s in OCSP responder \"%V\"", u.err, &u.url);
                    414:             return NGX_DECLINED;
                    415:         }
                    416: 
                    417:         return NGX_ERROR;
                    418:     }
                    419: 
                    420:     staple->addrs = u.addrs;
                    421:     staple->host = u.host;
                    422:     staple->uri = u.uri;
                    423:     staple->port = u.port;
                    424: 
                    425:     if (staple->uri.len == 0) {
                    426:         ngx_str_set(&staple->uri, "/");
                    427:     }
                    428: 
                    429:     return NGX_OK;
                    430: }
                    431: 
                    432: 
                    433: ngx_int_t
                    434: ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
                    435:     ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
                    436: {
                    437:     ngx_ssl_stapling_t  *staple;
                    438: 
                    439:     staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
                    440: 
                    441:     staple->resolver = resolver;
                    442:     staple->resolver_timeout = resolver_timeout;
                    443: 
                    444:     return NGX_OK;
                    445: }
                    446: 
                    447: 
                    448: static int
                    449: ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
                    450: {
                    451:     int                  rc;
                    452:     u_char              *p;
                    453:     ngx_connection_t    *c;
                    454:     ngx_ssl_stapling_t  *staple;
                    455: 
                    456:     c = ngx_ssl_get_connection(ssl_conn);
                    457: 
                    458:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
                    459:                    "SSL certificate status callback");
                    460: 
                    461:     staple = data;
                    462:     rc = SSL_TLSEXT_ERR_NOACK;
                    463: 
                    464:     if (staple->staple.len) {
                    465:         /* we have to copy ocsp response as OpenSSL will free it by itself */
                    466: 
                    467:         p = OPENSSL_malloc(staple->staple.len);
                    468:         if (p == NULL) {
                    469:             ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "OPENSSL_malloc() failed");
                    470:             return SSL_TLSEXT_ERR_NOACK;
                    471:         }
                    472: 
                    473:         ngx_memcpy(p, staple->staple.data, staple->staple.len);
                    474: 
                    475:         SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, staple->staple.len);
                    476: 
                    477:         rc = SSL_TLSEXT_ERR_OK;
                    478:     }
                    479: 
                    480:     ngx_ssl_stapling_update(staple);
                    481: 
                    482:     return rc;
                    483: }
                    484: 
                    485: 
                    486: static void
                    487: ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
                    488: {
                    489:     ngx_ssl_ocsp_ctx_t  *ctx;
                    490: 
                    491:     if (staple->host.len == 0
                    492:         || staple->loading || staple->valid >= ngx_time())
                    493:     {
                    494:         return;
                    495:     }
                    496: 
                    497:     staple->loading = 1;
                    498: 
                    499:     ctx = ngx_ssl_ocsp_start();
                    500:     if (ctx == NULL) {
                    501:         return;
                    502:     }
                    503: 
                    504:     ctx->cert = staple->cert;
                    505:     ctx->issuer = staple->issuer;
                    506: 
                    507:     ctx->addrs = staple->addrs;
                    508:     ctx->host = staple->host;
                    509:     ctx->uri = staple->uri;
                    510:     ctx->port = staple->port;
                    511:     ctx->timeout = staple->timeout;
                    512: 
                    513:     ctx->resolver = staple->resolver;
                    514:     ctx->resolver_timeout = staple->resolver_timeout;
                    515: 
                    516:     ctx->handler = ngx_ssl_stapling_ocsp_handler;
                    517:     ctx->data = staple;
                    518: 
                    519:     ngx_ssl_ocsp_request(ctx);
                    520: 
                    521:     return;
                    522: }
                    523: 
                    524: 
                    525: static void
                    526: ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx)
                    527: {
                    528: #if OPENSSL_VERSION_NUMBER >= 0x0090707fL
                    529:     const
                    530: #endif
                    531:     u_char                *p;
                    532:     int                    n;
                    533:     size_t                 len;
                    534:     ngx_str_t              response;
                    535:     X509_STORE            *store;
                    536:     STACK_OF(X509)        *chain;
                    537:     OCSP_CERTID           *id;
                    538:     OCSP_RESPONSE         *ocsp;
                    539:     OCSP_BASICRESP        *basic;
                    540:     ngx_ssl_stapling_t    *staple;
                    541:     ASN1_GENERALIZEDTIME  *thisupdate, *nextupdate;
                    542: 
                    543:     staple = ctx->data;
                    544:     ocsp = NULL;
                    545:     basic = NULL;
                    546:     id = NULL;
                    547: 
                    548:     if (ctx->code != 200) {
                    549:         goto error;
                    550:     }
                    551: 
                    552:     /* check the response */
                    553: 
                    554:     len = ctx->response->last - ctx->response->pos;
                    555:     p = ctx->response->pos;
                    556: 
                    557:     ocsp = d2i_OCSP_RESPONSE(NULL, &p, len);
                    558:     if (ocsp == NULL) {
                    559:         ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
                    560:                       "d2i_OCSP_RESPONSE() failed");
                    561:         goto error;
                    562:     }
                    563: 
                    564:     n = OCSP_response_status(ocsp);
                    565: 
                    566:     if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
                    567:         ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
                    568:                       "OCSP response not successful (%d: %s)",
                    569:                       n, OCSP_response_status_str(n));
                    570:         goto error;
                    571:     }
                    572: 
                    573:     basic = OCSP_response_get1_basic(ocsp);
                    574:     if (basic == NULL) {
                    575:         ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
                    576:                       "OCSP_response_get1_basic() failed");
                    577:         goto error;
                    578:     }
                    579: 
                    580:     store = SSL_CTX_get_cert_store(staple->ssl_ctx);
                    581:     if (store == NULL) {
                    582:         ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                    583:                       "SSL_CTX_get_cert_store() failed");
                    584:         goto error;
                    585:     }
                    586: 
                    587: #if OPENSSL_VERSION_NUMBER >= 0x10001000L
                    588:     SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain);
                    589: #else
                    590:     chain = staple->ssl_ctx->extra_certs;
                    591: #endif
                    592: 
                    593:     if (OCSP_basic_verify(basic, chain, store,
                    594:                           staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY)
                    595:         != 1)
                    596:     {
                    597:         ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
                    598:                       "OCSP_basic_verify() failed");
                    599:         goto error;
                    600:     }
                    601: 
                    602:     id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
                    603:     if (id == NULL) {
                    604:         ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                    605:                       "OCSP_cert_to_id() failed");
                    606:         goto error;
                    607:     }
                    608: 
                    609:     if (OCSP_resp_find_status(basic, id, &n, NULL, NULL,
                    610:                               &thisupdate, &nextupdate)
                    611:         != 1)
                    612:     {
                    613:         ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
                    614:                       "certificate status not found in the OCSP response");
                    615:         goto error;
                    616:     }
                    617: 
                    618:     if (n != V_OCSP_CERTSTATUS_GOOD) {
                    619:         ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
                    620:                       "certificate status \"%s\" in the OCSP response",
                    621:                       OCSP_cert_status_str(n));
                    622:         goto error;
                    623:     }
                    624: 
                    625:     if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) {
                    626:         ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0,
                    627:                       "OCSP_check_validity() failed");
                    628:         goto error;
                    629:     }
                    630: 
                    631:     OCSP_CERTID_free(id);
                    632:     OCSP_BASICRESP_free(basic);
                    633:     OCSP_RESPONSE_free(ocsp);
                    634: 
                    635:     /* copy the response to memory not in ctx->pool */
                    636: 
                    637:     response.len = len;
                    638:     response.data = ngx_alloc(response.len, ctx->log);
                    639: 
                    640:     if (response.data == NULL) {
                    641:         goto done;
                    642:     }
                    643: 
                    644:     ngx_memcpy(response.data, ctx->response->pos, response.len);
                    645: 
                    646:     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                    647:                    "ssl ocsp response, %s, %uz",
                    648:                    OCSP_cert_status_str(n), response.len);
                    649: 
                    650:     if (staple->staple.data) {
                    651:         ngx_free(staple->staple.data);
                    652:     }
                    653: 
                    654:     staple->staple = response;
                    655: 
                    656: done:
                    657: 
                    658:     staple->loading = 0;
                    659:     staple->valid = ngx_time() + 3600; /* ssl_stapling_valid */
                    660: 
                    661:     ngx_ssl_ocsp_done(ctx);
                    662:     return;
                    663: 
                    664: error:
                    665: 
                    666:     staple->loading = 0;
                    667:     staple->valid = ngx_time() + 300; /* ssl_stapling_err_valid */
                    668: 
                    669:     if (id) {
                    670:         OCSP_CERTID_free(id);
                    671:     }
                    672: 
                    673:     if (basic) {
                    674:         OCSP_BASICRESP_free(basic);
                    675:     }
                    676: 
                    677:     if (ocsp) {
                    678:         OCSP_RESPONSE_free(ocsp);
                    679:     }
                    680: 
                    681:     ngx_ssl_ocsp_done(ctx);
                    682: }
                    683: 
                    684: 
                    685: static void
                    686: ngx_ssl_stapling_cleanup(void *data)
                    687: {
                    688:     ngx_ssl_stapling_t  *staple = data;
                    689: 
                    690:     if (staple->issuer) {
                    691:         X509_free(staple->issuer);
                    692:     }
                    693: 
                    694:     if (staple->staple.data) {
                    695:         ngx_free(staple->staple.data);
                    696:     }
                    697: }
                    698: 
                    699: 
                    700: static ngx_ssl_ocsp_ctx_t *
                    701: ngx_ssl_ocsp_start(void)
                    702: {
                    703:     ngx_log_t           *log;
                    704:     ngx_pool_t          *pool;
                    705:     ngx_ssl_ocsp_ctx_t  *ctx;
                    706: 
                    707:     pool = ngx_create_pool(2048, ngx_cycle->log);
                    708:     if (pool == NULL) {
                    709:         return NULL;
                    710:     }
                    711: 
                    712:     ctx = ngx_pcalloc(pool, sizeof(ngx_ssl_ocsp_ctx_t));
                    713:     if (ctx == NULL) {
                    714:         ngx_destroy_pool(pool);
                    715:         return NULL;
                    716:     }
                    717: 
                    718:     log = ngx_palloc(pool, sizeof(ngx_log_t));
                    719:     if (log == NULL) {
                    720:         ngx_destroy_pool(pool);
                    721:         return NULL;
                    722:     }
                    723: 
                    724:     ctx->pool = pool;
                    725: 
                    726:     *log = *ctx->pool->log;
                    727: 
                    728:     ctx->pool->log = log;
                    729:     ctx->log = log;
                    730: 
                    731:     log->handler = ngx_ssl_ocsp_log_error;
                    732:     log->data = ctx;
                    733:     log->action = "requesting certificate status";
                    734: 
                    735:     return ctx;
                    736: }
                    737: 
                    738: 
                    739: static void
                    740: ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx)
                    741: {
                    742:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                    743:                    "ssl ocsp done");
                    744: 
                    745:     if (ctx->peer.connection) {
                    746:         ngx_close_connection(ctx->peer.connection);
                    747:     }
                    748: 
                    749:     ngx_destroy_pool(ctx->pool);
                    750: }
                    751: 
                    752: 
                    753: static void
                    754: ngx_ssl_ocsp_error(ngx_ssl_ocsp_ctx_t *ctx)
                    755: {
                    756:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                    757:                    "ssl ocsp error");
                    758: 
                    759:     ctx->code = 0;
                    760:     ctx->handler(ctx);
                    761: }
                    762: 
                    763: 
                    764: static void
                    765: ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx)
                    766: {
                    767:     ngx_resolver_ctx_t  *resolve, temp;
                    768: 
                    769:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                    770:                    "ssl ocsp request");
                    771: 
                    772:     if (ngx_ssl_ocsp_create_request(ctx) != NGX_OK) {
                    773:         ngx_ssl_ocsp_error(ctx);
                    774:         return;
                    775:     }
                    776: 
                    777:     if (ctx->resolver) {
                    778:         /* resolve OCSP responder hostname */
                    779: 
                    780:         temp.name = ctx->host;
                    781: 
                    782:         resolve = ngx_resolve_start(ctx->resolver, &temp);
                    783:         if (resolve == NULL) {
                    784:             ngx_ssl_ocsp_error(ctx);
                    785:             return;
                    786:         }
                    787: 
                    788:         if (resolve == NGX_NO_RESOLVER) {
                    789:             ngx_log_error(NGX_LOG_WARN, ctx->log, 0,
                    790:                           "no resolver defined to resolve %V", &ctx->host);
                    791:             goto connect;
                    792:         }
                    793: 
                    794:         resolve->name = ctx->host;
                    795:         resolve->type = NGX_RESOLVE_A;
                    796:         resolve->handler = ngx_ssl_ocsp_resolve_handler;
                    797:         resolve->data = ctx;
                    798:         resolve->timeout = ctx->resolver_timeout;
                    799: 
                    800:         if (ngx_resolve_name(resolve) != NGX_OK) {
                    801:             ngx_ssl_ocsp_error(ctx);
                    802:             return;
                    803:         }
                    804: 
                    805:         return;
                    806:     }
                    807: 
                    808: connect:
                    809: 
                    810:     ngx_ssl_ocsp_connect(ctx);
                    811: }
                    812: 
                    813: 
                    814: static void
                    815: ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve)
                    816: {
                    817:     ngx_ssl_ocsp_ctx_t *ctx = resolve->data;
                    818: 
                    819:     u_char              *p;
                    820:     size_t               len;
                    821:     in_port_t            port;
                    822:     ngx_uint_t           i;
                    823:     struct sockaddr_in  *sin;
                    824: 
                    825:     ngx_log_debug0(NGX_LOG_ALERT, ctx->log, 0,
                    826:                    "ssl ocsp resolve handler");
                    827: 
                    828:     if (resolve->state) {
                    829:         ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
                    830:                       "%V could not be resolved (%i: %s)",
                    831:                       &resolve->name, resolve->state,
                    832:                       ngx_resolver_strerror(resolve->state));
                    833:         goto failed;
                    834:     }
                    835: 
                    836: #if (NGX_DEBUG)
                    837:     {
                    838:     in_addr_t   addr;
                    839: 
                    840:     for (i = 0; i < resolve->naddrs; i++) {
                    841:         addr = ntohl(resolve->addrs[i]);
                    842: 
                    843:         ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                    844:                        "name was resolved to %ud.%ud.%ud.%ud",
                    845:                        (addr >> 24) & 0xff, (addr >> 16) & 0xff,
                    846:                        (addr >> 8) & 0xff, addr & 0xff);
                    847:     }
                    848:     }
                    849: #endif
                    850: 
                    851:     ctx->naddrs = resolve->naddrs;
                    852:     ctx->addrs = ngx_pcalloc(ctx->pool, ctx->naddrs * sizeof(ngx_addr_t));
                    853: 
                    854:     if (ctx->addrs == NULL) {
                    855:         goto failed;
                    856:     }
                    857: 
                    858:     port = htons(ctx->port);
                    859: 
                    860:     for (i = 0; i < resolve->naddrs; i++) {
                    861: 
                    862:         sin = ngx_pcalloc(ctx->pool, sizeof(struct sockaddr_in));
                    863:         if (sin == NULL) {
                    864:             goto failed;
                    865:         }
                    866: 
                    867:         sin->sin_family = AF_INET;
                    868:         sin->sin_port = port;
                    869:         sin->sin_addr.s_addr = resolve->addrs[i];
                    870: 
                    871:         ctx->addrs[i].sockaddr = (struct sockaddr *) sin;
                    872:         ctx->addrs[i].socklen = sizeof(struct sockaddr_in);
                    873: 
                    874:         len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
                    875: 
                    876:         p = ngx_pnalloc(ctx->pool, len);
                    877:         if (p == NULL) {
                    878:             goto failed;
                    879:         }
                    880: 
                    881:         len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
                    882: 
                    883:         ctx->addrs[i].name.len = len;
                    884:         ctx->addrs[i].name.data = p;
                    885:     }
                    886: 
                    887:     ngx_resolve_name_done(resolve);
                    888: 
                    889:     ngx_ssl_ocsp_connect(ctx);
                    890:     return;
                    891: 
                    892: failed:
                    893: 
                    894:     ngx_resolve_name_done(resolve);
                    895:     ngx_ssl_ocsp_error(ctx);
                    896: }
                    897: 
                    898: 
                    899: static void
                    900: ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx)
                    901: {
                    902:     ngx_int_t    rc;
                    903: 
                    904:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                    905:                    "ssl ocsp connect");
                    906: 
                    907:     /* TODO: use all ip addresses */
                    908: 
                    909:     ctx->peer.sockaddr = ctx->addrs[0].sockaddr;
                    910:     ctx->peer.socklen = ctx->addrs[0].socklen;
                    911:     ctx->peer.name = &ctx->addrs[0].name;
                    912:     ctx->peer.get = ngx_event_get_peer;
                    913:     ctx->peer.log = ctx->log;
                    914:     ctx->peer.log_error = NGX_ERROR_ERR;
                    915: 
                    916:     rc = ngx_event_connect_peer(&ctx->peer);
                    917: 
                    918:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                    919:                    "ssl ocsp connect peer done");
                    920: 
                    921:     if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
                    922:         ngx_ssl_ocsp_error(ctx);
                    923:         return;
                    924:     }
                    925: 
                    926:     ctx->peer.connection->data = ctx;
                    927:     ctx->peer.connection->pool = ctx->pool;
                    928: 
                    929:     ctx->peer.connection->read->handler = ngx_ssl_ocsp_read_handler;
                    930:     ctx->peer.connection->write->handler = ngx_ssl_ocsp_write_handler;
                    931: 
                    932:     ctx->process = ngx_ssl_ocsp_process_status_line;
                    933: 
                    934:     ngx_add_timer(ctx->peer.connection->read, ctx->timeout);
                    935:     ngx_add_timer(ctx->peer.connection->write, ctx->timeout);
                    936: 
                    937:     if (rc == NGX_OK) {
                    938:         ngx_ssl_ocsp_write_handler(ctx->peer.connection->write);
                    939:         return;
                    940:     }
                    941: }
                    942: 
                    943: 
                    944: static void
                    945: ngx_ssl_ocsp_write_handler(ngx_event_t *wev)
                    946: {
                    947:     ssize_t              n, size;
                    948:     ngx_connection_t    *c;
                    949:     ngx_ssl_ocsp_ctx_t  *ctx;
                    950: 
                    951:     c = wev->data;
                    952:     ctx = c->data;
                    953: 
                    954:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, wev->log, 0,
                    955:                    "ssl ocsp write handler");
                    956: 
                    957:     if (wev->timedout) {
                    958:         ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
                    959:                       "OCSP responder timed out");
                    960:         ngx_ssl_ocsp_error(ctx);
                    961:         return;
                    962:     }
                    963: 
                    964:     size = ctx->request->last - ctx->request->pos;
                    965: 
                    966:     n = ngx_send(c, ctx->request->pos, size);
                    967: 
                    968:     if (n == NGX_ERROR) {
                    969:         ngx_ssl_ocsp_error(ctx);
                    970:         return;
                    971:     }
                    972: 
                    973:     if (n > 0) {
                    974:         ctx->request->pos += n;
                    975: 
                    976:         if (n == size) {
                    977:             wev->handler = ngx_ssl_ocsp_dummy_handler;
                    978: 
                    979:             if (wev->timer_set) {
                    980:                 ngx_del_timer(wev);
                    981:             }
                    982: 
                    983:             if (ngx_handle_write_event(wev, 0) != NGX_OK) {
                    984:                 ngx_ssl_ocsp_error(ctx);
                    985:             }
                    986: 
                    987:             return;
                    988:         }
                    989:     }
                    990: 
                    991:     if (!wev->timer_set) {
                    992:         ngx_add_timer(wev, ctx->timeout);
                    993:     }
                    994: }
                    995: 
                    996: 
                    997: static void
                    998: ngx_ssl_ocsp_read_handler(ngx_event_t *rev)
                    999: {
                   1000:     ssize_t            n, size;
                   1001:     ngx_int_t          rc;
                   1002:     ngx_ssl_ocsp_ctx_t    *ctx;
                   1003:     ngx_connection_t  *c;
                   1004: 
                   1005:     c = rev->data;
                   1006:     ctx = c->data;
                   1007: 
                   1008:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, rev->log, 0,
                   1009:                    "ssl ocsp read handler");
                   1010: 
                   1011:     if (rev->timedout) {
                   1012:         ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
                   1013:                       "OCSP responder timed out");
                   1014:         ngx_ssl_ocsp_error(ctx);
                   1015:         return;
                   1016:     }
                   1017: 
                   1018:     if (ctx->response == NULL) {
                   1019:         ctx->response = ngx_create_temp_buf(ctx->pool, 16384);
                   1020:         if (ctx->response == NULL) {
                   1021:             ngx_ssl_ocsp_error(ctx);
                   1022:             return;
                   1023:         }
                   1024:     }
                   1025: 
                   1026:     for ( ;; ) {
                   1027: 
                   1028:         size = ctx->response->end - ctx->response->last;
                   1029: 
                   1030:         n = ngx_recv(c, ctx->response->last, size);
                   1031: 
                   1032:         if (n > 0) {
                   1033:             ctx->response->last += n;
                   1034: 
                   1035:             rc = ctx->process(ctx);
                   1036: 
                   1037:             if (rc == NGX_ERROR) {
                   1038:                 ngx_ssl_ocsp_error(ctx);
                   1039:                 return;
                   1040:             }
                   1041: 
                   1042:             continue;
                   1043:         }
                   1044: 
                   1045:         if (n == NGX_AGAIN) {
                   1046: 
                   1047:             if (ngx_handle_read_event(rev, 0) != NGX_OK) {
                   1048:                 ngx_ssl_ocsp_error(ctx);
                   1049:             }
                   1050: 
                   1051:             return;
                   1052:         }
                   1053: 
                   1054:         break;
                   1055:     }
                   1056: 
                   1057:     ctx->done = 1;
                   1058: 
                   1059:     rc = ctx->process(ctx);
                   1060: 
                   1061:     if (rc == NGX_DONE) {
                   1062:         /* ctx->handler() was called */
                   1063:         return;
                   1064:     }
                   1065: 
                   1066:     ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
                   1067:                   "OCSP responder prematurely closed connection");
                   1068: 
                   1069:     ngx_ssl_ocsp_error(ctx);
                   1070: }
                   1071: 
                   1072: 
                   1073: static void
                   1074: ngx_ssl_ocsp_dummy_handler(ngx_event_t *ev)
                   1075: {
                   1076:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                   1077:                    "ssl ocsp dummy handler");
                   1078: }
                   1079: 
                   1080: 
                   1081: static ngx_int_t
                   1082: ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx)
                   1083: {
                   1084:     int            len;
                   1085:     u_char        *p;
                   1086:     uintptr_t      escape;
                   1087:     ngx_str_t      binary, base64;
                   1088:     ngx_buf_t     *b;
                   1089:     OCSP_CERTID   *id;
                   1090:     OCSP_REQUEST  *ocsp;
                   1091: 
                   1092:     ocsp = OCSP_REQUEST_new();
                   1093:     if (ocsp == NULL) {
                   1094:         ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                   1095:                       "OCSP_REQUEST_new() failed");
                   1096:         return NGX_ERROR;
                   1097:     }
                   1098: 
                   1099:     id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
                   1100:     if (id == NULL) {
                   1101:         ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                   1102:                       "OCSP_cert_to_id() failed");
                   1103:         goto failed;
                   1104:     }
                   1105: 
                   1106:     if (OCSP_request_add0_id(ocsp, id) == NULL) {
                   1107:         ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                   1108:                       "OCSP_request_add0_id() failed");
                   1109:         goto failed;
                   1110:     }
                   1111: 
                   1112:     len = i2d_OCSP_REQUEST(ocsp, NULL);
                   1113:     if (len <= 0) {
                   1114:         ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
                   1115:                       "i2d_OCSP_REQUEST() failed");
                   1116:         goto failed;
                   1117:     }
                   1118: 
                   1119:     binary.len = len;
                   1120:     binary.data = ngx_palloc(ctx->pool, len);
                   1121:     if (binary.data == NULL) {
                   1122:         goto failed;
                   1123:     }
                   1124: 
                   1125:     p = binary.data;
                   1126:     len = i2d_OCSP_REQUEST(ocsp, &p);
                   1127:     if (len <= 0) {
                   1128:         ngx_ssl_error(NGX_LOG_EMERG, ctx->log, 0,
                   1129:                       "i2d_OCSP_REQUEST() failed");
                   1130:         goto failed;
                   1131:     }
                   1132: 
                   1133:     base64.len = ngx_base64_encoded_length(binary.len);
                   1134:     base64.data = ngx_palloc(ctx->pool, base64.len);
                   1135:     if (base64.data == NULL) {
                   1136:         goto failed;
                   1137:     }
                   1138: 
                   1139:     ngx_encode_base64(&base64, &binary);
                   1140: 
                   1141:     escape = ngx_escape_uri(NULL, base64.data, base64.len,
                   1142:                             NGX_ESCAPE_URI_COMPONENT);
                   1143: 
                   1144:     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                   1145:                    "ssl ocsp request length %z, escape %d",
                   1146:                    base64.len, escape);
                   1147: 
                   1148:     len = sizeof("GET ") - 1 + ctx->uri.len + sizeof("/") - 1
                   1149:           + base64.len + 2 * escape + sizeof(" HTTP/1.0" CRLF) - 1
                   1150:           + sizeof("Host: ") - 1 + ctx->host.len + sizeof(CRLF) - 1
                   1151:           + sizeof(CRLF) - 1;
                   1152: 
                   1153:     b = ngx_create_temp_buf(ctx->pool, len);
                   1154:     if (b == NULL) {
                   1155:         goto failed;
                   1156:     }
                   1157: 
                   1158:     p = b->last;
                   1159: 
                   1160:     p = ngx_cpymem(p, "GET ", sizeof("GET ") - 1);
                   1161:     p = ngx_cpymem(p, ctx->uri.data, ctx->uri.len);
                   1162: 
                   1163:     if (ctx->uri.data[ctx->uri.len - 1] != '/') {
                   1164:         *p++ = '/';
                   1165:     }
                   1166: 
                   1167:     if (escape == 0) {
                   1168:         p = ngx_cpymem(p, base64.data, base64.len);
                   1169: 
                   1170:     } else {
                   1171:         p = (u_char *) ngx_escape_uri(p, base64.data, base64.len,
                   1172:                                       NGX_ESCAPE_URI_COMPONENT);
                   1173:     }
                   1174: 
                   1175:     p = ngx_cpymem(p, " HTTP/1.0" CRLF, sizeof(" HTTP/1.0" CRLF) - 1);
                   1176:     p = ngx_cpymem(p, "Host: ", sizeof("Host: ") - 1);
                   1177:     p = ngx_cpymem(p, ctx->host.data, ctx->host.len);
                   1178:     *p++ = CR; *p++ = LF;
                   1179: 
                   1180:     /* add "\r\n" at the header end */
                   1181:     *p++ = CR; *p++ = LF;
                   1182: 
                   1183:     b->last = p;
                   1184:     ctx->request = b;
                   1185: 
                   1186:     return NGX_OK;
                   1187: 
                   1188: failed:
                   1189: 
                   1190:     OCSP_REQUEST_free(ocsp);
                   1191: 
                   1192:     return NGX_ERROR;
                   1193: }
                   1194: 
                   1195: 
                   1196: static ngx_int_t
                   1197: ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx)
                   1198: {
                   1199:     ngx_int_t  rc;
                   1200: 
                   1201:     rc = ngx_ssl_ocsp_parse_status_line(ctx);
                   1202: 
                   1203:     if (rc == NGX_OK) {
                   1204: #if 0
                   1205:         ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                   1206:                        "ssl ocsp status line \"%*s\"",
                   1207:                        ctx->response->pos - ctx->response->start,
                   1208:                        ctx->response->start);
                   1209: #endif
                   1210: 
                   1211:         ctx->process = ngx_ssl_ocsp_process_headers;
                   1212:         return ctx->process(ctx);
                   1213:     }
                   1214: 
                   1215:     if (rc == NGX_AGAIN) {
                   1216:         return NGX_AGAIN;
                   1217:     }
                   1218: 
                   1219:     /* rc == NGX_ERROR */
                   1220: 
                   1221:     ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
                   1222:                   "OCSP responder sent invalid response");
                   1223: 
                   1224:     return NGX_ERROR;
                   1225: }
                   1226: 
                   1227: 
                   1228: static ngx_int_t
                   1229: ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx)
                   1230: {
                   1231:     u_char      ch;
                   1232:     u_char     *p;
                   1233:     ngx_buf_t  *b;
                   1234:     enum {
                   1235:         sw_start = 0,
                   1236:         sw_H,
                   1237:         sw_HT,
                   1238:         sw_HTT,
                   1239:         sw_HTTP,
                   1240:         sw_first_major_digit,
                   1241:         sw_major_digit,
                   1242:         sw_first_minor_digit,
                   1243:         sw_minor_digit,
                   1244:         sw_status,
                   1245:         sw_space_after_status,
                   1246:         sw_status_text,
                   1247:         sw_almost_done
                   1248:     } state;
                   1249: 
                   1250:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                   1251:                    "ssl ocsp process status line");
                   1252: 
                   1253:     state = ctx->state;
                   1254:     b = ctx->response;
                   1255: 
                   1256:     for (p = b->pos; p < b->last; p++) {
                   1257:         ch = *p;
                   1258: 
                   1259:         switch (state) {
                   1260: 
                   1261:         /* "HTTP/" */
                   1262:         case sw_start:
                   1263:             switch (ch) {
                   1264:             case 'H':
                   1265:                 state = sw_H;
                   1266:                 break;
                   1267:             default:
                   1268:                 return NGX_ERROR;
                   1269:             }
                   1270:             break;
                   1271: 
                   1272:         case sw_H:
                   1273:             switch (ch) {
                   1274:             case 'T':
                   1275:                 state = sw_HT;
                   1276:                 break;
                   1277:             default:
                   1278:                 return NGX_ERROR;
                   1279:             }
                   1280:             break;
                   1281: 
                   1282:         case sw_HT:
                   1283:             switch (ch) {
                   1284:             case 'T':
                   1285:                 state = sw_HTT;
                   1286:                 break;
                   1287:             default:
                   1288:                 return NGX_ERROR;
                   1289:             }
                   1290:             break;
                   1291: 
                   1292:         case sw_HTT:
                   1293:             switch (ch) {
                   1294:             case 'P':
                   1295:                 state = sw_HTTP;
                   1296:                 break;
                   1297:             default:
                   1298:                 return NGX_ERROR;
                   1299:             }
                   1300:             break;
                   1301: 
                   1302:         case sw_HTTP:
                   1303:             switch (ch) {
                   1304:             case '/':
                   1305:                 state = sw_first_major_digit;
                   1306:                 break;
                   1307:             default:
                   1308:                 return NGX_ERROR;
                   1309:             }
                   1310:             break;
                   1311: 
                   1312:         /* the first digit of major HTTP version */
                   1313:         case sw_first_major_digit:
                   1314:             if (ch < '1' || ch > '9') {
                   1315:                 return NGX_ERROR;
                   1316:             }
                   1317: 
                   1318:             state = sw_major_digit;
                   1319:             break;
                   1320: 
                   1321:         /* the major HTTP version or dot */
                   1322:         case sw_major_digit:
                   1323:             if (ch == '.') {
                   1324:                 state = sw_first_minor_digit;
                   1325:                 break;
                   1326:             }
                   1327: 
                   1328:             if (ch < '0' || ch > '9') {
                   1329:                 return NGX_ERROR;
                   1330:             }
                   1331: 
                   1332:             break;
                   1333: 
                   1334:         /* the first digit of minor HTTP version */
                   1335:         case sw_first_minor_digit:
                   1336:             if (ch < '0' || ch > '9') {
                   1337:                 return NGX_ERROR;
                   1338:             }
                   1339: 
                   1340:             state = sw_minor_digit;
                   1341:             break;
                   1342: 
                   1343:         /* the minor HTTP version or the end of the request line */
                   1344:         case sw_minor_digit:
                   1345:             if (ch == ' ') {
                   1346:                 state = sw_status;
                   1347:                 break;
                   1348:             }
                   1349: 
                   1350:             if (ch < '0' || ch > '9') {
                   1351:                 return NGX_ERROR;
                   1352:             }
                   1353: 
                   1354:             break;
                   1355: 
                   1356:         /* HTTP status code */
                   1357:         case sw_status:
                   1358:             if (ch == ' ') {
                   1359:                 break;
                   1360:             }
                   1361: 
                   1362:             if (ch < '0' || ch > '9') {
                   1363:                 return NGX_ERROR;
                   1364:             }
                   1365: 
                   1366:             ctx->code = ctx->code * 10 + ch - '0';
                   1367: 
                   1368:             if (++ctx->count == 3) {
                   1369:                 state = sw_space_after_status;
                   1370:             }
                   1371: 
                   1372:             break;
                   1373: 
                   1374:         /* space or end of line */
                   1375:         case sw_space_after_status:
                   1376:             switch (ch) {
                   1377:             case ' ':
                   1378:                 state = sw_status_text;
                   1379:                 break;
                   1380:             case '.':                    /* IIS may send 403.1, 403.2, etc */
                   1381:                 state = sw_status_text;
                   1382:                 break;
                   1383:             case CR:
                   1384:                 state = sw_almost_done;
                   1385:                 break;
                   1386:             case LF:
                   1387:                 goto done;
                   1388:             default:
                   1389:                 return NGX_ERROR;
                   1390:             }
                   1391:             break;
                   1392: 
                   1393:         /* any text until end of line */
                   1394:         case sw_status_text:
                   1395:             switch (ch) {
                   1396:             case CR:
                   1397:                 state = sw_almost_done;
                   1398:                 break;
                   1399:             case LF:
                   1400:                 goto done;
                   1401:             }
                   1402:             break;
                   1403: 
                   1404:         /* end of status line */
                   1405:         case sw_almost_done:
                   1406:             switch (ch) {
                   1407:             case LF:
                   1408:                 goto done;
                   1409:             default:
                   1410:                 return NGX_ERROR;
                   1411:             }
                   1412:         }
                   1413:     }
                   1414: 
                   1415:     b->pos = p;
                   1416:     ctx->state = state;
                   1417: 
                   1418:     return NGX_AGAIN;
                   1419: 
                   1420: done:
                   1421: 
                   1422:     b->pos = p + 1;
                   1423:     ctx->state = sw_start;
                   1424: 
                   1425:     return NGX_OK;
                   1426: }
                   1427: 
                   1428: 
                   1429: static ngx_int_t
                   1430: ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx)
                   1431: {
                   1432:     size_t     len;
                   1433:     ngx_int_t  rc;
                   1434: 
                   1435:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                   1436:                    "ssl ocsp process headers");
                   1437: 
                   1438:     for ( ;; ) {
                   1439:         rc = ngx_ssl_ocsp_parse_header_line(ctx);
                   1440: 
                   1441:         if (rc == NGX_OK) {
                   1442: 
                   1443:             ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                   1444:                            "ssl ocsp header \"%*s: %*s\"",
                   1445:                            ctx->header_name_end - ctx->header_name_start,
                   1446:                            ctx->header_name_start,
                   1447:                            ctx->header_end - ctx->header_start,
                   1448:                            ctx->header_start);
                   1449: 
                   1450:             len = ctx->header_name_end - ctx->header_name_start;
                   1451: 
                   1452:             if (len == sizeof("Content-Type") - 1
                   1453:                 && ngx_strncasecmp(ctx->header_name_start,
                   1454:                                    (u_char *) "Content-Type",
                   1455:                                    sizeof("Content-Type") - 1)
                   1456:                    == 0)
                   1457:             {
                   1458:                 len = ctx->header_end - ctx->header_start;
                   1459: 
                   1460:                 if (len != sizeof("application/ocsp-response") - 1
                   1461:                     || ngx_strncasecmp(ctx->header_start,
                   1462:                                        (u_char *) "application/ocsp-response",
                   1463:                                        sizeof("application/ocsp-response") - 1)
                   1464:                        != 0)
                   1465:                 {
                   1466:                     ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
                   1467:                                   "OCSP responder sent invalid "
                   1468:                                   "\"Content-Type\" header: \"%*s\"",
                   1469:                                   ctx->header_end - ctx->header_start,
                   1470:                                   ctx->header_start);
                   1471:                     return NGX_ERROR;
                   1472:                 }
                   1473: 
                   1474:                 continue;
                   1475:             }
                   1476: 
                   1477:             /* TODO: honor Content-Length */
                   1478: 
                   1479:             continue;
                   1480:         }
                   1481: 
                   1482:         if (rc == NGX_DONE) {
                   1483:             break;
                   1484:         }
                   1485: 
                   1486:         if (rc == NGX_AGAIN) {
                   1487:             return NGX_AGAIN;
                   1488:         }
                   1489: 
                   1490:         /* rc == NGX_ERROR */
                   1491: 
                   1492:         ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
                   1493:                       "OCSP responder sent invalid response");
                   1494: 
                   1495:         return NGX_ERROR;
                   1496:     }
                   1497: 
                   1498:     ctx->process = ngx_ssl_ocsp_process_body;
                   1499:     return ctx->process(ctx);
                   1500: }
                   1501: 
                   1502: static ngx_int_t
                   1503: ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx)
                   1504: {
                   1505:     u_char      c, ch, *p;
                   1506:     enum {
                   1507:         sw_start = 0,
                   1508:         sw_name,
                   1509:         sw_space_before_value,
                   1510:         sw_value,
                   1511:         sw_space_after_value,
                   1512:         sw_almost_done,
                   1513:         sw_header_almost_done
                   1514:     } state;
                   1515: 
                   1516:     state = ctx->state;
                   1517: 
                   1518:     for (p = ctx->response->pos; p < ctx->response->last; p++) {
                   1519:         ch = *p;
                   1520: 
                   1521: #if 0
                   1522:         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                   1523:                        "s:%d in:'%02Xd:%c'", state, ch, ch);
                   1524: #endif
                   1525: 
                   1526:         switch (state) {
                   1527: 
                   1528:         /* first char */
                   1529:         case sw_start:
                   1530: 
                   1531:             switch (ch) {
                   1532:             case CR:
                   1533:                 ctx->header_end = p;
                   1534:                 state = sw_header_almost_done;
                   1535:                 break;
                   1536:             case LF:
                   1537:                 ctx->header_end = p;
                   1538:                 goto header_done;
                   1539:             default:
                   1540:                 state = sw_name;
                   1541:                 ctx->header_name_start = p;
                   1542: 
                   1543:                 c = (u_char) (ch | 0x20);
                   1544:                 if (c >= 'a' && c <= 'z') {
                   1545:                     break;
                   1546:                 }
                   1547: 
                   1548:                 if (ch >= '0' && ch <= '9') {
                   1549:                     break;
                   1550:                 }
                   1551: 
                   1552:                 return NGX_ERROR;
                   1553:             }
                   1554:             break;
                   1555: 
                   1556:         /* header name */
                   1557:         case sw_name:
                   1558:             c = (u_char) (ch | 0x20);
                   1559:             if (c >= 'a' && c <= 'z') {
                   1560:                 break;
                   1561:             }
                   1562: 
                   1563:             if (ch == ':') {
                   1564:                 ctx->header_name_end = p;
                   1565:                 state = sw_space_before_value;
                   1566:                 break;
                   1567:             }
                   1568: 
                   1569:             if (ch == '-') {
                   1570:                 break;
                   1571:             }
                   1572: 
                   1573:             if (ch >= '0' && ch <= '9') {
                   1574:                 break;
                   1575:             }
                   1576: 
                   1577:             if (ch == CR) {
                   1578:                 ctx->header_name_end = p;
                   1579:                 ctx->header_start = p;
                   1580:                 ctx->header_end = p;
                   1581:                 state = sw_almost_done;
                   1582:                 break;
                   1583:             }
                   1584: 
                   1585:             if (ch == LF) {
                   1586:                 ctx->header_name_end = p;
                   1587:                 ctx->header_start = p;
                   1588:                 ctx->header_end = p;
                   1589:                 goto done;
                   1590:             }
                   1591: 
                   1592:             return NGX_ERROR;
                   1593: 
                   1594:         /* space* before header value */
                   1595:         case sw_space_before_value:
                   1596:             switch (ch) {
                   1597:             case ' ':
                   1598:                 break;
                   1599:             case CR:
                   1600:                 ctx->header_start = p;
                   1601:                 ctx->header_end = p;
                   1602:                 state = sw_almost_done;
                   1603:                 break;
                   1604:             case LF:
                   1605:                 ctx->header_start = p;
                   1606:                 ctx->header_end = p;
                   1607:                 goto done;
                   1608:             default:
                   1609:                 ctx->header_start = p;
                   1610:                 state = sw_value;
                   1611:                 break;
                   1612:             }
                   1613:             break;
                   1614: 
                   1615:         /* header value */
                   1616:         case sw_value:
                   1617:             switch (ch) {
                   1618:             case ' ':
                   1619:                 ctx->header_end = p;
                   1620:                 state = sw_space_after_value;
                   1621:                 break;
                   1622:             case CR:
                   1623:                 ctx->header_end = p;
                   1624:                 state = sw_almost_done;
                   1625:                 break;
                   1626:             case LF:
                   1627:                 ctx->header_end = p;
                   1628:                 goto done;
                   1629:             }
                   1630:             break;
                   1631: 
                   1632:         /* space* before end of header line */
                   1633:         case sw_space_after_value:
                   1634:             switch (ch) {
                   1635:             case ' ':
                   1636:                 break;
                   1637:             case CR:
                   1638:                 state = sw_almost_done;
                   1639:                 break;
                   1640:             case LF:
                   1641:                 goto done;
                   1642:             default:
                   1643:                 state = sw_value;
                   1644:                 break;
                   1645:             }
                   1646:             break;
                   1647: 
                   1648:         /* end of header line */
                   1649:         case sw_almost_done:
                   1650:             switch (ch) {
                   1651:             case LF:
                   1652:                 goto done;
                   1653:             default:
                   1654:                 return NGX_ERROR;
                   1655:             }
                   1656: 
                   1657:         /* end of header */
                   1658:         case sw_header_almost_done:
                   1659:             switch (ch) {
                   1660:             case LF:
                   1661:                 goto header_done;
                   1662:             default:
                   1663:                 return NGX_ERROR;
                   1664:             }
                   1665:         }
                   1666:     }
                   1667: 
                   1668:     ctx->response->pos = p;
                   1669:     ctx->state = state;
                   1670: 
                   1671:     return NGX_AGAIN;
                   1672: 
                   1673: done:
                   1674: 
                   1675:     ctx->response->pos = p + 1;
                   1676:     ctx->state = sw_start;
                   1677: 
                   1678:     return NGX_OK;
                   1679: 
                   1680: header_done:
                   1681: 
                   1682:     ctx->response->pos = p + 1;
                   1683:     ctx->state = sw_start;
                   1684: 
                   1685:     return NGX_DONE;
                   1686: }
                   1687: 
                   1688: 
                   1689: static ngx_int_t
                   1690: ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx)
                   1691: {
                   1692:     ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
                   1693:                    "ssl ocsp process body");
                   1694: 
                   1695:     if (ctx->done) {
                   1696:         ctx->handler(ctx);
                   1697:         return NGX_DONE;
                   1698:     }
                   1699: 
                   1700:     return NGX_AGAIN;
                   1701: }
                   1702: 
                   1703: 
                   1704: static u_char *
                   1705: ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len)
                   1706: {
                   1707:     u_char              *p;
                   1708:     ngx_ssl_ocsp_ctx_t  *ctx;
                   1709: 
                   1710:     p = buf;
                   1711: 
                   1712:     if (log->action) {
                   1713:         p = ngx_snprintf(buf, len, " while %s", log->action);
                   1714:         len -= p - buf;
                   1715:     }
                   1716: 
                   1717:     ctx = log->data;
                   1718: 
                   1719:     if (ctx) {
                   1720:         p = ngx_snprintf(p, len, ", responder: %V", &ctx->host);
                   1721:     }
                   1722: 
                   1723:     return p;
                   1724: }
                   1725: 
                   1726: 
                   1727: #else
                   1728: 
                   1729: 
                   1730: ngx_int_t
                   1731: ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
                   1732:     ngx_str_t *responder, ngx_uint_t verify)
                   1733: {
                   1734:     ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
                   1735:                   "\"ssl_stapling\" ignored, not supported");
                   1736: 
                   1737:     return NGX_OK;
                   1738: }
                   1739: 
                   1740: ngx_int_t
                   1741: ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
                   1742:     ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
                   1743: {
                   1744:     return NGX_OK;
                   1745: }
                   1746: 
                   1747: 
                   1748: #endif

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