| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent e0dc0ce commit 35a660e
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -123,6 +123,7 @@ const char* const root_certs[] = { | |||
| 123 | 123 | std::string extra_root_certs_file; // NOLINT(runtime/string) | |
| 124 | 124 | ||
| 125 | 125 | X509_STORE* root_cert_store; | |
| 126 | + std::vector<X509*>* root_certs_vector; | ||
| 126 | 127 | ||
| 127 | 128 | // Just to generate static methods | |
| 128 | 129 | template class SSLWrap<TLSWrap>; | |
@@ -404,8 +405,6 @@ void SecureContext::Init(const FunctionCallbackInfo<Value>& args) { | |||
| 404 | 405 | SSL_SESS_CACHE_NO_AUTO_CLEAR); | |
| 405 | 406 | SSL_CTX_sess_set_get_cb(sc->ctx_, SSLWrap<Connection>::GetSessionCallback); | |
| 406 | 407 | SSL_CTX_sess_set_new_cb(sc->ctx_, SSLWrap<Connection>::NewSessionCallback); | |
| 407 | - | ||
| 408 | - sc->ca_store_ = nullptr; | ||
| 409 | 408 | } | |
| 410 | 409 | ||
| 411 | 410 | ||
@@ -689,8 +688,52 @@ void SecureContext::SetCert(const FunctionCallbackInfo<Value>& args) { | |||
| 689 | 688 | } | |
| 690 | 689 | ||
| 691 | 690 | ||
| 691 | + #if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) | ||
| 692 | + // This section contains OpenSSL 1.1.0 functions reimplemented for OpenSSL | ||
| 693 | + // 1.0.2 so that the following code can be written without lots of #if lines. | ||
| 694 | + | ||
| 695 | + static int X509_STORE_up_ref(X509_STORE* store) { | ||
| 696 | + CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); | ||
| 697 | + return 1; | ||
| 698 | + } | ||
| 699 | + | ||
| 700 | + static int X509_up_ref(X509* cert) { | ||
| 701 | + CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); | ||
| 702 | + return 1; | ||
| 703 | + } | ||
| 704 | + #endif // OPENSSL_VERSION_NUMBER < 0x10100000L && !OPENSSL_IS_BORINGSSL | ||
| 705 | + | ||
| 706 | + | ||
| 707 | + static X509_STORE* NewRootCertStore() { | ||
| 708 | + if (!root_certs_vector) { | ||
| 709 | + root_certs_vector = new std::vector<X509*>; | ||
| 710 | + | ||
| 711 | + for (size_t i = 0; i < arraysize(root_certs); i++) { | ||
| 712 | + BIO* bp = NodeBIO::NewFixed(root_certs[i], strlen(root_certs[i])); | ||
| 713 | + X509 *x509 = PEM_read_bio_X509(bp, nullptr, CryptoPemCallback, nullptr); | ||
| 714 | + BIO_free(bp); | ||
| 715 | + | ||
| 716 | + if (x509 == nullptr) { | ||
| 717 | + // Parse errors from the built-in roots are fatal. | ||
| 718 | + abort(); | ||
| 719 | + return nullptr; | ||
| 720 | + } | ||
| 721 | + | ||
| 722 | + root_certs_vector->push_back(x509); | ||
| 723 | + } | ||
| 724 | + } | ||
| 725 | + | ||
| 726 | + X509_STORE* store = X509_STORE_new(); | ||
| 727 | + for (auto& cert : *root_certs_vector) { | ||
| 728 | + X509_up_ref(cert); | ||
| 729 | + X509_STORE_add_cert(store, cert); | ||
| 730 | + } | ||
| 731 | + | ||
| 732 | + return store; | ||
| 733 | + } | ||
| 734 | + | ||
| 735 | + | ||
| 692 | 736 | void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) { | |
| 693 | - bool newCAStore = false; | ||
| 694 | 737 | Environment* env = Environment::GetCurrent(args); | |
| 695 | 738 | ||
| 696 | 739 | SecureContext* sc; | |
@@ -702,23 +745,24 @@ void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) { | |||
| 702 | 745 | return env->ThrowTypeError("Bad parameter"); | |
| 703 | 746 | } | |
| 704 | 747 | ||
| 705 | - if (!sc->ca_store_) { | ||
| 706 | - sc->ca_store_ = X509_STORE_new(); | ||
| 707 | - newCAStore = true; | ||
| 708 | - } | ||
| 709 | - | ||
| 710 | - X509* x509 = LoadX509(env, args[0]); | ||
| 711 | - if (!x509) | ||
| 748 | + BIO* bio = LoadBIO(env, args[0]); | ||
| 749 | + if (!bio) { | ||
| 712 | 750 | return; | |
| 751 | + } | ||
| 713 | 752 | ||
| 714 | - X509_STORE_add_cert(sc->ca_store_, x509); | ||
| 715 | - SSL_CTX_add_client_CA(sc->ctx_, x509); | ||
| 716 | - | ||
| 717 | - X509_free(x509); | ||
| 718 | - | ||
| 719 | - if (newCAStore) { | ||
| 720 | - SSL_CTX_set_cert_store(sc->ctx_, sc->ca_store_); | ||
| 753 | + X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_); | ||
| 754 | + while (X509* x509 = | ||
| 755 | + PEM_read_bio_X509(bio, nullptr, CryptoPemCallback, nullptr)) { | ||
| 756 | + if (cert_store == root_cert_store) { | ||
| 757 | + cert_store = NewRootCertStore(); | ||
| 758 | + SSL_CTX_set_cert_store(sc->ctx_, cert_store); | ||
| 759 | + } | ||
| 760 | + X509_STORE_add_cert(cert_store, x509); | ||
| 761 | + SSL_CTX_add_client_CA(sc->ctx_, x509); | ||
| 762 | + X509_free(x509); | ||
| 721 | 763 | } | |
| 764 | + | ||
| 765 | + BIO_free_all(bio); | ||
| 722 | 766 | } | |
| 723 | 767 | ||
| 724 | 768 | ||
@@ -739,19 +783,27 @@ void SecureContext::AddCRL(const FunctionCallbackInfo<Value>& args) { | |||
| 739 | 783 | if (!bio) | |
| 740 | 784 | return; | |
| 741 | 785 | ||
| 742 | - X509_CRL *x509 = | ||
| 786 | + X509_CRL* crl = | ||
| 743 | 787 | PEM_read_bio_X509_CRL(bio, nullptr, CryptoPemCallback, nullptr); | |
| 744 | 788 | ||
| 745 | - if (x509 == nullptr) { | ||
| 789 | + if (crl == nullptr) { | ||
| 790 | + return env->ThrowError("Failed to parse CRL"); | ||
| 746 | 791 | BIO_free_all(bio); | |
| 747 | 792 | return; | |
| 748 | 793 | } | |
| 749 | 794 | ||
| 750 | - X509_STORE_add_crl(sc->ca_store_, x509); | ||
| 751 | - X509_STORE_set_flags(sc->ca_store_, X509_V_FLAG_CRL_CHECK | | ||
| 752 | - X509_V_FLAG_CRL_CHECK_ALL); | ||
| 795 | + X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_); | ||
| 796 | + if (cert_store == root_cert_store) { | ||
| 797 | + cert_store = NewRootCertStore(); | ||
| 798 | + SSL_CTX_set_cert_store(sc->ctx_, cert_store); | ||
| 799 | + } | ||
| 800 | + | ||
| 801 | + X509_STORE_add_crl(cert_store, crl); | ||
| 802 | + X509_STORE_set_flags(cert_store, | ||
| 803 | + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); | ||
| 804 | + | ||
| 753 | 805 | BIO_free_all(bio); | |
| 754 | - X509_CRL_free(x509); | ||
| 806 | + X509_CRL_free(crl); | ||
| 755 | 807 | } | |
| 756 | 808 | ||
| 757 | 809 | ||
@@ -794,28 +846,8 @@ void SecureContext::AddRootCerts(const FunctionCallbackInfo<Value>& args) { | |||
| 794 | 846 | ClearErrorOnReturn clear_error_on_return; | |
| 795 | 847 | (void) &clear_error_on_return; // Silence compiler warning. | |
| 796 | 848 | ||
| 797 | - CHECK_EQ(sc->ca_store_, nullptr); | ||
| 798 | - | ||
| 799 | 849 | if (!root_cert_store) { | |
| 800 | - root_cert_store = X509_STORE_new(); | ||
| 801 | - | ||
| 802 | - for (size_t i = 0; i < arraysize(root_certs); i++) { | ||
| 803 | - BIO* bp = NodeBIO::NewFixed(root_certs[i], strlen(root_certs[i])); | ||
| 804 | - if (bp == nullptr) { | ||
| 805 | - return; | ||
| 806 | - } | ||
| 807 | - | ||
| 808 | - X509 *x509 = PEM_read_bio_X509(bp, nullptr, CryptoPemCallback, nullptr); | ||
| 809 | - if (x509 == nullptr) { | ||
| 810 | - BIO_free_all(bp); | ||
| 811 | - return; | ||
| 812 | - } | ||
| 813 | - | ||
| 814 | - X509_STORE_add_cert(root_cert_store, x509); | ||
| 815 | - | ||
| 816 | - BIO_free_all(bp); | ||
| 817 | - X509_free(x509); | ||
| 818 | - } | ||
| 850 | + root_cert_store = NewRootCertStore(); | ||
| 819 | 851 | ||
| 820 | 852 | if (!extra_root_certs_file.empty()) { | |
| 821 | 853 | unsigned long err = AddCertsFromFile( // NOLINT(runtime/int) | |
@@ -830,10 +862,9 @@ void SecureContext::AddRootCerts(const FunctionCallbackInfo<Value>& args) { | |||
| 830 | 862 | } | |
| 831 | 863 | } | |
| 832 | 864 | ||
| 833 | - sc->ca_store_ = root_cert_store; | ||
| 834 | 865 | // Increment reference count so global store is not deleted along with CTX. | |
| 835 | - CRYPTO_add(&root_cert_store->references, 1, CRYPTO_LOCK_X509_STORE); | ||
| 836 | - SSL_CTX_set_cert_store(sc->ctx_, sc->ca_store_); | ||
| 866 | + X509_STORE_up_ref(root_cert_store); | ||
| 867 | + SSL_CTX_set_cert_store(sc->ctx_, root_cert_store); | ||
| 837 | 868 | } | |
| 838 | 869 | ||
| 839 | 870 | ||
@@ -1034,6 +1065,8 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) { | |||
| 1034 | 1065 | sc->cert_ = nullptr; | |
| 1035 | 1066 | } | |
| 1036 | 1067 | ||
| 1068 | + X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_); | ||
| 1069 | + | ||
| 1037 | 1070 | if (d2i_PKCS12_bio(in, &p12) && | |
| 1038 | 1071 | PKCS12_parse(p12, pass, &pkey, &cert, &extra_certs) && | |
| 1039 | 1072 | SSL_CTX_use_certificate_chain(sc->ctx_, | |
@@ -1046,11 +1079,11 @@ void SecureContext::LoadPKCS12(const FunctionCallbackInfo<Value>& args) { | |||
| 1046 | 1079 | for (int i = 0; i < sk_X509_num(extra_certs); i++) { | |
| 1047 | 1080 | X509* ca = sk_X509_value(extra_certs, i); | |
| 1048 | 1081 | ||
| 1049 | - if (!sc->ca_store_) { | ||
| 1050 | - sc->ca_store_ = X509_STORE_new(); | ||
| 1051 | - SSL_CTX_set_cert_store(sc->ctx_, sc->ca_store_); | ||
| 1082 | + if (cert_store == root_cert_store) { | ||
| 1083 | + cert_store = NewRootCertStore(); | ||
| 1084 | + SSL_CTX_set_cert_store(sc->ctx_, cert_store); | ||
| 1052 | 1085 | } | |
| 1053 | - X509_STORE_add_cert(sc->ca_store_, ca); | ||
| 1086 | + X509_STORE_add_cert(cert_store, ca); | ||
| 1054 | 1087 | SSL_CTX_add_client_CA(sc->ctx_, ca); | |
| 1055 | 1088 | } | |
| 1056 | 1089 | 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