source: nginx/src/event/ngx_event_openssl_stapling.c

Last change on this file was 6688:6acbe9964ceb, checked in by Maxim Dounin <mdounin@…>, 2 weeks ago

OCSP stapling: fixed using wrong responder with multiple certs.

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