source: nginx/src/event/ngx_event_openssl_stapling.c

Last change on this file was 7509:b99cbafd51da, checked in by Sergey Kandaurov <pluknet@…>, 4 years ago

SSL: removed OpenSSL 0.9.7 compatibility.

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