source: nginx/src/event/ngx_event_openssl_stapling.c

tip
Last change on this file was 6206:595b179e429f, checked in by Maxim Dounin <mdounin@…>, 3 weeks ago

OCSP stapling: fixed segfault without nextUpdate.

OCSP responses may contain no nextUpdate. As per RFC 6960, this means
that nextUpdate checks should be bypassed. Handle this gracefully by
using NGX_MAX_TIME_T_VALUE as "valid" in such a case.

The problem was introduced by 6893a1007a7c (1.9.2).

Reported by Matthew Baldwin.

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