source: nginx/src/event/ngx_event_openssl_stapling.c

tip
Last change on this file was 5683:48c97d83ab7f, checked in by Filipe da Silva <fdasilvayy@…>, 3 months ago

OCSP stapling: missing OCSP request free call.

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