source: nginx/src/event/ngx_event_openssl_stapling.c

Last change on this file was 6491:45f2385a47e6, checked in by Sergey Kandaurov <pluknet@…>, 2 months ago

SSL: X509 was made opaque in OpenSSL 1.1.0.

To increment reference counters we now use newly introduced X509_up_ref()
function.

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