Mercurial > hg > nginx-vendor-0-8
comparison src/event/ngx_event_openssl.c @ 96:ca4f70b3ccc6 NGINX_0_2_2
nginx 0.2.2
*) Feature: the "config errmsg" command of the ngx_http_ssi_module.
*) Change: the ngx_http_geo_module variables can be overridden by the
"set" directive.
*) Feature: the "ssl_protocols" and "ssl_prefer_server_ciphers"
directives of the ngx_http_ssl_module and ngx_imap_ssl_module.
*) Bugfix: the ngx_http_autoindex_module did not show correctly the
long file names;
*) Bugfix: the ngx_http_autoindex_module now do not show the files
starting by dot.
*) Bugfix: if the SSL handshake failed then another connection may be
closed too.
Thanks to Rob Mueller.
*) Bugfix: the export versions of MSIE 5.x could not connect via HTTPS.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Fri, 30 Sep 2005 00:00:00 +0400 |
parents | 45945fa8b8ba |
children | 8bf57caa374a |
comparison
equal
deleted
inserted
replaced
95:2f95911bc4b4 | 96:ca4f70b3ccc6 |
---|---|
12 typedef struct { | 12 typedef struct { |
13 ngx_str_t engine; | 13 ngx_str_t engine; |
14 } ngx_openssl_conf_t; | 14 } ngx_openssl_conf_t; |
15 | 15 |
16 | 16 |
17 static void ngx_ssl_handshake_handler(ngx_event_t *ev); | |
17 static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); | 18 static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); |
18 static void ngx_ssl_write_handler(ngx_event_t *wev); | 19 static void ngx_ssl_write_handler(ngx_event_t *wev); |
19 static void ngx_ssl_read_handler(ngx_event_t *rev); | 20 static void ngx_ssl_read_handler(ngx_event_t *rev); |
21 static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, | |
22 ngx_err_t err, char *text); | |
20 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); | 23 static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); |
21 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf); | 24 static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf); |
22 | 25 |
23 #if !(NGX_SSL_ENGINE) | 26 #if !(NGX_SSL_ENGINE) |
24 static char *ngx_openssl_noengine(ngx_conf_t *cf, ngx_command_t *cmd, | 27 static char *ngx_openssl_noengine(ngx_conf_t *cf, ngx_command_t *cmd, |
61 NULL, /* init thread */ | 64 NULL, /* init thread */ |
62 NULL, /* exit thread */ | 65 NULL, /* exit thread */ |
63 NULL, /* exit process */ | 66 NULL, /* exit process */ |
64 NULL, /* exit master */ | 67 NULL, /* exit master */ |
65 NGX_MODULE_V1_PADDING | 68 NGX_MODULE_V1_PADDING |
66 }; | 69 }; |
70 | |
71 | |
72 static long ngx_ssl_protocols[] = { | |
73 SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1, | |
74 SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1, | |
75 SSL_OP_NO_SSLv2|SSL_OP_NO_TLSv1, | |
76 SSL_OP_NO_TLSv1, | |
77 SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3, | |
78 SSL_OP_NO_SSLv3, | |
79 SSL_OP_NO_SSLv2, | |
80 0, | |
81 }; | |
67 | 82 |
68 | 83 |
69 ngx_int_t | 84 ngx_int_t |
70 ngx_ssl_init(ngx_log_t *log) | 85 ngx_ssl_init(ngx_log_t *log) |
71 { | 86 { |
79 return NGX_OK; | 94 return NGX_OK; |
80 } | 95 } |
81 | 96 |
82 | 97 |
83 ngx_int_t | 98 ngx_int_t |
84 ngx_ssl_create_connection(ngx_ssl_ctx_t *ssl_ctx, ngx_connection_t *c, | 99 ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols) |
85 ngx_uint_t flags) | 100 { |
101 ssl->ctx = SSL_CTX_new(SSLv23_server_method()); | |
102 | |
103 if (ssl->ctx == NULL) { | |
104 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_new() failed"); | |
105 return NGX_ERROR; | |
106 } | |
107 | |
108 SSL_CTX_set_options(ssl->ctx, SSL_OP_ALL); | |
109 | |
110 if (ngx_ssl_protocols[protocols >> 1] != 0) { | |
111 SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]); | |
112 } | |
113 | |
114 SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); | |
115 | |
116 SSL_CTX_set_read_ahead(ssl->ctx, 1); | |
117 | |
118 return NGX_OK; | |
119 } | |
120 | |
121 | |
122 ngx_int_t | |
123 ngx_ssl_certificate(ngx_ssl_t *ssl, u_char *cert, u_char *key) | |
124 { | |
125 if (SSL_CTX_use_certificate_chain_file(ssl->ctx, (char *) cert) == 0) { | |
126 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, | |
127 "SSL_CTX_use_certificate_chain_file(\"%s\") failed", | |
128 cert); | |
129 return NGX_ERROR; | |
130 } | |
131 | |
132 if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key, SSL_FILETYPE_PEM) | |
133 == 0) | |
134 { | |
135 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, | |
136 "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key); | |
137 return NGX_ERROR; | |
138 } | |
139 | |
140 return NGX_OK; | |
141 } | |
142 | |
143 | |
144 ngx_int_t | |
145 ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl) | |
146 { | |
147 ssl->rsa512_key = RSA_generate_key(512, RSA_F4, NULL, NULL); | |
148 | |
149 if (ssl->rsa512_key) { | |
150 SSL_CTX_set_tmp_rsa(ssl->ctx, ssl->rsa512_key); | |
151 return NGX_OK; | |
152 } | |
153 | |
154 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "RSA_generate_key(512) failed"); | |
155 | |
156 return NGX_ERROR; | |
157 } | |
158 | |
159 | |
160 ngx_int_t | |
161 ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags) | |
86 { | 162 { |
87 ngx_ssl_t *ssl; | 163 ngx_ssl_connection_t *sc; |
88 | 164 |
89 ssl = ngx_pcalloc(c->pool, sizeof(ngx_ssl_t)); | 165 sc = ngx_pcalloc(c->pool, sizeof(ngx_ssl_connection_t)); |
90 if (ssl == NULL) { | 166 if (sc == NULL) { |
91 return NGX_ERROR; | 167 return NGX_ERROR; |
92 } | 168 } |
93 | 169 |
94 if (flags & NGX_SSL_BUFFER) { | 170 if (flags & NGX_SSL_BUFFER) { |
95 ssl->buffer = 1; | 171 sc->buffer = 1; |
96 | 172 |
97 ssl->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); | 173 sc->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); |
98 if (ssl->buf == NULL) { | 174 if (sc->buf == NULL) { |
99 return NGX_ERROR; | 175 return NGX_ERROR; |
100 } | 176 } |
101 } | 177 } |
102 | 178 |
103 ssl->connection = SSL_new(ssl_ctx); | 179 sc->connection = SSL_new(ssl->ctx); |
104 | 180 |
105 if (ssl->connection == NULL) { | 181 if (sc->connection == NULL) { |
106 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed"); | 182 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_new() failed"); |
107 return NGX_ERROR; | 183 return NGX_ERROR; |
108 } | 184 } |
109 | 185 |
110 if (SSL_set_fd(ssl->connection, c->fd) == 0) { | 186 if (SSL_set_fd(sc->connection, c->fd) == 0) { |
111 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed"); | 187 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_fd() failed"); |
112 return NGX_ERROR; | 188 return NGX_ERROR; |
113 } | 189 } |
114 | 190 |
115 SSL_set_accept_state(ssl->connection); | 191 SSL_set_accept_state(sc->connection); |
116 | 192 |
117 c->ssl = ssl; | 193 c->ssl = sc; |
118 | 194 |
119 return NGX_OK; | 195 return NGX_OK; |
196 } | |
197 | |
198 | |
199 ngx_int_t | |
200 ngx_ssl_handshake(ngx_connection_t *c) | |
201 { | |
202 int n, sslerr; | |
203 ngx_err_t err; | |
204 | |
205 n = SSL_do_handshake(c->ssl->connection); | |
206 | |
207 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); | |
208 | |
209 if (n == 1) { | |
210 | |
211 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
212 return NGX_ERROR; | |
213 } | |
214 | |
215 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { | |
216 return NGX_ERROR; | |
217 } | |
218 | |
219 #if (NGX_DEBUG) | |
220 { | |
221 char buf[129], *s, *d; | |
222 SSL_CIPHER *cipher; | |
223 | |
224 cipher = SSL_get_current_cipher(c->ssl->connection); | |
225 | |
226 if (cipher) { | |
227 SSL_CIPHER_description(cipher, &buf[1], 128); | |
228 | |
229 for (s = &buf[1], d = buf; *s; s++) { | |
230 if (*s == ' ' && *d == ' ') { | |
231 continue; | |
232 } | |
233 | |
234 if (*s == LF || *s == CR) { | |
235 continue; | |
236 } | |
237 | |
238 *++d = *s; | |
239 } | |
240 | |
241 if (*d != ' ') { | |
242 d++; | |
243 } | |
244 | |
245 *d = '\0'; | |
246 | |
247 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
248 "SSL: %s, cipher: \"%s\"", | |
249 SSL_get_version(c->ssl->connection), &buf[1]); | |
250 | |
251 if (SSL_session_reused(c->ssl->connection)) { | |
252 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
253 "SSL reused session"); | |
254 } | |
255 | |
256 } else { | |
257 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
258 "SSL no shared ciphers"); | |
259 } | |
260 } | |
261 #endif | |
262 | |
263 c->ssl->handshaked = 1; | |
264 | |
265 c->recv = ngx_ssl_recv; | |
266 c->send = ngx_ssl_write; | |
267 c->send_chain = ngx_ssl_send_chain; | |
268 | |
269 return NGX_OK; | |
270 } | |
271 | |
272 sslerr = SSL_get_error(c->ssl->connection, n); | |
273 | |
274 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); | |
275 | |
276 if (sslerr == SSL_ERROR_WANT_READ) { | |
277 c->read->ready = 0; | |
278 c->read->handler = ngx_ssl_handshake_handler; | |
279 | |
280 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
281 return NGX_ERROR; | |
282 } | |
283 | |
284 return NGX_AGAIN; | |
285 } | |
286 | |
287 if (sslerr == SSL_ERROR_WANT_WRITE) { | |
288 c->write->ready = 0; | |
289 c->write->handler = ngx_ssl_handshake_handler; | |
290 | |
291 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { | |
292 return NGX_ERROR; | |
293 } | |
294 | |
295 return NGX_AGAIN; | |
296 } | |
297 | |
298 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; | |
299 | |
300 c->ssl->no_wait_shutdown = 1; | |
301 c->ssl->no_send_shutdown = 1; | |
302 | |
303 if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { | |
304 ngx_log_error(NGX_LOG_INFO, c->log, err, | |
305 "client closed connection in SSL handshake"); | |
306 | |
307 return NGX_ERROR; | |
308 } | |
309 | |
310 ngx_ssl_connection_error(c, sslerr, err, "SSL_do_handshake() failed"); | |
311 | |
312 return NGX_ERROR; | |
313 } | |
314 | |
315 | |
316 static void | |
317 ngx_ssl_handshake_handler(ngx_event_t *ev) | |
318 { | |
319 ngx_connection_t *c; | |
320 | |
321 c = ev->data; | |
322 | |
323 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
324 "ssl handshake handler: %d", ev->write); | |
325 | |
326 if (ngx_ssl_handshake(c) == NGX_AGAIN) { | |
327 return; | |
328 } | |
329 | |
330 c->ssl->handler(c); | |
120 } | 331 } |
121 | 332 |
122 | 333 |
123 ssize_t | 334 ssize_t |
124 ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size) | 335 ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size) |
141 n = SSL_read(c->ssl->connection, buf, size); | 352 n = SSL_read(c->ssl->connection, buf, size); |
142 | 353 |
143 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); | 354 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_read: %d", n); |
144 | 355 |
145 if (n > 0) { | 356 if (n > 0) { |
146 | |
147 bytes += n; | 357 bytes += n; |
148 | |
149 #if (NGX_DEBUG) | |
150 | |
151 if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->connection)) | |
152 { | |
153 char buf[129], *s, *d; | |
154 SSL_CIPHER *cipher; | |
155 | |
156 c->ssl->handshaked = 1; | |
157 | |
158 cipher = SSL_get_current_cipher(c->ssl->connection); | |
159 | |
160 if (cipher) { | |
161 SSL_CIPHER_description(cipher, &buf[1], 128); | |
162 | |
163 for (s = &buf[1], d = buf; *s; s++) { | |
164 if (*s == ' ' && *d == ' ') { | |
165 continue; | |
166 } | |
167 | |
168 if (*s == LF || *s == CR) { | |
169 continue; | |
170 } | |
171 | |
172 *++d = *s; | |
173 } | |
174 | |
175 if (*d != ' ') { | |
176 d++; | |
177 } | |
178 | |
179 *d = '\0'; | |
180 | |
181 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
182 "SSL cipher: \"%s\"", &buf[1]); | |
183 | |
184 if (SSL_session_reused(c->ssl->connection)) { | |
185 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
186 "SSL reused session"); | |
187 } | |
188 | |
189 } else { | |
190 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
191 "SSL no shared ciphers"); | |
192 } | |
193 } | |
194 #endif | |
195 | |
196 } | 358 } |
197 | 359 |
198 c->ssl->last = ngx_ssl_handle_recv(c, n); | 360 c->ssl->last = ngx_ssl_handle_recv(c, n); |
199 | 361 |
200 if (c->ssl->last != NGX_OK) { | 362 if (c->ssl->last != NGX_OK) { |
219 | 381 |
220 | 382 |
221 static ngx_int_t | 383 static ngx_int_t |
222 ngx_ssl_handle_recv(ngx_connection_t *c, int n) | 384 ngx_ssl_handle_recv(ngx_connection_t *c, int n) |
223 { | 385 { |
224 int sslerr; | 386 int sslerr; |
225 char *handshake; | 387 ngx_err_t err; |
226 ngx_err_t err; | |
227 ngx_uint_t level; | |
228 | 388 |
229 if (n > 0) { | 389 if (n > 0) { |
230 | 390 |
231 if (c->ssl->saved_write_handler) { | 391 if (c->ssl->saved_write_handler) { |
232 | 392 |
248 } | 408 } |
249 | 409 |
250 return NGX_OK; | 410 return NGX_OK; |
251 } | 411 } |
252 | 412 |
253 if (!SSL_is_init_finished(c->ssl->connection)) { | |
254 handshake = " in SSL handshake"; | |
255 | |
256 } else { | |
257 handshake = ""; | |
258 } | |
259 | |
260 sslerr = SSL_get_error(c->ssl->connection, n); | 413 sslerr = SSL_get_error(c->ssl->connection, n); |
261 | 414 |
262 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; | 415 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; |
263 | 416 |
264 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); | 417 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); |
268 return NGX_AGAIN; | 421 return NGX_AGAIN; |
269 } | 422 } |
270 | 423 |
271 if (sslerr == SSL_ERROR_WANT_WRITE) { | 424 if (sslerr == SSL_ERROR_WANT_WRITE) { |
272 | 425 |
273 ngx_log_error(NGX_LOG_INFO, c->log, err, | 426 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
274 "client does SSL %shandshake", | 427 "client started SSL renegotiation"); |
275 SSL_is_init_finished(c->ssl->connection) ? "re" : ""); | |
276 | 428 |
277 c->write->ready = 0; | 429 c->write->ready = 0; |
278 | 430 |
279 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { | 431 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { |
280 return NGX_ERROR; | 432 return NGX_ERROR; |
290 } | 442 } |
291 | 443 |
292 return NGX_AGAIN; | 444 return NGX_AGAIN; |
293 } | 445 } |
294 | 446 |
295 c->ssl->no_rcv_shut = 1; | 447 c->ssl->no_wait_shutdown = 1; |
296 c->ssl->no_send_shut = 1; | 448 c->ssl->no_send_shutdown = 1; |
297 | 449 |
298 if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { | 450 if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { |
299 ngx_log_error(NGX_LOG_INFO, c->log, err, | 451 ngx_log_error(NGX_LOG_INFO, c->log, err, "client closed connection"); |
300 "client closed connection%s", handshake); | |
301 | 452 |
302 return NGX_ERROR; | 453 return NGX_ERROR; |
303 } | 454 } |
455 | |
456 ngx_ssl_connection_error(c, sslerr, err, "SSL_read() failed"); | |
457 | |
458 return NGX_ERROR; | |
459 } | |
460 | |
461 | |
462 static void | |
463 ngx_ssl_write_handler(ngx_event_t *wev) | |
464 { | |
465 ngx_connection_t *c; | |
466 | |
467 c = wev->data; | |
468 | |
469 c->read->handler(c->read); | |
470 } | |
471 | |
472 | |
473 /* | |
474 * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer | |
475 * before the SSL_write() call to decrease a SSL overhead. | |
476 * | |
477 * Besides for protocols such as HTTP it is possible to always buffer | |
478 * the output to decrease a SSL overhead some more. | |
479 */ | |
480 | |
481 ngx_chain_t * | |
482 ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) | |
483 { | |
484 int n; | |
485 ngx_uint_t flush; | |
486 ssize_t send, size; | |
487 ngx_buf_t *buf; | |
488 | |
489 buf = c->ssl->buf; | |
490 | |
491 if (in && in->next == NULL && !c->buffered && !c->ssl->buffer) { | |
492 | |
493 /* | |
494 * we avoid a buffer copy if the incoming buf is a single, | |
495 * our buffer is empty, and we do not need to buffer the output | |
496 */ | |
497 | |
498 n = ngx_ssl_write(c, in->buf->pos, in->buf->last - in->buf->pos); | |
499 | |
500 if (n == NGX_ERROR) { | |
501 return NGX_CHAIN_ERROR; | |
502 } | |
503 | |
504 if (n == NGX_AGAIN) { | |
505 c->buffered = 1; | |
506 return in; | |
507 } | |
508 | |
509 in->buf->pos += n; | |
510 | |
511 return in; | |
512 } | |
513 | |
514 | |
515 /* the maximum limit size is the maximum uint32_t value - the page size */ | |
516 | |
517 if (limit == 0 || limit > NGX_MAX_UINT32_VALUE - ngx_pagesize) { | |
518 limit = NGX_MAX_UINT32_VALUE - ngx_pagesize; | |
519 } | |
520 | |
521 | |
522 send = 0; | |
523 flush = (in == NULL) ? 1 : 0; | |
524 | |
525 for ( ;; ) { | |
526 | |
527 while (in && buf->last < buf->end) { | |
528 if (in->buf->last_buf) { | |
529 flush = 1; | |
530 } | |
531 | |
532 if (ngx_buf_special(in->buf)) { | |
533 in = in->next; | |
534 continue; | |
535 } | |
536 | |
537 size = in->buf->last - in->buf->pos; | |
538 | |
539 if (size > buf->end - buf->last) { | |
540 size = buf->end - buf->last; | |
541 } | |
542 | |
543 /* | |
544 * TODO: the taking in->buf->flush into account can be | |
545 * implemented using the limit on the higher level | |
546 */ | |
547 | |
548 if (send + size > limit) { | |
549 size = limit - send; | |
550 flush = 1; | |
551 } | |
552 | |
553 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
554 "SSL buf copy: %d", size); | |
555 | |
556 ngx_memcpy(buf->last, in->buf->pos, size); | |
557 | |
558 buf->last += size; | |
559 | |
560 in->buf->pos += size; | |
561 if (in->buf->pos == in->buf->last) { | |
562 in = in->next; | |
563 } | |
564 } | |
565 | |
566 size = buf->last - buf->pos; | |
567 | |
568 if (!flush && buf->last < buf->end && c->ssl->buffer) { | |
569 break; | |
570 } | |
571 | |
572 n = ngx_ssl_write(c, buf->pos, size); | |
573 | |
574 if (n == NGX_ERROR) { | |
575 return NGX_CHAIN_ERROR; | |
576 } | |
577 | |
578 if (n == NGX_AGAIN) { | |
579 c->buffered = 1; | |
580 return in; | |
581 } | |
582 | |
583 buf->pos += n; | |
584 send += n; | |
585 c->sent += n; | |
586 | |
587 if (n < size) { | |
588 break; | |
589 } | |
590 | |
591 if (buf->pos == buf->last) { | |
592 buf->pos = buf->start; | |
593 buf->last = buf->start; | |
594 } | |
595 | |
596 if (in == NULL || send == limit) { | |
597 break; | |
598 } | |
599 } | |
600 | |
601 c->buffered = (buf->pos < buf->last) ? 1 : 0; | |
602 | |
603 return in; | |
604 } | |
605 | |
606 | |
607 ssize_t | |
608 ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) | |
609 { | |
610 int n, sslerr; | |
611 ngx_err_t err; | |
612 | |
613 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); | |
614 | |
615 n = SSL_write(c->ssl->connection, data, size); | |
616 | |
617 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n); | |
618 | |
619 if (n > 0) { | |
620 | |
621 if (c->ssl->saved_read_handler) { | |
622 | |
623 c->read->handler = c->ssl->saved_read_handler; | |
624 c->ssl->saved_read_handler = NULL; | |
625 c->read->ready = 1; | |
626 | |
627 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
628 return NGX_ERROR; | |
629 } | |
630 | |
631 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { | |
632 return NGX_ERROR; | |
633 } | |
634 | |
635 ngx_post_event(c->read); | |
636 | |
637 ngx_mutex_unlock(ngx_posted_events_mutex); | |
638 } | |
639 | |
640 return n; | |
641 } | |
642 | |
643 sslerr = SSL_get_error(c->ssl->connection, n); | |
644 | |
645 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; | |
646 | |
647 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); | |
648 | |
649 if (sslerr == SSL_ERROR_WANT_WRITE) { | |
650 c->write->ready = 0; | |
651 return NGX_AGAIN; | |
652 } | |
653 | |
654 if (sslerr == SSL_ERROR_WANT_READ) { | |
655 | |
656 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
657 "client started SSL renegotiation"); | |
658 | |
659 c->read->ready = 0; | |
660 | |
661 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
662 return NGX_ERROR; | |
663 } | |
664 | |
665 /* | |
666 * we do not set the timer because there is already | |
667 * the write event timer | |
668 */ | |
669 | |
670 if (c->ssl->saved_read_handler == NULL) { | |
671 c->ssl->saved_read_handler = c->read->handler; | |
672 c->read->handler = ngx_ssl_read_handler; | |
673 } | |
674 | |
675 return NGX_AGAIN; | |
676 } | |
677 | |
678 c->ssl->no_wait_shutdown = 1; | |
679 c->ssl->no_send_shutdown = 1; | |
680 | |
681 ngx_ssl_connection_error(c, sslerr, err, "SSL_write() failed"); | |
682 | |
683 return NGX_ERROR; | |
684 } | |
685 | |
686 | |
687 static void | |
688 ngx_ssl_read_handler(ngx_event_t *rev) | |
689 { | |
690 ngx_connection_t *c; | |
691 | |
692 c = rev->data; | |
693 | |
694 c->write->handler(c->write); | |
695 } | |
696 | |
697 | |
698 ngx_int_t | |
699 ngx_ssl_shutdown(ngx_connection_t *c) | |
700 { | |
701 int n, sslerr, mode; | |
702 ngx_uint_t again; | |
703 | |
704 if (c->read->timedout) { | |
705 mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN; | |
706 | |
707 } else { | |
708 mode = SSL_get_shutdown(c->ssl->connection); | |
709 | |
710 if (c->ssl->no_wait_shutdown) { | |
711 mode |= SSL_RECEIVED_SHUTDOWN; | |
712 } | |
713 | |
714 if (c->ssl->no_send_shutdown) { | |
715 mode |= SSL_SENT_SHUTDOWN; | |
716 } | |
717 } | |
718 | |
719 SSL_set_shutdown(c->ssl->connection, mode); | |
720 | |
721 again = 0; | |
722 #if (NGX_SUPPRESS_WARN) | |
723 sslerr = 0; | |
724 #endif | |
725 | |
726 for ( ;; ) { | |
727 n = SSL_shutdown(c->ssl->connection); | |
728 | |
729 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); | |
730 | |
731 if (n == 1 || (n == 0 && c->read->timedout)) { | |
732 SSL_free(c->ssl->connection); | |
733 c->ssl = NULL; | |
734 | |
735 return NGX_OK; | |
736 } | |
737 | |
738 if (n == 0) { | |
739 again = 1; | |
740 break; | |
741 } | |
742 | |
743 break; | |
744 } | |
745 | |
746 if (!again) { | |
747 sslerr = SSL_get_error(c->ssl->connection, n); | |
748 | |
749 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
750 "SSL_get_error: %d", sslerr); | |
751 } | |
752 | |
753 if (again || sslerr == SSL_ERROR_WANT_READ) { | |
754 | |
755 ngx_add_timer(c->read, 30000); | |
756 | |
757 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
758 return NGX_ERROR; | |
759 } | |
760 | |
761 return NGX_AGAIN; | |
762 } | |
763 | |
764 if (sslerr == SSL_ERROR_WANT_WRITE) { | |
765 | |
766 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { | |
767 return NGX_ERROR; | |
768 } | |
769 | |
770 return NGX_AGAIN; | |
771 } | |
772 | |
773 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_shutdown() failed"); | |
774 | |
775 SSL_free(c->ssl->connection); | |
776 c->ssl = NULL; | |
777 | |
778 return NGX_ERROR; | |
779 } | |
780 | |
781 | |
782 static void | |
783 ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err, | |
784 char *text) | |
785 { | |
786 ngx_uint_t level; | |
304 | 787 |
305 level = NGX_LOG_CRIT; | 788 level = NGX_LOG_CRIT; |
306 | 789 |
307 if (sslerr == SSL_ERROR_SYSCALL) { | 790 if (sslerr == SSL_ERROR_SYSCALL) { |
308 | 791 |
327 break; | 810 break; |
328 } | 811 } |
329 } | 812 } |
330 } | 813 } |
331 | 814 |
332 ngx_ssl_error(level, c->log, err, "SSL_read() failed%s", handshake); | 815 ngx_ssl_error(level, c->log, err, text); |
333 | |
334 return NGX_ERROR; | |
335 } | |
336 | |
337 | |
338 static void | |
339 ngx_ssl_write_handler(ngx_event_t *wev) | |
340 { | |
341 ngx_connection_t *c; | |
342 | |
343 c = wev->data; | |
344 c->read->handler(c->read); | |
345 } | |
346 | |
347 | |
348 /* | |
349 * OpenSSL has no SSL_writev() so we copy several bufs into our 16K buffer | |
350 * before the SSL_write() call to decrease a SSL overhead. | |
351 * | |
352 * Besides for protocols such as HTTP it is possible to always buffer | |
353 * the output to decrease a SSL overhead some more. | |
354 */ | |
355 | |
356 ngx_chain_t * | |
357 ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) | |
358 { | |
359 int n; | |
360 ngx_uint_t flush; | |
361 ssize_t send, size; | |
362 ngx_buf_t *buf; | |
363 | |
364 buf = c->ssl->buf; | |
365 | |
366 if (in && in->next == NULL && !c->buffered && !c->ssl->buffer) { | |
367 | |
368 /* | |
369 * we avoid a buffer copy if the incoming buf is a single, | |
370 * our buffer is empty, and we do not need to buffer the output | |
371 */ | |
372 | |
373 n = ngx_ssl_write(c, in->buf->pos, in->buf->last - in->buf->pos); | |
374 | |
375 if (n == NGX_ERROR) { | |
376 return NGX_CHAIN_ERROR; | |
377 } | |
378 | |
379 if (n == NGX_AGAIN) { | |
380 c->buffered = 1; | |
381 return in; | |
382 } | |
383 | |
384 in->buf->pos += n; | |
385 | |
386 return in; | |
387 } | |
388 | |
389 | |
390 /* the maximum limit size is the maximum uint32_t value - the page size */ | |
391 | |
392 if (limit == 0 || limit > NGX_MAX_UINT32_VALUE - ngx_pagesize) { | |
393 limit = NGX_MAX_UINT32_VALUE - ngx_pagesize; | |
394 } | |
395 | |
396 | |
397 send = 0; | |
398 flush = (in == NULL) ? 1 : 0; | |
399 | |
400 for ( ;; ) { | |
401 | |
402 while (in && buf->last < buf->end) { | |
403 if (in->buf->last_buf) { | |
404 flush = 1; | |
405 } | |
406 | |
407 if (ngx_buf_special(in->buf)) { | |
408 in = in->next; | |
409 continue; | |
410 } | |
411 | |
412 size = in->buf->last - in->buf->pos; | |
413 | |
414 if (size > buf->end - buf->last) { | |
415 size = buf->end - buf->last; | |
416 } | |
417 | |
418 /* | |
419 * TODO: the taking in->buf->flush into account can be | |
420 * implemented using the limit on the higher level | |
421 */ | |
422 | |
423 if (send + size > limit) { | |
424 size = limit - send; | |
425 flush = 1; | |
426 } | |
427 | |
428 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
429 "SSL buf copy: %d", size); | |
430 | |
431 ngx_memcpy(buf->last, in->buf->pos, size); | |
432 | |
433 buf->last += size; | |
434 | |
435 in->buf->pos += size; | |
436 if (in->buf->pos == in->buf->last) { | |
437 in = in->next; | |
438 } | |
439 } | |
440 | |
441 size = buf->last - buf->pos; | |
442 | |
443 if (!flush && buf->last < buf->end && c->ssl->buffer) { | |
444 break; | |
445 } | |
446 | |
447 n = ngx_ssl_write(c, buf->pos, size); | |
448 | |
449 if (n == NGX_ERROR) { | |
450 return NGX_CHAIN_ERROR; | |
451 } | |
452 | |
453 if (n == NGX_AGAIN) { | |
454 c->buffered = 1; | |
455 return in; | |
456 } | |
457 | |
458 buf->pos += n; | |
459 send += n; | |
460 c->sent += n; | |
461 | |
462 if (n < size) { | |
463 break; | |
464 } | |
465 | |
466 if (buf->pos == buf->last) { | |
467 buf->pos = buf->start; | |
468 buf->last = buf->start; | |
469 } | |
470 | |
471 if (in == NULL || send == limit) { | |
472 break; | |
473 } | |
474 } | |
475 | |
476 c->buffered = (buf->pos < buf->last) ? 1 : 0; | |
477 | |
478 return in; | |
479 } | |
480 | |
481 | |
482 ssize_t | |
483 ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) | |
484 { | |
485 int n, sslerr; | |
486 ngx_err_t err; | |
487 ngx_uint_t level; | |
488 | |
489 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); | |
490 | |
491 n = SSL_write(c->ssl->connection, data, size); | |
492 | |
493 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n); | |
494 | |
495 if (n > 0) { | |
496 | |
497 #if (NGX_DEBUG) | |
498 | |
499 if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->connection)) { | |
500 char buf[129], *s, *d; | |
501 SSL_CIPHER *cipher; | |
502 | |
503 c->ssl->handshaked = 1; | |
504 | |
505 cipher = SSL_get_current_cipher(c->ssl->connection); | |
506 | |
507 if (cipher) { | |
508 SSL_CIPHER_description(cipher, &buf[1], 128); | |
509 | |
510 for (s = &buf[1], d = buf; *s; s++) { | |
511 if (*s == ' ' && *d == ' ') { | |
512 continue; | |
513 } | |
514 | |
515 if (*s == LF || *s == CR) { | |
516 continue; | |
517 } | |
518 | |
519 *++d = *s; | |
520 } | |
521 | |
522 if (*d != ' ') { | |
523 d++; | |
524 } | |
525 | |
526 *d = '\0'; | |
527 | |
528 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
529 "SSL cipher: \"%s\"", &buf[1]); | |
530 | |
531 if (SSL_session_reused(c->ssl->connection)) { | |
532 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
533 "SSL reused session"); | |
534 } | |
535 | |
536 } else { | |
537 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
538 "SSL no shared ciphers"); | |
539 } | |
540 } | |
541 #endif | |
542 | |
543 if (c->ssl->saved_read_handler) { | |
544 | |
545 c->read->handler = c->ssl->saved_read_handler; | |
546 c->ssl->saved_read_handler = NULL; | |
547 c->read->ready = 1; | |
548 | |
549 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
550 return NGX_ERROR; | |
551 } | |
552 | |
553 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { | |
554 return NGX_ERROR; | |
555 } | |
556 | |
557 ngx_post_event(c->read); | |
558 | |
559 ngx_mutex_unlock(ngx_posted_events_mutex); | |
560 } | |
561 | |
562 return n; | |
563 } | |
564 | |
565 sslerr = SSL_get_error(c->ssl->connection, n); | |
566 | |
567 err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; | |
568 | |
569 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); | |
570 | |
571 if (sslerr == SSL_ERROR_WANT_WRITE) { | |
572 c->write->ready = 0; | |
573 return NGX_AGAIN; | |
574 } | |
575 | |
576 if (sslerr == SSL_ERROR_WANT_READ) { | |
577 | |
578 ngx_log_error(NGX_LOG_INFO, c->log, err, | |
579 "client does SSL %shandshake", | |
580 SSL_is_init_finished(c->ssl->connection) ? "re" : ""); | |
581 | |
582 c->read->ready = 0; | |
583 | |
584 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
585 return NGX_ERROR; | |
586 } | |
587 | |
588 /* | |
589 * we do not set the timer because there is already | |
590 * the write event timer | |
591 */ | |
592 | |
593 if (c->ssl->saved_read_handler == NULL) { | |
594 c->ssl->saved_read_handler = c->read->handler; | |
595 c->read->handler = ngx_ssl_read_handler; | |
596 } | |
597 | |
598 return NGX_AGAIN; | |
599 } | |
600 | |
601 c->ssl->no_rcv_shut = 1; | |
602 c->ssl->no_send_shut = 1; | |
603 | |
604 level = NGX_LOG_CRIT; | |
605 | |
606 if (sslerr == SSL_ERROR_SYSCALL) { | |
607 | |
608 if (err == NGX_ECONNRESET | |
609 || err == NGX_EPIPE | |
610 || err == NGX_ENOTCONN | |
611 || err == NGX_ECONNREFUSED | |
612 || err == NGX_EHOSTUNREACH) | |
613 { | |
614 switch (c->log_error) { | |
615 | |
616 case NGX_ERROR_IGNORE_ECONNRESET: | |
617 case NGX_ERROR_INFO: | |
618 level = NGX_LOG_INFO; | |
619 break; | |
620 | |
621 case NGX_ERROR_ERR: | |
622 level = NGX_LOG_ERR; | |
623 break; | |
624 | |
625 default: | |
626 break; | |
627 } | |
628 } | |
629 } | |
630 | |
631 ngx_ssl_error(level, c->log, err, "SSL_write() failed"); | |
632 | |
633 return NGX_ERROR; | |
634 } | |
635 | |
636 | |
637 static void | |
638 ngx_ssl_read_handler(ngx_event_t *rev) | |
639 { | |
640 ngx_connection_t *c; | |
641 | |
642 c = rev->data; | |
643 c->write->handler(c->write); | |
644 } | |
645 | |
646 | |
647 ngx_int_t | |
648 ngx_ssl_shutdown(ngx_connection_t *c) | |
649 { | |
650 int n, sslerr, mode; | |
651 ngx_uint_t again; | |
652 | |
653 if (!c->ssl->shutdown_set) { | |
654 | |
655 /* it seems that SSL_set_shutdown() could be called once only */ | |
656 | |
657 if (c->read->timedout) { | |
658 mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN; | |
659 | |
660 } else { | |
661 mode = 0; | |
662 | |
663 if (c->ssl->no_rcv_shut) { | |
664 mode = SSL_RECEIVED_SHUTDOWN; | |
665 } | |
666 | |
667 if (c->ssl->no_send_shut) { | |
668 mode |= SSL_SENT_SHUTDOWN; | |
669 } | |
670 } | |
671 | |
672 if (mode) { | |
673 SSL_set_shutdown(c->ssl->connection, mode); | |
674 c->ssl->shutdown_set = 1; | |
675 } | |
676 } | |
677 | |
678 again = 0; | |
679 #if (NGX_SUPPRESS_WARN) | |
680 sslerr = 0; | |
681 #endif | |
682 | |
683 for ( ;; ) { | |
684 n = SSL_shutdown(c->ssl->connection); | |
685 | |
686 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); | |
687 | |
688 if (n == 1 || (n == 0 && c->read->timedout)) { | |
689 SSL_free(c->ssl->connection); | |
690 c->ssl = NULL; | |
691 | |
692 return NGX_OK; | |
693 } | |
694 | |
695 if (n == 0) { | |
696 again = 1; | |
697 break; | |
698 } | |
699 | |
700 break; | |
701 } | |
702 | |
703 if (!again) { | |
704 sslerr = SSL_get_error(c->ssl->connection, n); | |
705 | |
706 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
707 "SSL_get_error: %d", sslerr); | |
708 } | |
709 | |
710 if (again || sslerr == SSL_ERROR_WANT_READ) { | |
711 | |
712 ngx_add_timer(c->read, 30000); | |
713 | |
714 if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { | |
715 return NGX_ERROR; | |
716 } | |
717 | |
718 return NGX_AGAIN; | |
719 } | |
720 | |
721 if (sslerr == SSL_ERROR_WANT_WRITE) { | |
722 | |
723 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { | |
724 return NGX_ERROR; | |
725 } | |
726 | |
727 return NGX_AGAIN; | |
728 } | |
729 | |
730 ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_shutdown() failed"); | |
731 | |
732 SSL_free(c->ssl->connection); | |
733 c->ssl = NULL; | |
734 | |
735 return NGX_ERROR; | |
736 } | 816 } |
737 | 817 |
738 | 818 |
739 void | 819 void |
740 ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) | 820 ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) |
741 { | 821 { |
822 u_long n; | |
823 va_list args; | |
742 u_char errstr[NGX_MAX_CONF_ERRSTR], *p, *last; | 824 u_char errstr[NGX_MAX_CONF_ERRSTR], *p, *last; |
743 va_list args; | |
744 | 825 |
745 last = errstr + NGX_MAX_CONF_ERRSTR; | 826 last = errstr + NGX_MAX_CONF_ERRSTR; |
746 | 827 |
747 va_start(args, fmt); | 828 va_start(args, fmt); |
748 p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args); | 829 p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args); |
749 va_end(args); | 830 va_end(args); |
750 | 831 |
751 p = ngx_cpystrn(p, (u_char *) " (SSL: ", last - p); | 832 p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); |
752 | 833 |
753 ERR_error_string_n(ERR_get_error(), (char *) p, last - p); | 834 while (p < last && (n = ERR_get_error())) { |
835 | |
836 *p++ = ' '; | |
837 | |
838 ERR_error_string_n(n, (char *) p, last - p); | |
839 | |
840 while (p < last && *p) { | |
841 p++; | |
842 } | |
843 } | |
754 | 844 |
755 ngx_log_error(level, log, err, "%s)", errstr); | 845 ngx_log_error(level, log, err, "%s)", errstr); |
756 } | 846 } |
757 | 847 |
758 | 848 |
759 void | 849 void |
760 ngx_ssl_cleanup_ctx(void *data) | 850 ngx_ssl_cleanup_ctx(void *data) |
761 { | 851 { |
762 SSL_CTX *ctx = data; | 852 ngx_ssl_t *ssl = data; |
763 | 853 |
764 SSL_CTX_free(ctx); | 854 RSA_free(ssl->rsa512_key); |
855 SSL_CTX_free(ssl->ctx); | |
765 } | 856 } |
766 | 857 |
767 | 858 |
768 static void * | 859 static void * |
769 ngx_openssl_create_conf(ngx_cycle_t *cycle) | 860 ngx_openssl_create_conf(ngx_cycle_t *cycle) |