source: nginx/src/event/ngx_event_openssl_stapling.c

tip
Last change on this file was 6181:6893a1007a7c, checked in by Maxim Dounin <mdounin@…>, 3 weeks ago

OCSP stapling: avoid sending expired responses (ticket #425).

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