Annotation of embedaddon/nginx/src/event/ngx_event_openssl_stapling.c, revision 1.1.1.1
1.1 misho 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:
17: typedef 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:
41: typedef struct ngx_ssl_ocsp_ctx_s ngx_ssl_ocsp_ctx_t;
42:
43: struct 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:
85: static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
86: ngx_str_t *file);
87: static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl);
88: static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
89: ngx_str_t *responder);
90:
91: static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
92: void *data);
93: static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple);
94: static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx);
95:
96: static void ngx_ssl_stapling_cleanup(void *data);
97:
98: static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(void);
99: static void ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx);
100: static void ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx);
101: static void ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve);
102: static void ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx);
103: static void ngx_ssl_ocsp_write_handler(ngx_event_t *wev);
104: static void ngx_ssl_ocsp_read_handler(ngx_event_t *rev);
105: static void ngx_ssl_ocsp_dummy_handler(ngx_event_t *ev);
106:
107: static ngx_int_t ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx);
108: static ngx_int_t ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx);
109: static ngx_int_t ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx);
110: static ngx_int_t ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx);
111: static ngx_int_t ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx);
112: static ngx_int_t ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx);
113:
114: static u_char *ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len);
115:
116:
117: ngx_int_t
118: ngx_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:
180: done:
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:
189: static ngx_int_t
190: ngx_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:
248: failed:
249:
250: OCSP_RESPONSE_free(response);
251: BIO_free(bio);
252:
253: return NGX_ERROR;
254: }
255:
256:
257: static ngx_int_t
258: ngx_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:
344: static ngx_int_t
345: ngx_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:
433: ngx_int_t
434: ngx_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:
448: static int
449: ngx_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:
486: static void
487: ngx_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:
525: static void
526: ngx_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:
656: done:
657:
658: staple->loading = 0;
659: staple->valid = ngx_time() + 3600; /* ssl_stapling_valid */
660:
661: ngx_ssl_ocsp_done(ctx);
662: return;
663:
664: error:
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:
685: static void
686: ngx_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:
700: static ngx_ssl_ocsp_ctx_t *
701: ngx_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:
739: static void
740: ngx_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:
753: static void
754: ngx_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:
764: static void
765: ngx_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->type = NGX_RESOLVE_A;
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:
808: connect:
809:
810: ngx_ssl_ocsp_connect(ctx);
811: }
812:
813:
814: static void
815: ngx_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: ngx_uint_t i;
823: struct sockaddr_in *sin;
824:
825: ngx_log_debug0(NGX_LOG_ALERT, 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: in_addr_t addr;
839:
840: for (i = 0; i < resolve->naddrs; i++) {
841: addr = ntohl(resolve->addrs[i]);
842:
843: ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
844: "name was resolved to %ud.%ud.%ud.%ud",
845: (addr >> 24) & 0xff, (addr >> 16) & 0xff,
846: (addr >> 8) & 0xff, addr & 0xff);
847: }
848: }
849: #endif
850:
851: ctx->naddrs = resolve->naddrs;
852: ctx->addrs = ngx_pcalloc(ctx->pool, ctx->naddrs * sizeof(ngx_addr_t));
853:
854: if (ctx->addrs == NULL) {
855: goto failed;
856: }
857:
858: port = htons(ctx->port);
859:
860: for (i = 0; i < resolve->naddrs; i++) {
861:
862: sin = ngx_pcalloc(ctx->pool, sizeof(struct sockaddr_in));
863: if (sin == NULL) {
864: goto failed;
865: }
866:
867: sin->sin_family = AF_INET;
868: sin->sin_port = port;
869: sin->sin_addr.s_addr = resolve->addrs[i];
870:
871: ctx->addrs[i].sockaddr = (struct sockaddr *) sin;
872: ctx->addrs[i].socklen = sizeof(struct sockaddr_in);
873:
874: len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
875:
876: p = ngx_pnalloc(ctx->pool, len);
877: if (p == NULL) {
878: goto failed;
879: }
880:
881: len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
882:
883: ctx->addrs[i].name.len = len;
884: ctx->addrs[i].name.data = p;
885: }
886:
887: ngx_resolve_name_done(resolve);
888:
889: ngx_ssl_ocsp_connect(ctx);
890: return;
891:
892: failed:
893:
894: ngx_resolve_name_done(resolve);
895: ngx_ssl_ocsp_error(ctx);
896: }
897:
898:
899: static void
900: ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx)
901: {
902: ngx_int_t rc;
903:
904: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
905: "ssl ocsp connect");
906:
907: /* TODO: use all ip addresses */
908:
909: ctx->peer.sockaddr = ctx->addrs[0].sockaddr;
910: ctx->peer.socklen = ctx->addrs[0].socklen;
911: ctx->peer.name = &ctx->addrs[0].name;
912: ctx->peer.get = ngx_event_get_peer;
913: ctx->peer.log = ctx->log;
914: ctx->peer.log_error = NGX_ERROR_ERR;
915:
916: rc = ngx_event_connect_peer(&ctx->peer);
917:
918: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
919: "ssl ocsp connect peer done");
920:
921: if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
922: ngx_ssl_ocsp_error(ctx);
923: return;
924: }
925:
926: ctx->peer.connection->data = ctx;
927: ctx->peer.connection->pool = ctx->pool;
928:
929: ctx->peer.connection->read->handler = ngx_ssl_ocsp_read_handler;
930: ctx->peer.connection->write->handler = ngx_ssl_ocsp_write_handler;
931:
932: ctx->process = ngx_ssl_ocsp_process_status_line;
933:
934: ngx_add_timer(ctx->peer.connection->read, ctx->timeout);
935: ngx_add_timer(ctx->peer.connection->write, ctx->timeout);
936:
937: if (rc == NGX_OK) {
938: ngx_ssl_ocsp_write_handler(ctx->peer.connection->write);
939: return;
940: }
941: }
942:
943:
944: static void
945: ngx_ssl_ocsp_write_handler(ngx_event_t *wev)
946: {
947: ssize_t n, size;
948: ngx_connection_t *c;
949: ngx_ssl_ocsp_ctx_t *ctx;
950:
951: c = wev->data;
952: ctx = c->data;
953:
954: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, wev->log, 0,
955: "ssl ocsp write handler");
956:
957: if (wev->timedout) {
958: ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
959: "OCSP responder timed out");
960: ngx_ssl_ocsp_error(ctx);
961: return;
962: }
963:
964: size = ctx->request->last - ctx->request->pos;
965:
966: n = ngx_send(c, ctx->request->pos, size);
967:
968: if (n == NGX_ERROR) {
969: ngx_ssl_ocsp_error(ctx);
970: return;
971: }
972:
973: if (n > 0) {
974: ctx->request->pos += n;
975:
976: if (n == size) {
977: wev->handler = ngx_ssl_ocsp_dummy_handler;
978:
979: if (wev->timer_set) {
980: ngx_del_timer(wev);
981: }
982:
983: if (ngx_handle_write_event(wev, 0) != NGX_OK) {
984: ngx_ssl_ocsp_error(ctx);
985: }
986:
987: return;
988: }
989: }
990:
991: if (!wev->timer_set) {
992: ngx_add_timer(wev, ctx->timeout);
993: }
994: }
995:
996:
997: static void
998: ngx_ssl_ocsp_read_handler(ngx_event_t *rev)
999: {
1000: ssize_t n, size;
1001: ngx_int_t rc;
1002: ngx_ssl_ocsp_ctx_t *ctx;
1003: ngx_connection_t *c;
1004:
1005: c = rev->data;
1006: ctx = c->data;
1007:
1008: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, rev->log, 0,
1009: "ssl ocsp read handler");
1010:
1011: if (rev->timedout) {
1012: ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
1013: "OCSP responder timed out");
1014: ngx_ssl_ocsp_error(ctx);
1015: return;
1016: }
1017:
1018: if (ctx->response == NULL) {
1019: ctx->response = ngx_create_temp_buf(ctx->pool, 16384);
1020: if (ctx->response == NULL) {
1021: ngx_ssl_ocsp_error(ctx);
1022: return;
1023: }
1024: }
1025:
1026: for ( ;; ) {
1027:
1028: size = ctx->response->end - ctx->response->last;
1029:
1030: n = ngx_recv(c, ctx->response->last, size);
1031:
1032: if (n > 0) {
1033: ctx->response->last += n;
1034:
1035: rc = ctx->process(ctx);
1036:
1037: if (rc == NGX_ERROR) {
1038: ngx_ssl_ocsp_error(ctx);
1039: return;
1040: }
1041:
1042: continue;
1043: }
1044:
1045: if (n == NGX_AGAIN) {
1046:
1047: if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1048: ngx_ssl_ocsp_error(ctx);
1049: }
1050:
1051: return;
1052: }
1053:
1054: break;
1055: }
1056:
1057: ctx->done = 1;
1058:
1059: rc = ctx->process(ctx);
1060:
1061: if (rc == NGX_DONE) {
1062: /* ctx->handler() was called */
1063: return;
1064: }
1065:
1066: ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
1067: "OCSP responder prematurely closed connection");
1068:
1069: ngx_ssl_ocsp_error(ctx);
1070: }
1071:
1072:
1073: static void
1074: ngx_ssl_ocsp_dummy_handler(ngx_event_t *ev)
1075: {
1076: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
1077: "ssl ocsp dummy handler");
1078: }
1079:
1080:
1081: static ngx_int_t
1082: ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx)
1083: {
1084: int len;
1085: u_char *p;
1086: uintptr_t escape;
1087: ngx_str_t binary, base64;
1088: ngx_buf_t *b;
1089: OCSP_CERTID *id;
1090: OCSP_REQUEST *ocsp;
1091:
1092: ocsp = OCSP_REQUEST_new();
1093: if (ocsp == NULL) {
1094: ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
1095: "OCSP_REQUEST_new() failed");
1096: return NGX_ERROR;
1097: }
1098:
1099: id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
1100: if (id == NULL) {
1101: ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
1102: "OCSP_cert_to_id() failed");
1103: goto failed;
1104: }
1105:
1106: if (OCSP_request_add0_id(ocsp, id) == NULL) {
1107: ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
1108: "OCSP_request_add0_id() failed");
1109: goto failed;
1110: }
1111:
1112: len = i2d_OCSP_REQUEST(ocsp, NULL);
1113: if (len <= 0) {
1114: ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
1115: "i2d_OCSP_REQUEST() failed");
1116: goto failed;
1117: }
1118:
1119: binary.len = len;
1120: binary.data = ngx_palloc(ctx->pool, len);
1121: if (binary.data == NULL) {
1122: goto failed;
1123: }
1124:
1125: p = binary.data;
1126: len = i2d_OCSP_REQUEST(ocsp, &p);
1127: if (len <= 0) {
1128: ngx_ssl_error(NGX_LOG_EMERG, ctx->log, 0,
1129: "i2d_OCSP_REQUEST() failed");
1130: goto failed;
1131: }
1132:
1133: base64.len = ngx_base64_encoded_length(binary.len);
1134: base64.data = ngx_palloc(ctx->pool, base64.len);
1135: if (base64.data == NULL) {
1136: goto failed;
1137: }
1138:
1139: ngx_encode_base64(&base64, &binary);
1140:
1141: escape = ngx_escape_uri(NULL, base64.data, base64.len,
1142: NGX_ESCAPE_URI_COMPONENT);
1143:
1144: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1145: "ssl ocsp request length %z, escape %d",
1146: base64.len, escape);
1147:
1148: len = sizeof("GET ") - 1 + ctx->uri.len + sizeof("/") - 1
1149: + base64.len + 2 * escape + sizeof(" HTTP/1.0" CRLF) - 1
1150: + sizeof("Host: ") - 1 + ctx->host.len + sizeof(CRLF) - 1
1151: + sizeof(CRLF) - 1;
1152:
1153: b = ngx_create_temp_buf(ctx->pool, len);
1154: if (b == NULL) {
1155: goto failed;
1156: }
1157:
1158: p = b->last;
1159:
1160: p = ngx_cpymem(p, "GET ", sizeof("GET ") - 1);
1161: p = ngx_cpymem(p, ctx->uri.data, ctx->uri.len);
1162:
1163: if (ctx->uri.data[ctx->uri.len - 1] != '/') {
1164: *p++ = '/';
1165: }
1166:
1167: if (escape == 0) {
1168: p = ngx_cpymem(p, base64.data, base64.len);
1169:
1170: } else {
1171: p = (u_char *) ngx_escape_uri(p, base64.data, base64.len,
1172: NGX_ESCAPE_URI_COMPONENT);
1173: }
1174:
1175: p = ngx_cpymem(p, " HTTP/1.0" CRLF, sizeof(" HTTP/1.0" CRLF) - 1);
1176: p = ngx_cpymem(p, "Host: ", sizeof("Host: ") - 1);
1177: p = ngx_cpymem(p, ctx->host.data, ctx->host.len);
1178: *p++ = CR; *p++ = LF;
1179:
1180: /* add "\r\n" at the header end */
1181: *p++ = CR; *p++ = LF;
1182:
1183: b->last = p;
1184: ctx->request = b;
1185:
1186: return NGX_OK;
1187:
1188: failed:
1189:
1190: OCSP_REQUEST_free(ocsp);
1191:
1192: return NGX_ERROR;
1193: }
1194:
1195:
1196: static ngx_int_t
1197: ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx)
1198: {
1199: ngx_int_t rc;
1200:
1201: rc = ngx_ssl_ocsp_parse_status_line(ctx);
1202:
1203: if (rc == NGX_OK) {
1204: #if 0
1205: ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1206: "ssl ocsp status line \"%*s\"",
1207: ctx->response->pos - ctx->response->start,
1208: ctx->response->start);
1209: #endif
1210:
1211: ctx->process = ngx_ssl_ocsp_process_headers;
1212: return ctx->process(ctx);
1213: }
1214:
1215: if (rc == NGX_AGAIN) {
1216: return NGX_AGAIN;
1217: }
1218:
1219: /* rc == NGX_ERROR */
1220:
1221: ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
1222: "OCSP responder sent invalid response");
1223:
1224: return NGX_ERROR;
1225: }
1226:
1227:
1228: static ngx_int_t
1229: ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx)
1230: {
1231: u_char ch;
1232: u_char *p;
1233: ngx_buf_t *b;
1234: enum {
1235: sw_start = 0,
1236: sw_H,
1237: sw_HT,
1238: sw_HTT,
1239: sw_HTTP,
1240: sw_first_major_digit,
1241: sw_major_digit,
1242: sw_first_minor_digit,
1243: sw_minor_digit,
1244: sw_status,
1245: sw_space_after_status,
1246: sw_status_text,
1247: sw_almost_done
1248: } state;
1249:
1250: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1251: "ssl ocsp process status line");
1252:
1253: state = ctx->state;
1254: b = ctx->response;
1255:
1256: for (p = b->pos; p < b->last; p++) {
1257: ch = *p;
1258:
1259: switch (state) {
1260:
1261: /* "HTTP/" */
1262: case sw_start:
1263: switch (ch) {
1264: case 'H':
1265: state = sw_H;
1266: break;
1267: default:
1268: return NGX_ERROR;
1269: }
1270: break;
1271:
1272: case sw_H:
1273: switch (ch) {
1274: case 'T':
1275: state = sw_HT;
1276: break;
1277: default:
1278: return NGX_ERROR;
1279: }
1280: break;
1281:
1282: case sw_HT:
1283: switch (ch) {
1284: case 'T':
1285: state = sw_HTT;
1286: break;
1287: default:
1288: return NGX_ERROR;
1289: }
1290: break;
1291:
1292: case sw_HTT:
1293: switch (ch) {
1294: case 'P':
1295: state = sw_HTTP;
1296: break;
1297: default:
1298: return NGX_ERROR;
1299: }
1300: break;
1301:
1302: case sw_HTTP:
1303: switch (ch) {
1304: case '/':
1305: state = sw_first_major_digit;
1306: break;
1307: default:
1308: return NGX_ERROR;
1309: }
1310: break;
1311:
1312: /* the first digit of major HTTP version */
1313: case sw_first_major_digit:
1314: if (ch < '1' || ch > '9') {
1315: return NGX_ERROR;
1316: }
1317:
1318: state = sw_major_digit;
1319: break;
1320:
1321: /* the major HTTP version or dot */
1322: case sw_major_digit:
1323: if (ch == '.') {
1324: state = sw_first_minor_digit;
1325: break;
1326: }
1327:
1328: if (ch < '0' || ch > '9') {
1329: return NGX_ERROR;
1330: }
1331:
1332: break;
1333:
1334: /* the first digit of minor HTTP version */
1335: case sw_first_minor_digit:
1336: if (ch < '0' || ch > '9') {
1337: return NGX_ERROR;
1338: }
1339:
1340: state = sw_minor_digit;
1341: break;
1342:
1343: /* the minor HTTP version or the end of the request line */
1344: case sw_minor_digit:
1345: if (ch == ' ') {
1346: state = sw_status;
1347: break;
1348: }
1349:
1350: if (ch < '0' || ch > '9') {
1351: return NGX_ERROR;
1352: }
1353:
1354: break;
1355:
1356: /* HTTP status code */
1357: case sw_status:
1358: if (ch == ' ') {
1359: break;
1360: }
1361:
1362: if (ch < '0' || ch > '9') {
1363: return NGX_ERROR;
1364: }
1365:
1366: ctx->code = ctx->code * 10 + ch - '0';
1367:
1368: if (++ctx->count == 3) {
1369: state = sw_space_after_status;
1370: }
1371:
1372: break;
1373:
1374: /* space or end of line */
1375: case sw_space_after_status:
1376: switch (ch) {
1377: case ' ':
1378: state = sw_status_text;
1379: break;
1380: case '.': /* IIS may send 403.1, 403.2, etc */
1381: state = sw_status_text;
1382: break;
1383: case CR:
1384: state = sw_almost_done;
1385: break;
1386: case LF:
1387: goto done;
1388: default:
1389: return NGX_ERROR;
1390: }
1391: break;
1392:
1393: /* any text until end of line */
1394: case sw_status_text:
1395: switch (ch) {
1396: case CR:
1397: state = sw_almost_done;
1398: break;
1399: case LF:
1400: goto done;
1401: }
1402: break;
1403:
1404: /* end of status line */
1405: case sw_almost_done:
1406: switch (ch) {
1407: case LF:
1408: goto done;
1409: default:
1410: return NGX_ERROR;
1411: }
1412: }
1413: }
1414:
1415: b->pos = p;
1416: ctx->state = state;
1417:
1418: return NGX_AGAIN;
1419:
1420: done:
1421:
1422: b->pos = p + 1;
1423: ctx->state = sw_start;
1424:
1425: return NGX_OK;
1426: }
1427:
1428:
1429: static ngx_int_t
1430: ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx)
1431: {
1432: size_t len;
1433: ngx_int_t rc;
1434:
1435: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1436: "ssl ocsp process headers");
1437:
1438: for ( ;; ) {
1439: rc = ngx_ssl_ocsp_parse_header_line(ctx);
1440:
1441: if (rc == NGX_OK) {
1442:
1443: ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1444: "ssl ocsp header \"%*s: %*s\"",
1445: ctx->header_name_end - ctx->header_name_start,
1446: ctx->header_name_start,
1447: ctx->header_end - ctx->header_start,
1448: ctx->header_start);
1449:
1450: len = ctx->header_name_end - ctx->header_name_start;
1451:
1452: if (len == sizeof("Content-Type") - 1
1453: && ngx_strncasecmp(ctx->header_name_start,
1454: (u_char *) "Content-Type",
1455: sizeof("Content-Type") - 1)
1456: == 0)
1457: {
1458: len = ctx->header_end - ctx->header_start;
1459:
1460: if (len != sizeof("application/ocsp-response") - 1
1461: || ngx_strncasecmp(ctx->header_start,
1462: (u_char *) "application/ocsp-response",
1463: sizeof("application/ocsp-response") - 1)
1464: != 0)
1465: {
1466: ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
1467: "OCSP responder sent invalid "
1468: "\"Content-Type\" header: \"%*s\"",
1469: ctx->header_end - ctx->header_start,
1470: ctx->header_start);
1471: return NGX_ERROR;
1472: }
1473:
1474: continue;
1475: }
1476:
1477: /* TODO: honor Content-Length */
1478:
1479: continue;
1480: }
1481:
1482: if (rc == NGX_DONE) {
1483: break;
1484: }
1485:
1486: if (rc == NGX_AGAIN) {
1487: return NGX_AGAIN;
1488: }
1489:
1490: /* rc == NGX_ERROR */
1491:
1492: ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
1493: "OCSP responder sent invalid response");
1494:
1495: return NGX_ERROR;
1496: }
1497:
1498: ctx->process = ngx_ssl_ocsp_process_body;
1499: return ctx->process(ctx);
1500: }
1501:
1502: static ngx_int_t
1503: ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx)
1504: {
1505: u_char c, ch, *p;
1506: enum {
1507: sw_start = 0,
1508: sw_name,
1509: sw_space_before_value,
1510: sw_value,
1511: sw_space_after_value,
1512: sw_almost_done,
1513: sw_header_almost_done
1514: } state;
1515:
1516: state = ctx->state;
1517:
1518: for (p = ctx->response->pos; p < ctx->response->last; p++) {
1519: ch = *p;
1520:
1521: #if 0
1522: ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1523: "s:%d in:'%02Xd:%c'", state, ch, ch);
1524: #endif
1525:
1526: switch (state) {
1527:
1528: /* first char */
1529: case sw_start:
1530:
1531: switch (ch) {
1532: case CR:
1533: ctx->header_end = p;
1534: state = sw_header_almost_done;
1535: break;
1536: case LF:
1537: ctx->header_end = p;
1538: goto header_done;
1539: default:
1540: state = sw_name;
1541: ctx->header_name_start = p;
1542:
1543: c = (u_char) (ch | 0x20);
1544: if (c >= 'a' && c <= 'z') {
1545: break;
1546: }
1547:
1548: if (ch >= '0' && ch <= '9') {
1549: break;
1550: }
1551:
1552: return NGX_ERROR;
1553: }
1554: break;
1555:
1556: /* header name */
1557: case sw_name:
1558: c = (u_char) (ch | 0x20);
1559: if (c >= 'a' && c <= 'z') {
1560: break;
1561: }
1562:
1563: if (ch == ':') {
1564: ctx->header_name_end = p;
1565: state = sw_space_before_value;
1566: break;
1567: }
1568:
1569: if (ch == '-') {
1570: break;
1571: }
1572:
1573: if (ch >= '0' && ch <= '9') {
1574: break;
1575: }
1576:
1577: if (ch == CR) {
1578: ctx->header_name_end = p;
1579: ctx->header_start = p;
1580: ctx->header_end = p;
1581: state = sw_almost_done;
1582: break;
1583: }
1584:
1585: if (ch == LF) {
1586: ctx->header_name_end = p;
1587: ctx->header_start = p;
1588: ctx->header_end = p;
1589: goto done;
1590: }
1591:
1592: return NGX_ERROR;
1593:
1594: /* space* before header value */
1595: case sw_space_before_value:
1596: switch (ch) {
1597: case ' ':
1598: break;
1599: case CR:
1600: ctx->header_start = p;
1601: ctx->header_end = p;
1602: state = sw_almost_done;
1603: break;
1604: case LF:
1605: ctx->header_start = p;
1606: ctx->header_end = p;
1607: goto done;
1608: default:
1609: ctx->header_start = p;
1610: state = sw_value;
1611: break;
1612: }
1613: break;
1614:
1615: /* header value */
1616: case sw_value:
1617: switch (ch) {
1618: case ' ':
1619: ctx->header_end = p;
1620: state = sw_space_after_value;
1621: break;
1622: case CR:
1623: ctx->header_end = p;
1624: state = sw_almost_done;
1625: break;
1626: case LF:
1627: ctx->header_end = p;
1628: goto done;
1629: }
1630: break;
1631:
1632: /* space* before end of header line */
1633: case sw_space_after_value:
1634: switch (ch) {
1635: case ' ':
1636: break;
1637: case CR:
1638: state = sw_almost_done;
1639: break;
1640: case LF:
1641: goto done;
1642: default:
1643: state = sw_value;
1644: break;
1645: }
1646: break;
1647:
1648: /* end of header line */
1649: case sw_almost_done:
1650: switch (ch) {
1651: case LF:
1652: goto done;
1653: default:
1654: return NGX_ERROR;
1655: }
1656:
1657: /* end of header */
1658: case sw_header_almost_done:
1659: switch (ch) {
1660: case LF:
1661: goto header_done;
1662: default:
1663: return NGX_ERROR;
1664: }
1665: }
1666: }
1667:
1668: ctx->response->pos = p;
1669: ctx->state = state;
1670:
1671: return NGX_AGAIN;
1672:
1673: done:
1674:
1675: ctx->response->pos = p + 1;
1676: ctx->state = sw_start;
1677:
1678: return NGX_OK;
1679:
1680: header_done:
1681:
1682: ctx->response->pos = p + 1;
1683: ctx->state = sw_start;
1684:
1685: return NGX_DONE;
1686: }
1687:
1688:
1689: static ngx_int_t
1690: ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx)
1691: {
1692: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1693: "ssl ocsp process body");
1694:
1695: if (ctx->done) {
1696: ctx->handler(ctx);
1697: return NGX_DONE;
1698: }
1699:
1700: return NGX_AGAIN;
1701: }
1702:
1703:
1704: static u_char *
1705: ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len)
1706: {
1707: u_char *p;
1708: ngx_ssl_ocsp_ctx_t *ctx;
1709:
1710: p = buf;
1711:
1712: if (log->action) {
1713: p = ngx_snprintf(buf, len, " while %s", log->action);
1714: len -= p - buf;
1715: }
1716:
1717: ctx = log->data;
1718:
1719: if (ctx) {
1720: p = ngx_snprintf(p, len, ", responder: %V", &ctx->host);
1721: }
1722:
1723: return p;
1724: }
1725:
1726:
1727: #else
1728:
1729:
1730: ngx_int_t
1731: ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
1732: ngx_str_t *responder, ngx_uint_t verify)
1733: {
1734: ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
1735: "\"ssl_stapling\" ignored, not supported");
1736:
1737: return NGX_OK;
1738: }
1739:
1740: ngx_int_t
1741: ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
1742: ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
1743: {
1744: return NGX_OK;
1745: }
1746:
1747:
1748: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>