| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 4849d03 commit f299333
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -121,6 +121,7 @@ const char* const root_certs[] = { | |||
| 121 | 121 | }; | |
| 122 | 122 | ||
| 123 | 123 | X509_STORE* root_cert_store; | |
| 124 | + std::vector<X509*>* root_certs_vector; | ||
| 124 | 125 | ||
| 125 | 126 | // Just to generate static methods | |
| 126 | 127 | template class SSLWrap<TLSWrap>; | |
@@ -402,8 +403,6 @@ void SecureContext::Init(const FunctionCallbackInfo<Value>& args) { | |||
| 402 | 403 | SSL_SESS_CACHE_NO_AUTO_CLEAR); | |
| 403 | 404 | SSL_CTX_sess_set_get_cb(sc->ctx_, SSLWrap<Connection>::GetSessionCallback); | |
| 404 | 405 | SSL_CTX_sess_set_new_cb(sc->ctx_, SSLWrap<Connection>::NewSessionCallback); | |
| 405 | - | ||
| 406 | - sc->ca_store_ = nullptr; | ||
| 407 | 406 | } | |
| 408 | 407 | ||
| 409 | 408 | ||
@@ -672,8 +671,52 @@ void SecureContext::SetCert(const FunctionCallbackInfo<Value>& args) { | |||
| 672 | 671 | } | |
| 673 | 672 | ||
| 674 | 673 | ||
| 674 | + #if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) | ||
| 675 | + // This section contains OpenSSL 1.1.0 functions reimplemented for OpenSSL | ||
| 676 | + // 1.0.2 so that the following code can be written without lots of #if lines. | ||
| 677 | + | ||
| 678 | + static int X509_STORE_up_ref(X509_STORE* store) { | ||
| 679 | + CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); | ||
| 680 | + return 1; | ||
| 681 | + } | ||
| 682 | + | ||
| 683 | + static int X509_up_ref(X509* cert) { | ||
| 684 | + CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); | ||
| 685 | + return 1; | ||
| 686 | + } | ||
| 687 | + #endif // OPENSSL_VERSION_NUMBER < 0x10100000L && !OPENSSL_IS_BORINGSSL | ||
| 688 | + | ||
| 689 | + | ||
| 690 | + static X509_STORE* NewRootCertStore() { | ||
| 691 | + if (!root_certs_vector) { | ||
| 692 | + root_certs_vector = new std::vector<X509*>; | ||
| 693 | + | ||
| 694 | + for (size_t i = 0; i < arraysize(root_certs); i++) { | ||
| 695 | + BIO* bp = NodeBIO::NewFixed(root_certs[i], strlen(root_certs[i])); | ||
| 696 | + X509 *x509 = PEM_read_bio_X509(bp, nullptr, CryptoPemCallback, nullptr); | ||
| 697 | + BIO_free(bp); | ||
| 698 | + | ||
| 699 | + if (x509 == nullptr) { | ||
| 700 | + // Parse errors from the built-in roots are fatal. | ||
| 701 | + abort(); | ||
| 702 | + return nullptr; | ||
| 703 | + } | ||
| 704 | + | ||
| 705 | + root_certs_vector->push_back(x509); | ||
| 706 | + } | ||
| 707 | + } | ||
| 708 | + | ||
| 709 | + X509_STORE* store = X509_STORE_new(); | ||
| 710 | + for (auto& cert : *root_certs_vector) { | ||
| 711 | + X509_up_ref(cert); | ||
| 712 | + X509_STORE_add_cert(store, cert); | ||
| 713 | + } | ||
| 714 | + | ||
| 715 | + return store; | ||
| 716 | + } | ||
| 717 | + | ||
| 718 | + | ||
| 675 | 719 | void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) { | |
| 676 | - bool newCAStore = false; | ||
| 677 | 720 | Environment* env = Environment::GetCurrent(args); | |
| 678 | 721 | ||
| 679 | 722 | SecureContext* sc; | |
@@ -685,26 +728,24 @@ void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) { | |||
| 685 | 728 | return env->ThrowTypeError("CA certificate argument is mandatory"); | |
| 686 | 729 | } | |
| 687 | 730 | ||
| 688 | - if (!sc->ca_store_) { | ||
| 689 | - sc->ca_store_ = X509_STORE_new(); | ||
| 690 | - newCAStore = true; | ||
| 731 | + BIO* bio = LoadBIO(env, args[0]); | ||
| 732 | + if (!bio) { | ||
| 733 | + return; | ||
| 691 | 734 | } | |
| 692 | 735 | ||
| 693 | - unsigned cert_count = 0; | ||
| 694 | - if (BIO* bio = LoadBIO(env, args[0])) { | ||
| 695 | - while (X509* x509 = | ||
| 696 | - PEM_read_bio_X509(bio, nullptr, CryptoPemCallback, nullptr)) { | ||
| 697 | - X509_STORE_add_cert(sc->ca_store_, x509); | ||
| 698 | - SSL_CTX_add_client_CA(sc->ctx_, x509); | ||
| 699 | - X509_free(x509); | ||
| 700 | - cert_count += 1; | ||
| 736 | + X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_); | ||
| 737 | + while (X509* x509 = | ||
| 738 | + PEM_read_bio_X509(bio, nullptr, CryptoPemCallback, nullptr)) { | ||
| 739 | + if (cert_store == root_cert_store) { | ||
| 740 | + cert_store = NewRootCertStore(); | ||
| 741 | + SSL_CTX_set_cert_store(sc->ctx_, cert_store); | ||
| 701 | 742 | } | |
| 702 | - BIO_free_all(bio); | ||
| 743 | + X509_STORE_add_cert(cert_store, x509); | ||
| 744 | + SSL_CTX_add_client_CA(sc->ctx_, x509); | ||
| 745 | + X509_free(x509); | ||
| 703 | 746 | } | |
| 704 | 747 | ||
| 705 | - if (cert_count > 0 && newCAStore) { | ||
| 706 | - SSL_CTX_set_cert_store(sc->ctx_, sc->ca_store_); | ||
| 707 | - } | ||
| 748 | + BIO_free_all(bio); | ||
| 708 | 749 | } | |
| 709 | 750 | ||
| 710 | 751 | ||
@@ -725,57 +766,43 @@ void SecureContext::AddCRL(const FunctionCallbackInfo<Value>& args) { | |||
| 725 | 766 | if (!bio) | |
| 726 | 767 | return; | |
| 727 | 768 | ||
| 728 | - X509_CRL *x509 = | ||
| 769 | + X509_CRL* crl = | ||
| 729 | 770 | PEM_read_bio_X509_CRL(bio, nullptr, CryptoPemCallback, nullptr); | |
| 730 | 771 | ||
| 731 | - if (x509 == nullptr) { | ||
| 772 | + if (crl == nullptr) { | ||
| 773 | + return env->ThrowError("Failed to parse CRL"); | ||
| 732 | 774 | BIO_free_all(bio); | |
| 733 | 775 | return; | |
| 734 | 776 | } | |
| 735 | 777 | ||
| 736 | - X509_STORE_add_crl(sc->ca_store_, x509); | ||
| 737 | - X509_STORE_set_flags(sc->ca_store_, X509_V_FLAG_CRL_CHECK | | ||
| 738 | - X509_V_FLAG_CRL_CHECK_ALL); | ||
| 778 | + X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_); | ||
| 779 | + if (cert_store == root_cert_store) { | ||
| 780 | + cert_store = NewRootCertStore(); | ||
| 781 | + SSL_CTX_set_cert_store(sc->ctx_, cert_store); | ||
| 782 | + } | ||
| 783 | + | ||
| 784 | + X509_STORE_add_crl(cert_store, crl); | ||
| 785 | + X509_STORE_set_flags(cert_store, | ||
| 786 | + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); | ||
| 787 | + | ||
| 739 | 788 | BIO_free_all(bio); | |
| 740 | - X509_CRL_free(x509); | ||
| 789 | + X509_CRL_free(crl); | ||
| 741 | 790 | } | |
| 742 | 791 | ||
| 743 | 792 | ||
| 744 | - | ||
| 745 | 793 | void SecureContext::AddRootCerts(const FunctionCallbackInfo<Value>& args) { | |
| 746 | 794 | SecureContext* sc; | |
| 747 | 795 | ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); | |
| 748 | 796 | ClearErrorOnReturn clear_error_on_return; | |
| 749 | 797 | (void) &clear_error_on_return; // Silence compiler warning. | |
| 750 | 798 | ||
| 751 | - CHECK_EQ(sc->ca_store_, nullptr); | ||
| 752 | - | ||
| 753 | 799 | if (!root_cert_store) { | |
| 754 | - root_cert_store = X509_STORE_new(); | ||
| 755 | - | ||
| 756 | - for (size_t i = 0; i < arraysize(root_certs); i++) { | ||
| 757 | - BIO* bp = NodeBIO::NewFixed(root_certs[i], strlen(root_certs[i])); | ||
| 758 | - if (bp == nullptr) { | ||
| 759 | - return; | ||
| 760 | - } | ||
| 761 | - | ||
| 762 | - X509 *x509 = PEM_read_bio_X509(bp, nullptr, CryptoPemCallback, nullptr); | ||
| 763 | - if (x509 == nullptr) { | ||
| 764 | - BIO_free_all(bp); | ||
| 765 | - return; | ||
| 766 | - } | ||
| 767 | - | ||
| 768 | - X509_STORE_add_cert(root_cert_store, x509); | ||
| 769 | - | ||
| 770 | - BIO_free_all(bp); | ||
| 771 | - X509_free(x509); | ||
| 772 | - } | ||
| 800 | + root_cert_store = NewRootCertStore(); | ||
| 773 | 801 | } | |
| 774 | 802 | ||
| 775 | - sc->ca_store_ = root_cert_store; | ||
| 776 | 803 | // Increment reference count so global store is not deleted along with CTX. | |
| 777 | - CRYPTO_add(&root_cert_store->references, 1, CRYPTO_LOCK_X509_STORE); | ||
| 778 | - SSL_CTX_set_cert_store(sc->ctx_, sc->ca_store_); | ||
| 804 | + X509_STORE_up_ref(root_cert_store); | ||
| 805 | + SSL_CTX_set_cert_store(sc->ctx_, root_cert_store); | ||
| 779 | 806 | } | |
| 780 | 807 | ||
| 781 | 808 | ||
@@ -985,6 +1012,8 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) { | |||
| 985 | 1012 | sc->cert_ = nullptr; | |
| 986 | 1013 | } | |
| 987 | 1014 | ||
| 1015 | + X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_); | ||
| 1016 | + | ||
| 988 | 1017 | if (d2i_PKCS12_bio(in, &p12) && | |
| 989 | 1018 | PKCS12_parse(p12, pass, &pkey, &cert, &extra_certs) && | |
| 990 | 1019 | SSL_CTX_use_certificate_chain(sc->ctx_, | |
@@ -997,11 +1026,11 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) { | |||
| 997 | 1026 | for (int i = 0; i < sk_X509_num(extra_certs); i++) { | |
| 998 | 1027 | X509* ca = sk_X509_value(extra_certs, i); | |
| 999 | 1028 | ||
| 1000 | - if (!sc->ca_store_) { | ||
| 1001 | - sc->ca_store_ = X509_STORE_new(); | ||
| 1002 | - SSL_CTX_set_cert_store(sc->ctx_, sc->ca_store_); | ||
| 1029 | + if (cert_store == root_cert_store) { | ||
| 1030 | + cert_store = NewRootCertStore(); | ||
| 1031 | + SSL_CTX_set_cert_store(sc->ctx_, cert_store); | ||
| 1003 | 1032 | } | |
| 1004 | - X509_STORE_add_cert(sc->ca_store_, ca); | ||
| 1033 | + X509_STORE_add_cert(cert_store, ca); | ||
| 1005 | 1034 | SSL_CTX_add_client_CA(sc->ctx_, ca); | |
| 1006 | 1035 | } | |
| 1007 | 1036 | ret = true; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -76,7 +76,6 @@ class SecureContext : public BaseObject { | |||
| 76 | 76 | ||
| 77 | 77 | static void Initialize(Environment* env, v8::Local<v8::Object> target); | |
| 78 | 78 | ||
| 79 | - X509_STORE* ca_store_; | ||
| 80 | 79 | SSL_CTX* ctx_; | |
| 81 | 80 | X509* cert_; | |
| 82 | 81 | X509* issuer_; | |
@@ -131,7 +130,6 @@ class SecureContext : public BaseObject { | |||
| 131 | 130 | ||
| 132 | 131 | SecureContext(Environment* env, v8::Local<v8::Object> wrap) | |
| 133 | 132 | : BaseObject(env, wrap), | |
| 134 | - ca_store_(nullptr), | ||
| 135 | 133 | ctx_(nullptr), | |
| 136 | 134 | cert_(nullptr), | |
| 137 | 135 | issuer_(nullptr) { | |
@@ -140,20 +138,19 @@ class SecureContext : public BaseObject { | |||
| 140 | 138 | } | |
| 141 | 139 | ||
| 142 | 140 | void FreeCTXMem() { | |
| 143 | - if (ctx_) { | ||
| 144 | - env()->isolate()->AdjustAmountOfExternalAllocatedMemory(-kExternalSize); | ||
| 145 | - SSL_CTX_free(ctx_); | ||
| 146 | - if (cert_ != nullptr) | ||
| 147 | - X509_free(cert_); | ||
| 148 | - if (issuer_ != nullptr) | ||
| 149 | - X509_free(issuer_); | ||
| 150 | - ctx_ = nullptr; | ||
| 151 | - ca_store_ = nullptr; | ||
| 152 | - cert_ = nullptr; | ||
| 153 | - issuer_ = nullptr; | ||
| 154 | - } else { | ||
| 155 | - CHECK_EQ(ca_store_, nullptr); | ||
| 141 | + if (!ctx_) { | ||
| 142 | + return; | ||
| 156 | 143 | } | |
| 144 | + | ||
| 145 | + env()->isolate()->AdjustAmountOfExternalAllocatedMemory(-kExternalSize); | ||
| 146 | + SSL_CTX_free(ctx_); | ||
| 147 | + if (cert_ != nullptr) | ||
| 148 | + X509_free(cert_); | ||
| 149 | + if (issuer_ != nullptr) | ||
| 150 | + X509_free(issuer_); | ||
| 151 | + ctx_ = nullptr; | ||
| 152 | + cert_ = nullptr; | ||
| 153 | + issuer_ = nullptr; | ||
| 157 | 154 | } | |
| 158 | 155 | }; | |
| 159 | 156 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -140,3 +140,7 @@ assert.throws(function() { | |||
| 140 | 140 | ||
| 141 | 141 | // Make sure memory isn't released before being returned | |
| 142 | 142 | console.log(crypto.randomBytes(16)); | |
| 143 | + | ||
| 144 | + assert.throws(function() { | ||
| 145 | + tls.createSecureContext({ crl: 'not a CRL' }); | ||
| 146 | + }, /Failed to parse CRL/); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,62 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + const fs = require('fs'); | ||
| 4 | + | ||
| 5 | + if (!common.hasCrypto) { | ||
| 6 | + common.skip('missing crypto'); | ||
| 7 | + return; | ||
| 8 | + } | ||
| 9 | + const tls = require('tls'); | ||
| 10 | + | ||
| 11 | + function filenamePEM(n) { | ||
| 12 | + return require('path').join(common.fixturesDir, 'keys', n + '.pem'); | ||
| 13 | + } | ||
| 14 | + | ||
| 15 | + function loadPEM(n) { | ||
| 16 | + return fs.readFileSync(filenamePEM(n)); | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + const caCert = loadPEM('ca1-cert'); | ||
| 20 | + const contextWithoutCert = tls.createSecureContext({}); | ||
| 21 | + const contextWithCert = tls.createSecureContext({}); | ||
| 22 | + // Adding a CA certificate to contextWithCert should not also add it to | ||
| 23 | + // contextWithoutCert. This is tested by trying to connect to a server that | ||
| 24 | + // depends on that CA using contextWithoutCert. | ||
| 25 | + contextWithCert.context.addCACert(caCert); | ||
| 26 | + | ||
| 27 | + const serverOptions = { | ||
| 28 | + key: loadPEM('agent1-key'), | ||
| 29 | + cert: loadPEM('agent1-cert'), | ||
| 30 | + }; | ||
| 31 | + const server = tls.createServer(serverOptions, function() {}); | ||
| 32 | + | ||
| 33 | + const clientOptions = { | ||
| 34 | + port: undefined, | ||
| 35 | + ca: [caCert], | ||
| 36 | + servername: 'agent1', | ||
| 37 | + rejectUnauthorized: true, | ||
| 38 | + }; | ||
| 39 | + | ||
| 40 | + function startTest() { | ||
| 41 | + // This client should fail to connect because it doesn't trust the CA | ||
| 42 | + // certificate. | ||
| 43 | + clientOptions.secureContext = contextWithoutCert; | ||
| 44 | + clientOptions.port = server.address().port; | ||
| 45 | + const client = tls.connect(clientOptions, common.fail); | ||
| 46 | + client.on('error', common.mustCall(() => { | ||
| 47 | + client.destroy(); | ||
| 48 | + | ||
| 49 | + // This time it should connect because contextWithCert includes the needed | ||
| 50 | + // CA certificate. | ||
| 51 | + clientOptions.secureContext = contextWithCert; | ||
| 52 | + const client2 = tls.connect(clientOptions, common.mustCall(() => { | ||
| 53 | + client2.destroy(); | ||
| 54 | + server.close(); | ||
| 55 | + })); | ||
| 56 | + client2.on('error', (e) => { | ||
| 57 | + console.log(e); | ||
| 58 | + }); | ||
| 59 | + })); | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + server.listen(0, startTest); | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments