source: nginx/src/event/ngx_event_openssl_stapling.c

Last change on this file was 6593:b3b7e33083ac, checked in by Roman Arutyunyan <arut@…>, 2 months ago

Introduced ngx_inet_get_port() and ngx_inet_set_port() functions.

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