Mercurial > hg > nginx
comparison src/event/ngx_event_openssl.c @ 5744:42114bf12da0
SSL: the "ssl_password_file" directive.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Mon, 16 Jun 2014 19:43:25 +0400 |
parents | 5e892d40e5cc |
children | 57c05ff57980 |
comparison
equal
deleted
inserted
replaced
5743:dde2ae4701e1 | 5744:42114bf12da0 |
---|---|
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_event.h> | 10 #include <ngx_event.h> |
11 | 11 |
12 | 12 |
13 #define NGX_SSL_PASSWORD_BUFFER_SIZE 4096 | |
14 | |
15 | |
13 typedef struct { | 16 typedef struct { |
14 ngx_uint_t engine; /* unsigned engine:1; */ | 17 ngx_uint_t engine; /* unsigned engine:1; */ |
15 } ngx_openssl_conf_t; | 18 } ngx_openssl_conf_t; |
16 | 19 |
17 | 20 |
21 static int ngx_ssl_password_callback(char *buf, int size, int rwflag, | |
22 void *userdata); | |
18 static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); | 23 static int ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store); |
19 static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, | 24 static void ngx_ssl_info_callback(const ngx_ssl_conn_t *ssl_conn, int where, |
20 int ret); | 25 int ret); |
26 static void ngx_ssl_passwords_cleanup(void *data); | |
21 static void ngx_ssl_handshake_handler(ngx_event_t *ev); | 27 static void ngx_ssl_handshake_handler(ngx_event_t *ev); |
22 static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); | 28 static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); |
23 static void ngx_ssl_write_handler(ngx_event_t *wev); | 29 static void ngx_ssl_write_handler(ngx_event_t *wev); |
24 static void ngx_ssl_read_handler(ngx_event_t *rev); | 30 static void ngx_ssl_read_handler(ngx_event_t *rev); |
25 static void ngx_ssl_shutdown_handler(ngx_event_t *ev); | 31 static void ngx_ssl_shutdown_handler(ngx_event_t *ev); |
255 } | 261 } |
256 | 262 |
257 | 263 |
258 ngx_int_t | 264 ngx_int_t |
259 ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, | 265 ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, |
260 ngx_str_t *key) | 266 ngx_str_t *key, ngx_array_t *passwords) |
261 { | 267 { |
262 BIO *bio; | 268 BIO *bio; |
263 X509 *x509; | 269 X509 *x509; |
264 u_long n; | 270 u_long n; |
271 ngx_str_t *pwd; | |
272 ngx_uint_t tries; | |
265 | 273 |
266 if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { | 274 if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { |
267 return NGX_ERROR; | 275 return NGX_ERROR; |
268 } | 276 } |
269 | 277 |
346 | 354 |
347 if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) { | 355 if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) { |
348 return NGX_ERROR; | 356 return NGX_ERROR; |
349 } | 357 } |
350 | 358 |
351 if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data, | 359 if (passwords) { |
352 SSL_FILETYPE_PEM) | 360 tries = passwords->nelts; |
353 == 0) | 361 pwd = passwords->elts; |
354 { | 362 |
363 SSL_CTX_set_default_passwd_cb(ssl->ctx, ngx_ssl_password_callback); | |
364 SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, pwd); | |
365 | |
366 } else { | |
367 tries = 1; | |
368 #if (NGX_SUPPRESS_WARN) | |
369 pwd = NULL; | |
370 #endif | |
371 } | |
372 | |
373 for ( ;; ) { | |
374 | |
375 if (SSL_CTX_use_PrivateKey_file(ssl->ctx, (char *) key->data, | |
376 SSL_FILETYPE_PEM) | |
377 != 0) | |
378 { | |
379 break; | |
380 } | |
381 | |
382 if (--tries) { | |
383 n = ERR_peek_error(); | |
384 | |
385 if (ERR_GET_LIB(n) == ERR_LIB_EVP | |
386 && ERR_GET_REASON(n) == EVP_R_BAD_DECRYPT) | |
387 { | |
388 ERR_clear_error(); | |
389 SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ++pwd); | |
390 continue; | |
391 } | |
392 } | |
393 | |
355 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, | 394 ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, |
356 "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data); | 395 "SSL_CTX_use_PrivateKey_file(\"%s\") failed", key->data); |
357 return NGX_ERROR; | 396 return NGX_ERROR; |
358 } | 397 } |
359 | 398 |
399 SSL_CTX_set_default_passwd_cb(ssl->ctx, NULL); | |
400 | |
360 return NGX_OK; | 401 return NGX_OK; |
402 } | |
403 | |
404 | |
405 static int | |
406 ngx_ssl_password_callback(char *buf, int size, int rwflag, void *userdata) | |
407 { | |
408 ngx_str_t *pwd = userdata; | |
409 | |
410 if (rwflag) { | |
411 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, | |
412 "ngx_ssl_password_callback() is called for encryption"); | |
413 return 0; | |
414 } | |
415 | |
416 if (pwd->len > (size_t) size) { | |
417 ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, | |
418 "password is truncated to %d bytes", size); | |
419 } else { | |
420 size = pwd->len; | |
421 } | |
422 | |
423 ngx_memcpy(buf, pwd->data, size); | |
424 | |
425 return size; | |
361 } | 426 } |
362 | 427 |
363 | 428 |
364 ngx_int_t | 429 ngx_int_t |
365 ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, | 430 ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, |
592 key = RSA_generate_key(512, RSA_F4, NULL, NULL); | 657 key = RSA_generate_key(512, RSA_F4, NULL, NULL); |
593 } | 658 } |
594 } | 659 } |
595 | 660 |
596 return key; | 661 return key; |
662 } | |
663 | |
664 | |
665 ngx_array_t * | |
666 ngx_ssl_read_password_file(ngx_conf_t *cf, ngx_str_t *file) | |
667 { | |
668 u_char *p, *last, *end; | |
669 size_t len; | |
670 ssize_t n; | |
671 ngx_fd_t fd; | |
672 ngx_str_t *pwd; | |
673 ngx_array_t *passwords; | |
674 ngx_pool_cleanup_t *cln; | |
675 u_char buf[NGX_SSL_PASSWORD_BUFFER_SIZE]; | |
676 | |
677 if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) { | |
678 return NULL; | |
679 } | |
680 | |
681 cln = ngx_pool_cleanup_add(cf->temp_pool, 0); | |
682 passwords = ngx_array_create(cf->temp_pool, 4, sizeof(ngx_str_t)); | |
683 | |
684 if (cln == NULL || passwords == NULL) { | |
685 return NULL; | |
686 } | |
687 | |
688 cln->handler = ngx_ssl_passwords_cleanup; | |
689 cln->data = passwords; | |
690 | |
691 fd = ngx_open_file(file->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); | |
692 if (fd == NGX_INVALID_FILE) { | |
693 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, | |
694 ngx_open_file_n " \"%s\" failed", file->data); | |
695 return NULL; | |
696 } | |
697 | |
698 len = 0; | |
699 last = buf; | |
700 | |
701 do { | |
702 n = ngx_read_fd(fd, last, NGX_SSL_PASSWORD_BUFFER_SIZE - len); | |
703 | |
704 if (n == -1) { | |
705 ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, | |
706 ngx_read_fd_n " \"%s\" failed", file->data); | |
707 passwords = NULL; | |
708 goto cleanup; | |
709 } | |
710 | |
711 end = last + n; | |
712 | |
713 if (len && n == 0) { | |
714 *end++ = LF; | |
715 } | |
716 | |
717 p = buf; | |
718 | |
719 for ( ;; ) { | |
720 last = ngx_strlchr(last, end, LF); | |
721 | |
722 if (last == NULL) { | |
723 break; | |
724 } | |
725 | |
726 len = last++ - p; | |
727 | |
728 if (len && p[len - 1] == CR) { | |
729 len--; | |
730 } | |
731 | |
732 if (len) { | |
733 pwd = ngx_array_push(passwords); | |
734 if (pwd == NULL) { | |
735 passwords = NULL; | |
736 goto cleanup; | |
737 } | |
738 | |
739 pwd->len = len; | |
740 pwd->data = ngx_pnalloc(cf->temp_pool, len); | |
741 | |
742 if (pwd->data == NULL) { | |
743 passwords->nelts--; | |
744 passwords = NULL; | |
745 goto cleanup; | |
746 } | |
747 | |
748 ngx_memcpy(pwd->data, p, len); | |
749 } | |
750 | |
751 p = last; | |
752 } | |
753 | |
754 len = end - p; | |
755 | |
756 if (len == NGX_SSL_PASSWORD_BUFFER_SIZE) { | |
757 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
758 "too long line in \"%s\"", file->data); | |
759 passwords = NULL; | |
760 goto cleanup; | |
761 } | |
762 | |
763 ngx_memmove(buf, p, len); | |
764 last = buf + len; | |
765 | |
766 } while (n != 0); | |
767 | |
768 if (passwords->nelts == 0) { | |
769 pwd = ngx_array_push(passwords); | |
770 if (pwd == NULL) { | |
771 passwords = NULL; | |
772 goto cleanup; | |
773 } | |
774 | |
775 ngx_memzero(pwd, sizeof(ngx_str_t)); | |
776 } | |
777 | |
778 cleanup: | |
779 | |
780 if (ngx_close_file(fd) == NGX_FILE_ERROR) { | |
781 ngx_conf_log_error(NGX_LOG_ALERT, cf, ngx_errno, | |
782 ngx_close_file_n " \"%s\" failed", file->data); | |
783 } | |
784 | |
785 ngx_memzero(buf, NGX_SSL_PASSWORD_BUFFER_SIZE); | |
786 | |
787 return passwords; | |
788 } | |
789 | |
790 | |
791 static void | |
792 ngx_ssl_passwords_cleanup(void *data) | |
793 { | |
794 ngx_array_t *passwords = data; | |
795 | |
796 ngx_str_t *pwd; | |
797 ngx_uint_t i; | |
798 | |
799 pwd = passwords->elts; | |
800 | |
801 for (i = 0; i < passwords->nelts; i++) { | |
802 ngx_memzero(pwd[i].data, pwd[i].len); | |
803 } | |
597 } | 804 } |
598 | 805 |
599 | 806 |
600 ngx_int_t | 807 ngx_int_t |
601 ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) | 808 ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file) |