diff options
author | william <william@25thandclement.com> | 2015-04-16 21:00:58 -0700 |
---|---|---|
committer | william <william@25thandclement.com> | 2015-04-16 21:00:58 -0700 |
commit | 8dbe7e424adcfcf0bec4c8573b874d733c5b2a66 (patch) | |
tree | 9a074c0ca8f2347752b9c8564f4da383e5cb80fd | |
parent | 55da052192e151ee055e62a378d6ebdbdcbe5087 (diff) | |
download | luaossl-8dbe7e424adcfcf0bec4c8573b874d733c5b2a66.tar.gz luaossl-8dbe7e424adcfcf0bec4c8573b874d733c5b2a66.tar.bz2 luaossl-8dbe7e424adcfcf0bec4c8573b874d733c5b2a66.zip |
add fix for issue #17
-rw-r--r-- | src/openssl.c | 155 |
1 files changed, 148 insertions, 7 deletions
diff --git a/src/openssl.c b/src/openssl.c index 3465922..163ba7f 100644 --- a/src/openssl.c +++ b/src/openssl.c | |||
@@ -33,7 +33,9 @@ | |||
33 | #include <math.h> /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ | 33 | #include <math.h> /* INFINITY fabs(3) floor(3) frexp(3) fmod(3) round(3) isfinite(3) */ |
34 | #include <time.h> /* struct tm time_t strptime(3) time(2) */ | 34 | #include <time.h> /* struct tm time_t strptime(3) time(2) */ |
35 | #include <ctype.h> /* tolower(3) */ | 35 | #include <ctype.h> /* tolower(3) */ |
36 | #include <signal.h> /* sig_atomic_t */ | ||
36 | #include <errno.h> /* ENOMEM errno */ | 37 | #include <errno.h> /* ENOMEM errno */ |
38 | #include <assert.h> /* assert */ | ||
37 | 39 | ||
38 | #include <sys/types.h> /* ssize_t pid_t */ | 40 | #include <sys/types.h> /* ssize_t pid_t */ |
39 | #if !defined __sun && !defined _AIX | 41 | #if !defined __sun && !defined _AIX |
@@ -44,16 +46,11 @@ | |||
44 | #include <sys/socket.h> /* AF_INET AF_INET6 */ | 46 | #include <sys/socket.h> /* AF_INET AF_INET6 */ |
45 | #include <sys/resource.h> /* RUSAGE_SELF struct rusage getrusage(2) */ | 47 | #include <sys/resource.h> /* RUSAGE_SELF struct rusage getrusage(2) */ |
46 | #include <sys/utsname.h> /* struct utsname uname(3) */ | 48 | #include <sys/utsname.h> /* struct utsname uname(3) */ |
47 | |||
48 | #include <fcntl.h> /* O_RDONLY O_CLOEXEC open(2) */ | 49 | #include <fcntl.h> /* O_RDONLY O_CLOEXEC open(2) */ |
49 | |||
50 | #include <unistd.h> /* close(2) getpid(2) */ | 50 | #include <unistd.h> /* close(2) getpid(2) */ |
51 | |||
52 | #include <netinet/in.h> /* struct in_addr struct in6_addr */ | 51 | #include <netinet/in.h> /* struct in_addr struct in6_addr */ |
53 | #include <arpa/inet.h> /* inet_pton(3) */ | 52 | #include <arpa/inet.h> /* inet_pton(3) */ |
54 | |||
55 | #include <pthread.h> /* pthread_mutex_init(3) pthread_mutex_lock(3) pthread_mutex_unlock(3) */ | 53 | #include <pthread.h> /* pthread_mutex_init(3) pthread_mutex_lock(3) pthread_mutex_unlock(3) */ |
56 | |||
57 | #include <dlfcn.h> /* dladdr(3) dlopen(3) */ | 54 | #include <dlfcn.h> /* dladdr(3) dlopen(3) */ |
58 | 55 | ||
59 | #if __APPLE__ | 56 | #if __APPLE__ |
@@ -576,6 +573,22 @@ static void lib_setintegers(lua_State *L, const integer_Reg *l) { | |||
576 | } /* lib_setintegers() */ | 573 | } /* lib_setintegers() */ |
577 | 574 | ||
578 | 575 | ||
576 | #define COMPAT_X509_STORE_FREE_BUG 0x01 | ||
577 | |||
578 | static struct { | ||
579 | int flags; | ||
580 | |||
581 | int SSL_CTX_ex_index; | ||
582 | void (*X509_STORE_free)(X509_STORE *); | ||
583 | |||
584 | struct { | ||
585 | X509_STORE *store; | ||
586 | } tmp; | ||
587 | } compat = { | ||
588 | .flags = 0, | ||
589 | .SSL_CTX_ex_index = -1, | ||
590 | .X509_STORE_free = &X509_STORE_free, | ||
591 | }; | ||
579 | 592 | ||
580 | #if !HAVE_EVP_PKEY_base_id | 593 | #if !HAVE_EVP_PKEY_base_id |
581 | #define EVP_PKEY_base_id(key) compat_EVP_PKEY_base_id((key)) | 594 | #define EVP_PKEY_base_id(key) compat_EVP_PKEY_base_id((key)) |
@@ -621,6 +634,126 @@ static void *compat_EVP_PKEY_get0(EVP_PKEY *key) { | |||
621 | } /* compat_EVP_PKEY_get0() */ | 634 | } /* compat_EVP_PKEY_get0() */ |
622 | #endif | 635 | #endif |
623 | 636 | ||
637 | /* X509_STORE_free in OpenSSL versions < 1.0.2 doesn't obey reference count */ | ||
638 | #define X509_STORE_free(store) \ | ||
639 | (compat.X509_STORE_free)((store)) | ||
640 | |||
641 | static void compat_X509_STORE_free(X509_STORE *store) { | ||
642 | int i; | ||
643 | |||
644 | i = CRYPTO_add(&store->references, -1, CRYPTO_LOCK_X509_STORE); | ||
645 | |||
646 | if (i > 0) | ||
647 | return; | ||
648 | |||
649 | (X509_STORE_free)(store); | ||
650 | } /* compat_X509_STORE_free() */ | ||
651 | |||
652 | #if !HAVE_SSL_CTX_set1_cert_store | ||
653 | #define SSL_CTX_set1_cert_store(ctx, store) \ | ||
654 | compat_SSL_CTX_set1_cert_store((ctx), (store)) | ||
655 | |||
656 | static void compat_SSL_CTX_set1_cert_store(SSL_CTX *ctx, X509_STORE *store) { | ||
657 | int n; | ||
658 | |||
659 | /* | ||
660 | * This isn't thead-safe, but using X509_STORE or SSL_CTX objects | ||
661 | * from different threads isn't safe generally. | ||
662 | */ | ||
663 | if (ctx->cert_store) { | ||
664 | X509_STORE_free(ctx->cert_store); | ||
665 | ctx->cert_store = NULL; | ||
666 | } | ||
667 | |||
668 | n = store->references; | ||
669 | |||
670 | SSL_CTX_set_cert_store(ctx, store); | ||
671 | |||
672 | if (n == store->references) | ||
673 | CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); | ||
674 | } /* compat_SSL_CTX_set1_cert_store() */ | ||
675 | #endif | ||
676 | |||
677 | static void compat_SSL_CTX_onfree(void *_ctx, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { | ||
678 | SSL_CTX *ctx = _ctx; | ||
679 | |||
680 | if (ctx->cert_store) { | ||
681 | X509_STORE_free(ctx->cert_store); | ||
682 | ctx->cert_store = NULL; | ||
683 | } | ||
684 | } /* compat_SSL_CTX_onfree() */ | ||
685 | |||
686 | /* helper routine to determine if X509_STORE_free obeys reference count */ | ||
687 | static void compat_init_X509_STORE_onfree(void *store, void *data NOTUSED, CRYPTO_EX_DATA *ad NOTUSED, int idx NOTUSED, long argl NOTUSED, void *argp NOTUSED) { | ||
688 | /* unfortunately there's no way to remove a handler */ | ||
689 | if (store != compat.tmp.store) | ||
690 | return; | ||
691 | |||
692 | /* signal that we were freed by nulling our reference */ | ||
693 | compat.tmp.store = NULL; | ||
694 | } /* compat_init_X509_STORE_onfree() */ | ||
695 | |||
696 | static int compat_init(void) { | ||
697 | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; | ||
698 | static volatile sig_atomic_t done; | ||
699 | int error; | ||
700 | |||
701 | if ((error = pthread_mutex_lock(&mutex))) | ||
702 | return error; | ||
703 | |||
704 | if (!done) { | ||
705 | /* | ||
706 | * Test if X509_STORE_free obeys reference counts. | ||
707 | */ | ||
708 | if (-1 == CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_X509_STORE, 0, NULL, NULL, NULL, &compat_init_X509_STORE_onfree)) | ||
709 | goto sslerr; | ||
710 | |||
711 | if (!(compat.tmp.store = X509_STORE_new())) | ||
712 | goto sslerr; | ||
713 | |||
714 | CRYPTO_add(&compat.tmp.store->references, 1, CRYPTO_LOCK_X509_STORE); | ||
715 | X509_STORE_free(compat.tmp.store); | ||
716 | |||
717 | if (compat.tmp.store) { | ||
718 | X509_STORE_free(compat.tmp.store); | ||
719 | assert(compat.tmp.store == NULL); | ||
720 | compat.tmp.store = NULL; | ||
721 | } else { | ||
722 | /* | ||
723 | * If X509_STORE_free does NOT obey reference | ||
724 | * counts, then make sure that our fixed version is | ||
725 | * called on SSL_CTX destruction. Note that this | ||
726 | * won't fix code which doesn't properly obey the | ||
727 | * reference counts when setting the cert_store | ||
728 | * member. | ||
729 | */ | ||
730 | if (-1 == CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_CTX, 0, NULL, NULL, NULL, &compat_SSL_CTX_onfree)) | ||
731 | goto sslerr; | ||
732 | |||
733 | compat.flags |= COMPAT_X509_STORE_FREE_BUG; | ||
734 | } | ||
735 | |||
736 | done = 1; | ||
737 | } | ||
738 | epilog: | ||
739 | if (compat.tmp.store) { | ||
740 | X509_STORE_free(compat.tmp.store); | ||
741 | compat.tmp.store = NULL; | ||
742 | } | ||
743 | |||
744 | pthread_mutex_unlock(&mutex); | ||
745 | |||
746 | return 0; | ||
747 | sslerr: | ||
748 | error = -1; | ||
749 | |||
750 | goto epilog; | ||
751 | syserr: | ||
752 | error = errno; | ||
753 | |||
754 | goto epilog; | ||
755 | } /* compat_init() */ | ||
756 | |||
624 | 757 | ||
625 | typedef int auxref_t; | 758 | typedef int auxref_t; |
626 | typedef int auxtype_t; | 759 | typedef int auxtype_t; |
@@ -4699,8 +4832,7 @@ static int sx_setStore(lua_State *L) { | |||
4699 | SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); | 4832 | SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS); |
4700 | X509_STORE *store = checksimple(L, 2, X509_STORE_CLASS); | 4833 | X509_STORE *store = checksimple(L, 2, X509_STORE_CLASS); |
4701 | 4834 | ||
4702 | SSL_CTX_set_cert_store(ctx, store); | 4835 | SSL_CTX_set1_cert_store(ctx, store); |
4703 | CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); | ||
4704 | 4836 | ||
4705 | lua_pushboolean(L, 1); | 4837 | lua_pushboolean(L, 1); |
4706 | 4838 | ||
@@ -6251,6 +6383,15 @@ static void initall(lua_State *L) { | |||
6251 | } | 6383 | } |
6252 | } | 6384 | } |
6253 | 6385 | ||
6386 | /* TODO: Move down to after SSL_load_error_strings */ | ||
6387 | if ((error = compat_init())) { | ||
6388 | if (error == -1) { | ||
6389 | throwssl(L, "openssl.init"); | ||
6390 | } else { | ||
6391 | luaL_error(L, "openssl.init: %s", xstrerror(error)); | ||
6392 | } | ||
6393 | } | ||
6394 | |||
6254 | pthread_mutex_lock(&mutex); | 6395 | pthread_mutex_lock(&mutex); |
6255 | 6396 | ||
6256 | if (!initssl) { | 6397 | if (!initssl) { |