source: nginx/src/event/ngx_event_openssl_stapling.c

tip
Last change on this file was 6064:ff957cd36860, checked in by Filipe da Silva <fdasilva@…>, 8 weeks ago

OCSP stapling: missing free calls.

Missing call to X509_STORE_CTX_free when X509_STORE_CTX_init fails.
Missing call to OCSP_CERTID_free when OCSP_request_add0_id fails.
Possible leaks in vary particular scenariis of memory shortage.

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