nginxtra 1.2.8.8 → 1.4.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/bin/nginxtra +1 -1
  2. data/bin/nginxtra_rails +1 -1
  3. data/lib/nginxtra/version.rb +1 -1
  4. data/vendor/nginx/CHANGES +202 -63
  5. data/vendor/nginx/CHANGES.ru +208 -66
  6. data/vendor/nginx/auto/lib/md5/conf +3 -3
  7. data/vendor/nginx/auto/lib/perl/conf +3 -1
  8. data/vendor/nginx/auto/lib/perl/make +21 -16
  9. data/vendor/nginx/auto/lib/sha1/conf +1 -1
  10. data/vendor/nginx/auto/modules +25 -4
  11. data/vendor/nginx/auto/options +7 -1
  12. data/vendor/nginx/auto/sources +15 -1
  13. data/vendor/nginx/auto/unix +14 -0
  14. data/vendor/nginx/src/core/nginx.h +2 -2
  15. data/vendor/nginx/src/core/ngx_array.c +1 -7
  16. data/vendor/nginx/src/core/ngx_array.h +2 -2
  17. data/vendor/nginx/src/core/ngx_connection.c +13 -7
  18. data/vendor/nginx/src/core/ngx_connection.h +1 -2
  19. data/vendor/nginx/src/core/ngx_core.h +1 -2
  20. data/vendor/nginx/src/core/ngx_crypt.c +37 -0
  21. data/vendor/nginx/src/core/ngx_cycle.h +1 -1
  22. data/vendor/nginx/src/core/ngx_inet.c +219 -48
  23. data/vendor/nginx/src/core/ngx_inet.h +1 -1
  24. data/vendor/nginx/src/event/modules/ngx_devpoll_module.c +7 -1
  25. data/vendor/nginx/src/event/modules/ngx_eventport_module.c +1 -1
  26. data/vendor/nginx/src/event/ngx_event.c +5 -1
  27. data/vendor/nginx/src/event/ngx_event.h +1 -0
  28. data/vendor/nginx/src/event/ngx_event_connect.c +1 -1
  29. data/vendor/nginx/src/event/ngx_event_openssl.c +135 -9
  30. data/vendor/nginx/src/event/ngx_event_openssl.h +9 -0
  31. data/vendor/nginx/src/event/ngx_event_openssl_stapling.c +1749 -0
  32. data/vendor/nginx/src/http/modules/ngx_http_addition_filter_module.c +1 -0
  33. data/vendor/nginx/src/http/modules/ngx_http_chunked_filter_module.c +1 -0
  34. data/vendor/nginx/src/http/modules/ngx_http_fastcgi_module.c +5 -0
  35. data/vendor/nginx/src/http/modules/ngx_http_flv_module.c +4 -0
  36. data/vendor/nginx/src/http/modules/ngx_http_geo_module.c +7 -8
  37. data/vendor/nginx/src/http/modules/ngx_http_geoip_module.c +10 -12
  38. data/vendor/nginx/src/http/modules/ngx_http_gunzip_filter_module.c +677 -0
  39. data/vendor/nginx/src/http/modules/ngx_http_gzip_filter_module.c +3 -0
  40. data/vendor/nginx/src/http/modules/ngx_http_gzip_static_module.c +36 -10
  41. data/vendor/nginx/src/http/modules/ngx_http_headers_filter_module.c +31 -13
  42. data/vendor/nginx/src/http/modules/ngx_http_image_filter_module.c +13 -0
  43. data/vendor/nginx/src/http/modules/ngx_http_limit_conn_module.c +18 -2
  44. data/vendor/nginx/src/http/modules/ngx_http_limit_req_module.c +19 -2
  45. data/vendor/nginx/src/http/modules/ngx_http_map_module.c +1 -1
  46. data/vendor/nginx/src/http/modules/ngx_http_memcached_module.c +60 -8
  47. data/vendor/nginx/src/http/modules/ngx_http_mp4_module.c +4 -8
  48. data/vendor/nginx/src/http/modules/ngx_http_not_modified_filter_module.c +126 -29
  49. data/vendor/nginx/src/http/modules/ngx_http_proxy_module.c +59 -301
  50. data/vendor/nginx/src/http/modules/ngx_http_range_filter_module.c +34 -6
  51. data/vendor/nginx/src/http/modules/ngx_http_realip_module.c +13 -12
  52. data/vendor/nginx/src/http/modules/ngx_http_scgi_module.c +30 -11
  53. data/vendor/nginx/src/http/modules/ngx_http_ssi_filter_module.c +1 -0
  54. data/vendor/nginx/src/http/modules/ngx_http_ssl_module.c +155 -4
  55. data/vendor/nginx/src/http/modules/ngx_http_ssl_module.h +6 -0
  56. data/vendor/nginx/src/http/modules/ngx_http_static_module.c +4 -0
  57. data/vendor/nginx/src/http/modules/ngx_http_stub_status_module.c +90 -3
  58. data/vendor/nginx/src/http/modules/ngx_http_sub_filter_module.c +1 -0
  59. data/vendor/nginx/src/http/modules/ngx_http_upstream_ip_hash_module.c +5 -0
  60. data/vendor/nginx/src/http/modules/ngx_http_upstream_least_conn_module.c +5 -0
  61. data/vendor/nginx/src/http/modules/ngx_http_uwsgi_module.c +14 -1
  62. data/vendor/nginx/src/http/modules/ngx_http_xslt_filter_module.c +1 -0
  63. data/vendor/nginx/src/http/modules/perl/Makefile.PL +4 -2
  64. data/vendor/nginx/src/http/modules/perl/nginx.pm +1 -1
  65. data/vendor/nginx/src/http/modules/perl/nginx.xs +36 -3
  66. data/vendor/nginx/src/http/ngx_http.c +24 -1
  67. data/vendor/nginx/src/http/ngx_http.h +26 -2
  68. data/vendor/nginx/src/http/ngx_http_core_module.c +136 -10
  69. data/vendor/nginx/src/http/ngx_http_core_module.h +37 -13
  70. data/vendor/nginx/src/http/ngx_http_header_filter_module.c +9 -2
  71. data/vendor/nginx/src/http/ngx_http_parse.c +404 -0
  72. data/vendor/nginx/src/http/ngx_http_request.c +840 -517
  73. data/vendor/nginx/src/http/ngx_http_request.h +37 -25
  74. data/vendor/nginx/src/http/ngx_http_request_body.c +585 -156
  75. data/vendor/nginx/src/http/ngx_http_spdy.c +2882 -0
  76. data/vendor/nginx/src/http/ngx_http_spdy.h +235 -0
  77. data/vendor/nginx/src/http/ngx_http_spdy_filter_module.c +999 -0
  78. data/vendor/nginx/src/http/ngx_http_spdy_module.c +351 -0
  79. data/vendor/nginx/src/http/ngx_http_spdy_module.h +36 -0
  80. data/vendor/nginx/src/http/ngx_http_special_response.c +3 -1
  81. data/vendor/nginx/src/http/ngx_http_upstream.c +415 -26
  82. data/vendor/nginx/src/http/ngx_http_upstream.h +11 -1
  83. data/vendor/nginx/src/http/ngx_http_upstream_round_robin.c +2 -45
  84. data/vendor/nginx/src/http/ngx_http_upstream_round_robin.h +0 -2
  85. data/vendor/nginx/src/http/ngx_http_variables.c +72 -12
  86. data/vendor/nginx/src/mail/ngx_mail.h +2 -2
  87. data/vendor/nginx/src/mail/ngx_mail_auth_http_module.c +35 -25
  88. data/vendor/nginx/src/mail/ngx_mail_core_module.c +5 -1
  89. metadata +9 -2
