source: nginx/src/event/ngx_event_openssl_stapling.c

Last change on this file was 6813:94586180fb41, checked in by Maxim Dounin <mdounin@…>, 2 days ago

OCSP stapling: improved error logging context.

It now logs the IP address of the responder used (if it's already known),
as well as the certificate name.

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