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)