@@ -17,6 +17,7 @@
17
17
  #include <openssl/conf.h>
18
18
  #include <openssl/engine.h>
19
19
  #include <openssl/evp.h>
20
+ #include <openssl/ocsp.h>
20
21
 
21
22
  #define NGX_SSL_NAME "OpenSSL"
22
23
 
@@ -101,7 +102,13 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
101
102
  ngx_str_t *cert, ngx_str_t *key);
102
103
  ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
103
104
  ngx_str_t *cert, ngx_int_t depth);
105
+ ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
106
+ ngx_str_t *cert, ngx_int_t depth);
104
107
  ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl);
108
+ ngx_int_t ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl,
109
+ ngx_str_t *file, ngx_str_t *responder, ngx_uint_t verify);
110
+ ngx_int_t ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
111
+ ngx_resolver_t *resolver, ngx_msec_t resolver_timeout);
105
112
  RSA *ngx_ssl_rsa512_key_callback(SSL *ssl, int is_export, int key_length);
106
113
  ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file);
107
114
  ngx_int_t ngx_ssl_ecdh_curve(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *name);
@@ -164,6 +171,8 @@ void ngx_ssl_cleanup_ctx(void *data);
164
171
  extern int ngx_ssl_connection_index;
165
172
  extern int ngx_ssl_server_conf_index;
166
173
  extern int ngx_ssl_session_cache_index;
174
+ extern int ngx_ssl_certificate_index;
175
+ extern int ngx_ssl_stapling_index;
167
176
 
168
177
 
169
178
  #endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */
@@ -0,0 +1,1749 @@
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
+ n, OCSP_response_status_str(n));
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
+ n, 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
+
657
+ done:
658
+
659
+ staple->loading = 0;
660
+ staple->valid = ngx_time() + 3600; /* ssl_stapling_valid */
661
+
662
+ ngx_ssl_ocsp_done(ctx);
663
+ return;
664
+
665
+ error:
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
+
686
+ static void
687
+ ngx_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
+
701
+ static ngx_ssl_ocsp_ctx_t *
702
+ ngx_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
+
740
+ static void
741
+ ngx_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
+
754
+ static void
755
+ ngx_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
+
765
+ static void
766
+ ngx_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->type = NGX_RESOLVE_A;
797
+ resolve->handler = ngx_ssl_ocsp_resolve_handler;
798
+ resolve->data = ctx;
799
+ resolve->timeout = ctx->resolver_timeout;
800
+
801
+ if (ngx_resolve_name(resolve) != NGX_OK) {
802
+ ngx_ssl_ocsp_error(ctx);
803
+ return;
804
+ }
805
+
806
+ return;
807
+ }
808
+
809
+ connect:
810
+
811
+ ngx_ssl_ocsp_connect(ctx);
812
+ }
813
+
814
+
815
+ static void
816
+ ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve)
817
+ {
818
+ ngx_ssl_ocsp_ctx_t *ctx = resolve->data;
819
+
820
+ u_char *p;
821
+ size_t len;
822
+ in_port_t port;
823
+ ngx_uint_t i;
824
+ struct sockaddr_in *sin;
825
+
826
+ ngx_log_debug0(NGX_LOG_ALERT, 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
+ in_addr_t addr;
840
+
841
+ for (i = 0; i < resolve->naddrs; i++) {
842
+ addr = ntohl(resolve->addrs[i]);
843
+
844
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
845
+ "name was resolved to %ud.%ud.%ud.%ud",
846
+ (addr >> 24) & 0xff, (addr >> 16) & 0xff,
847
+ (addr >> 8) & 0xff, addr & 0xff);
848
+ }
849
+ }
850
+ #endif
851
+
852
+ ctx->naddrs = resolve->naddrs;
853
+ ctx->addrs = ngx_pcalloc(ctx->pool, ctx->naddrs * sizeof(ngx_addr_t));
854
+
855
+ if (ctx->addrs == NULL) {
856
+ goto failed;
857
+ }
858
+
859
+ port = htons(ctx->port);
860
+
861
+ for (i = 0; i < resolve->naddrs; i++) {
862
+
863
+ sin = ngx_pcalloc(ctx->pool, sizeof(struct sockaddr_in));
864
+ if (sin == NULL) {
865
+ goto failed;
866
+ }
867
+
868
+ sin->sin_family = AF_INET;
869
+ sin->sin_port = port;
870
+ sin->sin_addr.s_addr = resolve->addrs[i];
871
+
872
+ ctx->addrs[i].sockaddr = (struct sockaddr *) sin;
873
+ ctx->addrs[i].socklen = sizeof(struct sockaddr_in);
874
+
875
+ len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1;
876
+
877
+ p = ngx_pnalloc(ctx->pool, len);
878
+ if (p == NULL) {
879
+ goto failed;
880
+ }
881
+
882
+ len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1);
883
+
884
+ ctx->addrs[i].name.len = len;
885
+ ctx->addrs[i].name.data = p;
886
+ }
887
+
888
+ ngx_resolve_name_done(resolve);
889
+
890
+ ngx_ssl_ocsp_connect(ctx);
891
+ return;
892
+
893
+ failed:
894
+
895
+ ngx_resolve_name_done(resolve);
896
+ ngx_ssl_ocsp_error(ctx);
897
+ }
898
+
899
+
900
+ static void
901
+ ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx)
902
+ {
903
+ ngx_int_t rc;
904
+
905
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
906
+ "ssl ocsp connect");
907
+
908
+ /* TODO: use all ip addresses */
909
+
910
+ ctx->peer.sockaddr = ctx->addrs[0].sockaddr;
911
+ ctx->peer.socklen = ctx->addrs[0].socklen;
912
+ ctx->peer.name = &ctx->addrs[0].name;
913
+ ctx->peer.get = ngx_event_get_peer;
914
+ ctx->peer.log = ctx->log;
915
+ ctx->peer.log_error = NGX_ERROR_ERR;
916
+
917
+ rc = ngx_event_connect_peer(&ctx->peer);
918
+
919
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
920
+ "ssl ocsp connect peer done");
921
+
922
+ if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
923
+ ngx_ssl_ocsp_error(ctx);
924
+ return;
925
+ }
926
+
927
+ ctx->peer.connection->data = ctx;
928
+ ctx->peer.connection->pool = ctx->pool;
929
+
930
+ ctx->peer.connection->read->handler = ngx_ssl_ocsp_read_handler;
931
+ ctx->peer.connection->write->handler = ngx_ssl_ocsp_write_handler;
932
+
933
+ ctx->process = ngx_ssl_ocsp_process_status_line;
934
+
935
+ ngx_add_timer(ctx->peer.connection->read, ctx->timeout);
936
+ ngx_add_timer(ctx->peer.connection->write, ctx->timeout);
937
+
938
+ if (rc == NGX_OK) {
939
+ ngx_ssl_ocsp_write_handler(ctx->peer.connection->write);
940
+ return;
941
+ }
942
+ }
943
+
944
+
945
+ static void
946
+ ngx_ssl_ocsp_write_handler(ngx_event_t *wev)
947
+ {
948
+ ssize_t n, size;
949
+ ngx_connection_t *c;
950
+ ngx_ssl_ocsp_ctx_t *ctx;
951
+
952
+ c = wev->data;
953
+ ctx = c->data;
954
+
955
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, wev->log, 0,
956
+ "ssl ocsp write handler");
957
+
958
+ if (wev->timedout) {
959
+ ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
960
+ "OCSP responder timed out");
961
+ ngx_ssl_ocsp_error(ctx);
962
+ return;
963
+ }
964
+
965
+ size = ctx->request->last - ctx->request->pos;
966
+
967
+ n = ngx_send(c, ctx->request->pos, size);
968
+
969
+ if (n == NGX_ERROR) {
970
+ ngx_ssl_ocsp_error(ctx);
971
+ return;
972
+ }
973
+
974
+ if (n > 0) {
975
+ ctx->request->pos += n;
976
+
977
+ if (n == size) {
978
+ wev->handler = ngx_ssl_ocsp_dummy_handler;
979
+
980
+ if (wev->timer_set) {
981
+ ngx_del_timer(wev);
982
+ }
983
+
984
+ if (ngx_handle_write_event(wev, 0) != NGX_OK) {
985
+ ngx_ssl_ocsp_error(ctx);
986
+ }
987
+
988
+ return;
989
+ }
990
+ }
991
+
992
+ if (!wev->timer_set) {
993
+ ngx_add_timer(wev, ctx->timeout);
994
+ }
995
+ }
996
+
997
+
998
+ static void
999
+ ngx_ssl_ocsp_read_handler(ngx_event_t *rev)
1000
+ {
1001
+ ssize_t n, size;
1002
+ ngx_int_t rc;
1003
+ ngx_ssl_ocsp_ctx_t *ctx;
1004
+ ngx_connection_t *c;
1005
+
1006
+ c = rev->data;
1007
+ ctx = c->data;
1008
+
1009
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, rev->log, 0,
1010
+ "ssl ocsp read handler");
1011
+
1012
+ if (rev->timedout) {
1013
+ ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
1014
+ "OCSP responder timed out");
1015
+ ngx_ssl_ocsp_error(ctx);
1016
+ return;
1017
+ }
1018
+
1019
+ if (ctx->response == NULL) {
1020
+ ctx->response = ngx_create_temp_buf(ctx->pool, 16384);
1021
+ if (ctx->response == NULL) {
1022
+ ngx_ssl_ocsp_error(ctx);
1023
+ return;
1024
+ }
1025
+ }
1026
+
1027
+ for ( ;; ) {
1028
+
1029
+ size = ctx->response->end - ctx->response->last;
1030
+
1031
+ n = ngx_recv(c, ctx->response->last, size);
1032
+
1033
+ if (n > 0) {
1034
+ ctx->response->last += n;
1035
+
1036
+ rc = ctx->process(ctx);
1037
+
1038
+ if (rc == NGX_ERROR) {
1039
+ ngx_ssl_ocsp_error(ctx);
1040
+ return;
1041
+ }
1042
+
1043
+ continue;
1044
+ }
1045
+
1046
+ if (n == NGX_AGAIN) {
1047
+
1048
+ if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1049
+ ngx_ssl_ocsp_error(ctx);
1050
+ }
1051
+
1052
+ return;
1053
+ }
1054
+
1055
+ break;
1056
+ }
1057
+
1058
+ ctx->done = 1;
1059
+
1060
+ rc = ctx->process(ctx);
1061
+
1062
+ if (rc == NGX_DONE) {
1063
+ /* ctx->handler() was called */
1064
+ return;
1065
+ }
1066
+
1067
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
1068
+ "OCSP responder prematurely closed connection");
1069
+
1070
+ ngx_ssl_ocsp_error(ctx);
1071
+ }
1072
+
1073
+
1074
+ static void
1075
+ ngx_ssl_ocsp_dummy_handler(ngx_event_t *ev)
1076
+ {
1077
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
1078
+ "ssl ocsp dummy handler");
1079
+ }
1080
+
1081
+
1082
+ static ngx_int_t
1083
+ ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx)
1084
+ {
1085
+ int len;
1086
+ u_char *p;
1087
+ uintptr_t escape;
1088
+ ngx_str_t binary, base64;
1089
+ ngx_buf_t *b;
1090
+ OCSP_CERTID *id;
1091
+ OCSP_REQUEST *ocsp;
1092
+
1093
+ ocsp = OCSP_REQUEST_new();
1094
+ if (ocsp == NULL) {
1095
+ ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
1096
+ "OCSP_REQUEST_new() failed");
1097
+ return NGX_ERROR;
1098
+ }
1099
+
1100
+ id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer);
1101
+ if (id == NULL) {
1102
+ ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
1103
+ "OCSP_cert_to_id() failed");
1104
+ goto failed;
1105
+ }
1106
+
1107
+ if (OCSP_request_add0_id(ocsp, id) == NULL) {
1108
+ ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
1109
+ "OCSP_request_add0_id() failed");
1110
+ goto failed;
1111
+ }
1112
+
1113
+ len = i2d_OCSP_REQUEST(ocsp, NULL);
1114
+ if (len <= 0) {
1115
+ ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
1116
+ "i2d_OCSP_REQUEST() failed");
1117
+ goto failed;
1118
+ }
1119
+
1120
+ binary.len = len;
1121
+ binary.data = ngx_palloc(ctx->pool, len);
1122
+ if (binary.data == NULL) {
1123
+ goto failed;
1124
+ }
1125
+
1126
+ p = binary.data;
1127
+ len = i2d_OCSP_REQUEST(ocsp, &p);
1128
+ if (len <= 0) {
1129
+ ngx_ssl_error(NGX_LOG_EMERG, ctx->log, 0,
1130
+ "i2d_OCSP_REQUEST() failed");
1131
+ goto failed;
1132
+ }
1133
+
1134
+ base64.len = ngx_base64_encoded_length(binary.len);
1135
+ base64.data = ngx_palloc(ctx->pool, base64.len);
1136
+ if (base64.data == NULL) {
1137
+ goto failed;
1138
+ }
1139
+
1140
+ ngx_encode_base64(&base64, &binary);
1141
+
1142
+ escape = ngx_escape_uri(NULL, base64.data, base64.len,
1143
+ NGX_ESCAPE_URI_COMPONENT);
1144
+
1145
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1146
+ "ssl ocsp request length %z, escape %d",
1147
+ base64.len, escape);
1148
+
1149
+ len = sizeof("GET ") - 1 + ctx->uri.len + sizeof("/") - 1
1150
+ + base64.len + 2 * escape + sizeof(" HTTP/1.0" CRLF) - 1
1151
+ + sizeof("Host: ") - 1 + ctx->host.len + sizeof(CRLF) - 1
1152
+ + sizeof(CRLF) - 1;
1153
+
1154
+ b = ngx_create_temp_buf(ctx->pool, len);
1155
+ if (b == NULL) {
1156
+ goto failed;
1157
+ }
1158
+
1159
+ p = b->last;
1160
+
1161
+ p = ngx_cpymem(p, "GET ", sizeof("GET ") - 1);
1162
+ p = ngx_cpymem(p, ctx->uri.data, ctx->uri.len);
1163
+
1164
+ if (ctx->uri.data[ctx->uri.len - 1] != '/') {
1165
+ *p++ = '/';
1166
+ }
1167
+
1168
+ if (escape == 0) {
1169
+ p = ngx_cpymem(p, base64.data, base64.len);
1170
+
1171
+ } else {
1172
+ p = (u_char *) ngx_escape_uri(p, base64.data, base64.len,
1173
+ NGX_ESCAPE_URI_COMPONENT);
1174
+ }
1175
+
1176
+ p = ngx_cpymem(p, " HTTP/1.0" CRLF, sizeof(" HTTP/1.0" CRLF) - 1);
1177
+ p = ngx_cpymem(p, "Host: ", sizeof("Host: ") - 1);
1178
+ p = ngx_cpymem(p, ctx->host.data, ctx->host.len);
1179
+ *p++ = CR; *p++ = LF;
1180
+
1181
+ /* add "\r\n" at the header end */
1182
+ *p++ = CR; *p++ = LF;
1183
+
1184
+ b->last = p;
1185
+ ctx->request = b;
1186
+
1187
+ return NGX_OK;
1188
+
1189
+ failed:
1190
+
1191
+ OCSP_REQUEST_free(ocsp);
1192
+
1193
+ return NGX_ERROR;
1194
+ }
1195
+
1196
+
1197
+ static ngx_int_t
1198
+ ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx)
1199
+ {
1200
+ ngx_int_t rc;
1201
+
1202
+ rc = ngx_ssl_ocsp_parse_status_line(ctx);
1203
+
1204
+ if (rc == NGX_OK) {
1205
+ #if 0
1206
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1207
+ "ssl ocsp status line \"%*s\"",
1208
+ ctx->response->pos - ctx->response->start,
1209
+ ctx->response->start);
1210
+ #endif
1211
+
1212
+ ctx->process = ngx_ssl_ocsp_process_headers;
1213
+ return ctx->process(ctx);
1214
+ }
1215
+
1216
+ if (rc == NGX_AGAIN) {
1217
+ return NGX_AGAIN;
1218
+ }
1219
+
1220
+ /* rc == NGX_ERROR */
1221
+
1222
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
1223
+ "OCSP responder sent invalid response");
1224
+
1225
+ return NGX_ERROR;
1226
+ }
1227
+
1228
+
1229
+ static ngx_int_t
1230
+ ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx)
1231
+ {
1232
+ u_char ch;
1233
+ u_char *p;
1234
+ ngx_buf_t *b;
1235
+ enum {
1236
+ sw_start = 0,
1237
+ sw_H,
1238
+ sw_HT,
1239
+ sw_HTT,
1240
+ sw_HTTP,
1241
+ sw_first_major_digit,
1242
+ sw_major_digit,
1243
+ sw_first_minor_digit,
1244
+ sw_minor_digit,
1245
+ sw_status,
1246
+ sw_space_after_status,
1247
+ sw_status_text,
1248
+ sw_almost_done
1249
+ } state;
1250
+
1251
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1252
+ "ssl ocsp process status line");
1253
+
1254
+ state = ctx->state;
1255
+ b = ctx->response;
1256
+
1257
+ for (p = b->pos; p < b->last; p++) {
1258
+ ch = *p;
1259
+
1260
+ switch (state) {
1261
+
1262
+ /* "HTTP/" */
1263
+ case sw_start:
1264
+ switch (ch) {
1265
+ case 'H':
1266
+ state = sw_H;
1267
+ break;
1268
+ default:
1269
+ return NGX_ERROR;
1270
+ }
1271
+ break;
1272
+
1273
+ case sw_H:
1274
+ switch (ch) {
1275
+ case 'T':
1276
+ state = sw_HT;
1277
+ break;
1278
+ default:
1279
+ return NGX_ERROR;
1280
+ }
1281
+ break;
1282
+
1283
+ case sw_HT:
1284
+ switch (ch) {
1285
+ case 'T':
1286
+ state = sw_HTT;
1287
+ break;
1288
+ default:
1289
+ return NGX_ERROR;
1290
+ }
1291
+ break;
1292
+
1293
+ case sw_HTT:
1294
+ switch (ch) {
1295
+ case 'P':
1296
+ state = sw_HTTP;
1297
+ break;
1298
+ default:
1299
+ return NGX_ERROR;
1300
+ }
1301
+ break;
1302
+
1303
+ case sw_HTTP:
1304
+ switch (ch) {
1305
+ case '/':
1306
+ state = sw_first_major_digit;
1307
+ break;
1308
+ default:
1309
+ return NGX_ERROR;
1310
+ }
1311
+ break;
1312
+
1313
+ /* the first digit of major HTTP version */
1314
+ case sw_first_major_digit:
1315
+ if (ch < '1' || ch > '9') {
1316
+ return NGX_ERROR;
1317
+ }
1318
+
1319
+ state = sw_major_digit;
1320
+ break;
1321
+
1322
+ /* the major HTTP version or dot */
1323
+ case sw_major_digit:
1324
+ if (ch == '.') {
1325
+ state = sw_first_minor_digit;
1326
+ break;
1327
+ }
1328
+
1329
+ if (ch < '0' || ch > '9') {
1330
+ return NGX_ERROR;
1331
+ }
1332
+
1333
+ break;
1334
+
1335
+ /* the first digit of minor HTTP version */
1336
+ case sw_first_minor_digit:
1337
+ if (ch < '0' || ch > '9') {
1338
+ return NGX_ERROR;
1339
+ }
1340
+
1341
+ state = sw_minor_digit;
1342
+ break;
1343
+
1344
+ /* the minor HTTP version or the end of the request line */
1345
+ case sw_minor_digit:
1346
+ if (ch == ' ') {
1347
+ state = sw_status;
1348
+ break;
1349
+ }
1350
+
1351
+ if (ch < '0' || ch > '9') {
1352
+ return NGX_ERROR;
1353
+ }
1354
+
1355
+ break;
1356
+
1357
+ /* HTTP status code */
1358
+ case sw_status:
1359
+ if (ch == ' ') {
1360
+ break;
1361
+ }
1362
+
1363
+ if (ch < '0' || ch > '9') {
1364
+ return NGX_ERROR;
1365
+ }
1366
+
1367
+ ctx->code = ctx->code * 10 + ch - '0';
1368
+
1369
+ if (++ctx->count == 3) {
1370
+ state = sw_space_after_status;
1371
+ }
1372
+
1373
+ break;
1374
+
1375
+ /* space or end of line */
1376
+ case sw_space_after_status:
1377
+ switch (ch) {
1378
+ case ' ':
1379
+ state = sw_status_text;
1380
+ break;
1381
+ case '.': /* IIS may send 403.1, 403.2, etc */
1382
+ state = sw_status_text;
1383
+ break;
1384
+ case CR:
1385
+ state = sw_almost_done;
1386
+ break;
1387
+ case LF:
1388
+ goto done;
1389
+ default:
1390
+ return NGX_ERROR;
1391
+ }
1392
+ break;
1393
+
1394
+ /* any text until end of line */
1395
+ case sw_status_text:
1396
+ switch (ch) {
1397
+ case CR:
1398
+ state = sw_almost_done;
1399
+ break;
1400
+ case LF:
1401
+ goto done;
1402
+ }
1403
+ break;
1404
+
1405
+ /* end of status line */
1406
+ case sw_almost_done:
1407
+ switch (ch) {
1408
+ case LF:
1409
+ goto done;
1410
+ default:
1411
+ return NGX_ERROR;
1412
+ }
1413
+ }
1414
+ }
1415
+
1416
+ b->pos = p;
1417
+ ctx->state = state;
1418
+
1419
+ return NGX_AGAIN;
1420
+
1421
+ done:
1422
+
1423
+ b->pos = p + 1;
1424
+ ctx->state = sw_start;
1425
+
1426
+ return NGX_OK;
1427
+ }
1428
+
1429
+
1430
+ static ngx_int_t
1431
+ ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx)
1432
+ {
1433
+ size_t len;
1434
+ ngx_int_t rc;
1435
+
1436
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1437
+ "ssl ocsp process headers");
1438
+
1439
+ for ( ;; ) {
1440
+ rc = ngx_ssl_ocsp_parse_header_line(ctx);
1441
+
1442
+ if (rc == NGX_OK) {
1443
+
1444
+ ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1445
+ "ssl ocsp header \"%*s: %*s\"",
1446
+ ctx->header_name_end - ctx->header_name_start,
1447
+ ctx->header_name_start,
1448
+ ctx->header_end - ctx->header_start,
1449
+ ctx->header_start);
1450
+
1451
+ len = ctx->header_name_end - ctx->header_name_start;
1452
+
1453
+ if (len == sizeof("Content-Type") - 1
1454
+ && ngx_strncasecmp(ctx->header_name_start,
1455
+ (u_char *) "Content-Type",
1456
+ sizeof("Content-Type") - 1)
1457
+ == 0)
1458
+ {
1459
+ len = ctx->header_end - ctx->header_start;
1460
+
1461
+ if (len != sizeof("application/ocsp-response") - 1
1462
+ || ngx_strncasecmp(ctx->header_start,
1463
+ (u_char *) "application/ocsp-response",
1464
+ sizeof("application/ocsp-response") - 1)
1465
+ != 0)
1466
+ {
1467
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
1468
+ "OCSP responder sent invalid "
1469
+ "\"Content-Type\" header: \"%*s\"",
1470
+ ctx->header_end - ctx->header_start,
1471
+ ctx->header_start);
1472
+ return NGX_ERROR;
1473
+ }
1474
+
1475
+ continue;
1476
+ }
1477
+
1478
+ /* TODO: honor Content-Length */
1479
+
1480
+ continue;
1481
+ }
1482
+
1483
+ if (rc == NGX_DONE) {
1484
+ break;
1485
+ }
1486
+
1487
+ if (rc == NGX_AGAIN) {
1488
+ return NGX_AGAIN;
1489
+ }
1490
+
1491
+ /* rc == NGX_ERROR */
1492
+
1493
+ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
1494
+ "OCSP responder sent invalid response");
1495
+
1496
+ return NGX_ERROR;
1497
+ }
1498
+
1499
+ ctx->process = ngx_ssl_ocsp_process_body;
1500
+ return ctx->process(ctx);
1501
+ }
1502
+
1503
+ static ngx_int_t
1504
+ ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx)
1505
+ {
1506
+ u_char c, ch, *p;
1507
+ enum {
1508
+ sw_start = 0,
1509
+ sw_name,
1510
+ sw_space_before_value,
1511
+ sw_value,
1512
+ sw_space_after_value,
1513
+ sw_almost_done,
1514
+ sw_header_almost_done
1515
+ } state;
1516
+
1517
+ state = ctx->state;
1518
+
1519
+ for (p = ctx->response->pos; p < ctx->response->last; p++) {
1520
+ ch = *p;
1521
+
1522
+ #if 0
1523
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1524
+ "s:%d in:'%02Xd:%c'", state, ch, ch);
1525
+ #endif
1526
+
1527
+ switch (state) {
1528
+
1529
+ /* first char */
1530
+ case sw_start:
1531
+
1532
+ switch (ch) {
1533
+ case CR:
1534
+ ctx->header_end = p;
1535
+ state = sw_header_almost_done;
1536
+ break;
1537
+ case LF:
1538
+ ctx->header_end = p;
1539
+ goto header_done;
1540
+ default:
1541
+ state = sw_name;
1542
+ ctx->header_name_start = p;
1543
+
1544
+ c = (u_char) (ch | 0x20);
1545
+ if (c >= 'a' && c <= 'z') {
1546
+ break;
1547
+ }
1548
+
1549
+ if (ch >= '0' && ch <= '9') {
1550
+ break;
1551
+ }
1552
+
1553
+ return NGX_ERROR;
1554
+ }
1555
+ break;
1556
+
1557
+ /* header name */
1558
+ case sw_name:
1559
+ c = (u_char) (ch | 0x20);
1560
+ if (c >= 'a' && c <= 'z') {
1561
+ break;
1562
+ }
1563
+
1564
+ if (ch == ':') {
1565
+ ctx->header_name_end = p;
1566
+ state = sw_space_before_value;
1567
+ break;
1568
+ }
1569
+
1570
+ if (ch == '-') {
1571
+ break;
1572
+ }
1573
+
1574
+ if (ch >= '0' && ch <= '9') {
1575
+ break;
1576
+ }
1577
+
1578
+ if (ch == CR) {
1579
+ ctx->header_name_end = p;
1580
+ ctx->header_start = p;
1581
+ ctx->header_end = p;
1582
+ state = sw_almost_done;
1583
+ break;
1584
+ }
1585
+
1586
+ if (ch == LF) {
1587
+ ctx->header_name_end = p;
1588
+ ctx->header_start = p;
1589
+ ctx->header_end = p;
1590
+ goto done;
1591
+ }
1592
+
1593
+ return NGX_ERROR;
1594
+
1595
+ /* space* before header value */
1596
+ case sw_space_before_value:
1597
+ switch (ch) {
1598
+ case ' ':
1599
+ break;
1600
+ case CR:
1601
+ ctx->header_start = p;
1602
+ ctx->header_end = p;
1603
+ state = sw_almost_done;
1604
+ break;
1605
+ case LF:
1606
+ ctx->header_start = p;
1607
+ ctx->header_end = p;
1608
+ goto done;
1609
+ default:
1610
+ ctx->header_start = p;
1611
+ state = sw_value;
1612
+ break;
1613
+ }
1614
+ break;
1615
+
1616
+ /* header value */
1617
+ case sw_value:
1618
+ switch (ch) {
1619
+ case ' ':
1620
+ ctx->header_end = p;
1621
+ state = sw_space_after_value;
1622
+ break;
1623
+ case CR:
1624
+ ctx->header_end = p;
1625
+ state = sw_almost_done;
1626
+ break;
1627
+ case LF:
1628
+ ctx->header_end = p;
1629
+ goto done;
1630
+ }
1631
+ break;
1632
+
1633
+ /* space* before end of header line */
1634
+ case sw_space_after_value:
1635
+ switch (ch) {
1636
+ case ' ':
1637
+ break;
1638
+ case CR:
1639
+ state = sw_almost_done;
1640
+ break;
1641
+ case LF:
1642
+ goto done;
1643
+ default:
1644
+ state = sw_value;
1645
+ break;
1646
+ }
1647
+ break;
1648
+
1649
+ /* end of header line */
1650
+ case sw_almost_done:
1651
+ switch (ch) {
1652
+ case LF:
1653
+ goto done;
1654
+ default:
1655
+ return NGX_ERROR;
1656
+ }
1657
+
1658
+ /* end of header */
1659
+ case sw_header_almost_done:
1660
+ switch (ch) {
1661
+ case LF:
1662
+ goto header_done;
1663
+ default:
1664
+ return NGX_ERROR;
1665
+ }
1666
+ }
1667
+ }
1668
+
1669
+ ctx->response->pos = p;
1670
+ ctx->state = state;
1671
+
1672
+ return NGX_AGAIN;
1673
+
1674
+ done:
1675
+
1676
+ ctx->response->pos = p + 1;
1677
+ ctx->state = sw_start;
1678
+
1679
+ return NGX_OK;
1680
+
1681
+ header_done:
1682
+
1683
+ ctx->response->pos = p + 1;
1684
+ ctx->state = sw_start;
1685
+
1686
+ return NGX_DONE;
1687
+ }
1688
+
1689
+
1690
+ static ngx_int_t
1691
+ ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx)
1692
+ {
1693
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
1694
+ "ssl ocsp process body");
1695
+
1696
+ if (ctx->done) {
1697
+ ctx->handler(ctx);
1698
+ return NGX_DONE;
1699
+ }
1700
+
1701
+ return NGX_AGAIN;
1702
+ }
1703
+
1704
+
1705
+ static u_char *
1706
+ ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len)
1707
+ {
1708
+ u_char *p;
1709
+ ngx_ssl_ocsp_ctx_t *ctx;
1710
+
1711
+ p = buf;
1712
+
1713
+ if (log->action) {
1714
+ p = ngx_snprintf(buf, len, " while %s", log->action);
1715
+ len -= p - buf;
1716
+ }
1717
+
1718
+ ctx = log->data;
1719
+
1720
+ if (ctx) {
1721
+ p = ngx_snprintf(p, len, ", responder: %V", &ctx->host);
1722
+ }
1723
+
1724
+ return p;
1725
+ }
1726
+
1727
+
1728
+ #else
1729
+
1730
+
1731
+ ngx_int_t
1732
+ ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
1733
+ ngx_str_t *responder, ngx_uint_t verify)
1734
+ {
1735
+ ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
1736
+ "\"ssl_stapling\" ignored, not supported");
1737
+
1738
+ return NGX_OK;
1739
+ }
1740
+
1741
+ ngx_int_t
1742
+ ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
1743
+ ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
1744
+ {
1745
+ return NGX_OK;
1746
+ }
1747
+
1748
+
1749
+ #endif