From e7f1280d006dc5e50f0d3844b63b7c746ced3cb9 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 13 Sep 2018 13:55:29 +0000 Subject: [PATCH 1/2] Rebase 10.1 --- src/node_constants.cc | 12 +- src/node_crypto.cc | 294 ++++++++++++++++++--- src/node_crypto.h | 2 + .../test-tls-client-getephemeralkeyinfo.js | 6 +- 4 files changed, 271 insertions(+), 43 deletions(-) diff --git a/src/node_constants.cc b/src/node_constants.cc index b6c7bf3..28ca346 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -951,8 +951,12 @@ void DefineOpenSSLConstants(Local target) { NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_RAND); # endif -# ifdef ENGINE_METHOD_EC - NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_EC); +# ifdef ENGINE_METHOD_ECDH + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_ECDH); +# endif + +# ifdef ENGINE_METHOD_ECDSA + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_ECDSA); # endif # ifdef ENGINE_METHOD_CIPHERS @@ -963,6 +967,10 @@ void DefineOpenSSLConstants(Local target) { NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_DIGESTS); # endif +# ifdef ENGINE_METHOD_STORE + NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_STORE); +# endif + # ifdef ENGINE_METHOD_PKEY_METHS NODE_DEFINE_CONSTANT(target, ENGINE_METHOD_PKEY_METHS); # endif diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 203d6b4..7bdb1b1 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -109,6 +109,119 @@ struct OpenSSLBufferDeleter { }; using OpenSSLBuffer = std::unique_ptr; +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e, + const BIGNUM** d) { + if (n != nullptr) { + *n = r->n; + } + if (e != nullptr) { + *e = r->e; + } + if (d != nullptr) { + *d = r->d; + } +} + +static void DH_get0_pqg(const DH* dh, const BIGNUM** p, const BIGNUM** q, + const BIGNUM** g) { + if (p != nullptr) { + *p = dh->p; + } + if (q != nullptr) { + *q = dh->q; + } + if (g != nullptr) { + *g = dh->g; + } +} + +static int DH_set0_pqg(DH* dh, BIGNUM* p, BIGNUM* q, BIGNUM* g) { + if ((dh->p == nullptr && p == nullptr) || + (dh->g == nullptr && g == nullptr)) { + return 0; + } + + if (p != nullptr) { + BN_free(dh->p); + dh->p = p; + } + if (q != nullptr) { + BN_free(dh->q); + dh->q = q; + } + if (g != nullptr) { + BN_free(dh->g); + dh->g = g; + } + + return 1; +} + +static void DH_get0_key(const DH* dh, const BIGNUM** pub_key, + const BIGNUM** priv_key) { + if (pub_key != nullptr) { + *pub_key = dh->pub_key; + } + if (priv_key != nullptr) { + *priv_key = dh->priv_key; + } +} + +static int DH_set0_key(DH* dh, BIGNUM* pub_key, BIGNUM* priv_key) { + if (pub_key != nullptr) { + BN_free(dh->pub_key); + dh->pub_key = pub_key; + } + if (priv_key != nullptr) { + BN_free(dh->priv_key); + dh->priv_key = priv_key; + } + + return 1; +} + +static const SSL_METHOD* TLS_method() { return SSLv23_method(); } + +static void SSL_SESSION_get0_ticket(const SSL_SESSION* s, + const unsigned char** tick, size_t* len) { + *len = s->tlsext_ticklen; + if (tick != nullptr) { + *tick = s->tlsext_tick; + } +} + +#define SSL_get_tlsext_status_type(ssl) (ssl->tlsext_status_type) + +static int X509_STORE_up_ref(X509_STORE* store) { + CRYPTO_add(&store->references, 1, CRYPTO_LOCK_X509_STORE); + return 1; +} + +static int X509_up_ref(X509* cert) { + CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509); + return 1; +} + +#define EVP_MD_CTX_new EVP_MD_CTX_create +#define EVP_MD_CTX_free EVP_MD_CTX_destroy + +HMAC_CTX* HMAC_CTX_new() { + HMAC_CTX* ctx = Malloc(1); + HMAC_CTX_init(ctx); + return ctx; +} + +void HMAC_CTX_free(HMAC_CTX* ctx) { + if (ctx == nullptr) { + return; + } + HMAC_CTX_cleanup(ctx); + free(ctx); +} +#endif // OPENSSL_VERSION_NUMBER < 0x10100000L + + static const char* const root_certs[] = { #include "node_root_certs.h" // NOLINT(build/include_order) }; @@ -125,11 +238,19 @@ template void SSLWrap::AddMethods(Environment* env, template void SSLWrap::ConfigureSecureContext(SecureContext* sc); template void SSLWrap::SetSNIContext(SecureContext* sc); template int SSLWrap::SetCACerts(SecureContext* sc); +#if OPENSSL_VERSION_NUMBER < 0x10100000L +template SSL_SESSION* SSLWrap::GetSessionCallback( + SSL* s, + unsigned char* key, + int len, + int* copy); +#else template SSL_SESSION* SSLWrap::GetSessionCallback( SSL* s, const unsigned char* key, int len, int* copy); +#endif template int SSLWrap::NewSessionCallback(SSL* s, SSL_SESSION* sess); template void SSLWrap::OnClientHello( @@ -148,6 +269,34 @@ template int SSLWrap::SelectALPNCallback( void* arg); +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static Mutex* mutexes; + +static void crypto_threadid_cb(CRYPTO_THREADID* tid) { + static_assert(sizeof(uv_thread_t) <= sizeof(void*), + "uv_thread_t does not fit in a pointer"); + CRYPTO_THREADID_set_pointer(tid, reinterpret_cast(uv_thread_self())); +} + + +static void crypto_lock_init(void) { + mutexes = new Mutex[CRYPTO_num_locks()]; +} + + +static void crypto_lock_cb(int mode, int n, const char* file, int line) { + CHECK(!(mode & CRYPTO_LOCK) ^ !(mode & CRYPTO_UNLOCK)); + CHECK(!(mode & CRYPTO_READ) ^ !(mode & CRYPTO_WRITE)); + + auto mutex = &mutexes[n]; + if (mode & CRYPTO_LOCK) + mutex->Lock(); + else + mutex->Unlock(); +} +#endif + + static int PasswordCallback(char* buf, int size, int rwflag, void* u) { if (u) { size_t buflen = static_cast(size); @@ -381,8 +530,8 @@ void SecureContext::Init(const FunctionCallbackInfo& args) { ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); Environment* env = sc->env(); - int min_version = 0; - int max_version = 0; + // int min_version = 0; + // int max_version = 0; const SSL_METHOD* method = TLS_method(); if (args.Length() == 1 && args[0]->IsString()) { @@ -405,47 +554,47 @@ void SecureContext::Init(const FunctionCallbackInfo& args) { } else if (strcmp(*sslmethod, "SSLv3_client_method") == 0) { return env->ThrowError("SSLv3 methods disabled"); } else if (strcmp(*sslmethod, "SSLv23_method") == 0) { - method = TLS_method(); + method = SSLv23_method(); } else if (strcmp(*sslmethod, "SSLv23_server_method") == 0) { - method = TLS_server_method(); + method = SSLv23_server_method(); } else if (strcmp(*sslmethod, "SSLv23_client_method") == 0) { - method = TLS_client_method(); + method = SSLv23_client_method(); } else if (strcmp(*sslmethod, "TLSv1_method") == 0) { - min_version = TLS1_VERSION; - max_version = TLS1_VERSION; - method = TLS_method(); + // min_version = TLS1_VERSION; + // max_version = TLS1_VERSION; + method = TLSv1_method(); } else if (strcmp(*sslmethod, "TLSv1_server_method") == 0) { - min_version = TLS1_VERSION; - max_version = TLS1_VERSION; - method = TLS_server_method(); + // min_version = TLS1_VERSION; + // max_version = TLS1_VERSION; + method = TLSv1_server_method(); } else if (strcmp(*sslmethod, "TLSv1_client_method") == 0) { - min_version = TLS1_VERSION; - max_version = TLS1_VERSION; - method = TLS_client_method(); + // min_version = TLS1_VERSION; + // max_version = TLS1_VERSION; + method = TLSv1_client_method(); } else if (strcmp(*sslmethod, "TLSv1_1_method") == 0) { - min_version = TLS1_1_VERSION; - max_version = TLS1_1_VERSION; - method = TLS_method(); + // min_version = TLS1_1_VERSION; + // max_version = TLS1_1_VERSION; + method = TLSv1_1_method(); } else if (strcmp(*sslmethod, "TLSv1_1_server_method") == 0) { - min_version = TLS1_1_VERSION; - max_version = TLS1_1_VERSION; - method = TLS_server_method(); + // min_version = TLS1_1_VERSION; + // max_version = TLS1_1_VERSION; + method = TLSv1_1_server_method(); } else if (strcmp(*sslmethod, "TLSv1_1_client_method") == 0) { - min_version = TLS1_1_VERSION; - max_version = TLS1_1_VERSION; - method = TLS_client_method(); + // min_version = TLS1_1_VERSION; + // max_version = TLS1_1_VERSION; + method = TLSv1_1_client_method(); } else if (strcmp(*sslmethod, "TLSv1_2_method") == 0) { - min_version = TLS1_2_VERSION; - max_version = TLS1_2_VERSION; - method = TLS_method(); + // min_version = TLS1_2_VERSION; + // max_version = TLS1_2_VERSION; + method = TLSv1_2_method(); } else if (strcmp(*sslmethod, "TLSv1_2_server_method") == 0) { - min_version = TLS1_2_VERSION; - max_version = TLS1_2_VERSION; - method = TLS_server_method(); + // min_version = TLS1_2_VERSION; + // max_version = TLS1_2_VERSION; + method = TLSv1_2_server_method(); } else if (strcmp(*sslmethod, "TLSv1_2_client_method") == 0) { - min_version = TLS1_2_VERSION; - max_version = TLS1_2_VERSION; - method = TLS_client_method(); + // min_version = TLS1_2_VERSION; + // max_version = TLS1_2_VERSION; + method = TLSv1_2_client_method(); } else { return env->ThrowError("Unknown method"); } @@ -467,6 +616,7 @@ void SecureContext::Init(const FunctionCallbackInfo& args) { SSL_SESS_CACHE_NO_INTERNAL | SSL_SESS_CACHE_NO_AUTO_CLEAR); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L SSL_CTX_set_min_proto_version(sc->ctx_.get(), min_version); SSL_CTX_set_max_proto_version(sc->ctx_.get(), max_version); // OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was @@ -478,6 +628,7 @@ void SecureContext::Init(const FunctionCallbackInfo& args) { return env->ThrowError("Error generating ticket keys"); } SSL_CTX_set_tlsext_ticket_key_cb(sc->ctx_.get(), TicketCompatibilityCallback); +#endif } @@ -925,6 +1076,11 @@ void SecureContext::SetECDHCurve(const FunctionCallbackInfo& args) { node::Utf8Value curve(env->isolate(), args[0]); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + SSL_CTX_set_options(sc->ctx_, SSL_OP_SINGLE_ECDH_USE); + SSL_CTX_set_ecdh_auto(sc->ctx_, 1); +#endif + if (strcmp(*curve, "auto") == 0) return; @@ -1179,9 +1335,17 @@ void SecureContext::GetTicketKeys(const FunctionCallbackInfo& args) { ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); Local buff = Buffer::New(wrap->env(), 48).ToLocalChecked(); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L memcpy(Buffer::Data(buff), wrap->ticket_key_name_, 16); memcpy(Buffer::Data(buff) + 16, wrap->ticket_key_hmac_, 16); memcpy(Buffer::Data(buff) + 32, wrap->ticket_key_aes_, 16); +#else + if (SSL_CTX_get_tlsext_ticket_keys(wrap->ctx_, + Buffer::Data(buff), + Buffer::Length(buff)) != 1) { + return wrap->env()->ThrowError("Failed to fetch tls ticket keys"); + } +#endif args.GetReturnValue().Set(buff); #endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys) @@ -1205,9 +1369,17 @@ void SecureContext::SetTicketKeys(const FunctionCallbackInfo& args) { env, "Ticket keys length must be 48 bytes"); } +#if OPENSSL_VERSION_NUMBER >= 0x10100000L memcpy(wrap->ticket_key_name_, Buffer::Data(args[0]), 16); memcpy(wrap->ticket_key_hmac_, Buffer::Data(args[0]) + 16, 16); memcpy(wrap->ticket_key_aes_, Buffer::Data(args[0]) + 32, 16); +#else + if (SSL_CTX_set_tlsext_ticket_keys(wrap->ctx_, + Buffer::Data(args[0]), + Buffer::Length(args[0])) != 1) { + return env->ThrowError("Failed to fetch tls ticket keys"); + } +#endif args.GetReturnValue().Set(true); #endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys) @@ -1215,6 +1387,14 @@ void SecureContext::SetTicketKeys(const FunctionCallbackInfo& args) { void SecureContext::SetFreeListLength(const FunctionCallbackInfo& args) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + // |freelist_max_len| was removed in OpenSSL 1.1.0. In that version OpenSSL + // mallocs and frees buffers directly, without the use of a freelist. + SecureContext* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); + + wrap->ctx_->freelist_max_len = args[0]->Int32Value(); +#endif } @@ -1311,6 +1491,7 @@ int SecureContext::TicketKeyCallback(SSL* ssl, } +#if OPENSSL_VERSION_NUMBER >= 0x10100000L int SecureContext::TicketCompatibilityCallback(SSL* ssl, unsigned char* name, unsigned char* iv, @@ -1345,6 +1526,7 @@ int SecureContext::TicketCompatibilityCallback(SSL* ssl, } return 1; } +#endif template @@ -1413,11 +1595,19 @@ void SSLWrap::ConfigureSecureContext(SecureContext* sc) { } +#if OPENSSL_VERSION_NUMBER < 0x10100000L +template +SSL_SESSION* SSLWrap::GetSessionCallback(SSL* s, + unsigned char* key, + int len, + int* copy) { +#else template SSL_SESSION* SSLWrap::GetSessionCallback(SSL* s, const unsigned char* key, int len, int* copy) { +#endif Base* w = static_cast(SSL_get_app_data(s)); *copy = 0; @@ -2077,6 +2267,7 @@ void SSLWrap::GetEphemeralKeyInfo( Integer::New(env->isolate(), EVP_PKEY_bits(key))).FromJust(); break; case EVP_PKEY_EC: +#if OPENSSL_VERSION_NUMBER >= 0x10100000L // TODO(shigeki) Change this to EVP_PKEY_X25519 and add EVP_PKEY_X448 // after upgrading to 1.1.1. case NID_X25519: @@ -2097,9 +2288,24 @@ void SSLWrap::GetEphemeralKeyInfo( curve_name)).FromJust(); info->Set(context, env->size_string(), Integer::New(env->isolate(), - EVP_PKEY_bits(key))).FromJust(); + EVP_PKEY_bits(key))).FromJust(); } break; +#else + { + EC_KEY* ec = EVP_PKEY_get1_EC_KEY(key); + int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); + EC_KEY_free(ec); + info->Set(context, env->type_string(), + FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH")).FromJust(); + info->Set(context, env->name_string(), + OneByteString(args.GetIsolate(), + OBJ_nid2sn(nid))).FromJust(); + info->Set(context, env->size_string(), + Integer::New(env->isolate(), + EVP_PKEY_bits(key))).FromJust(); + } +#endif } EVP_PKEY_free(key); } @@ -2778,10 +2984,10 @@ bool CipherBase::InitAuthenticated(const char* cipher_type, int iv_len, CHECK(IsAuthenticatedMode()); MarkPopErrorOnReturn mark_pop_error_on_return; - if (!EVP_CIPHER_CTX_ctrl(ctx_.get(), - EVP_CTRL_AEAD_SET_IVLEN, - iv_len, - nullptr)) { + // TODO(tniessen) Use EVP_CTRL_AEAD_SET_IVLEN when migrating to OpenSSL 1.1.0 + static_assert(EVP_CTRL_CCM_SET_IVLEN == EVP_CTRL_GCM_SET_IVLEN, + "OpenSSL constants differ between GCM and CCM"); + if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) { env()->ThrowError("Invalid IV length"); return false; } @@ -3137,8 +3343,10 @@ bool CipherBase::Final(unsigned char** out, int* out_len) { CHECK(mode == EVP_CIPH_GCM_MODE); auth_tag_len_ = sizeof(auth_tag_); } - CHECK_EQ(1, EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_AEAD_GET_TAG, - auth_tag_len_, + // TOOD(tniessen) Use EVP_CTRL_AEAP_GET_TAG in OpenSSL 1.1.0 + static_assert(EVP_CTRL_CCM_GET_TAG == EVP_CTRL_GCM_GET_TAG, + "OpenSSL constants differ between GCM and CCM"); + CHECK_EQ(1, EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_GET_TAG, auth_tag_len_, reinterpret_cast(auth_tag_))); } } @@ -3414,12 +3622,14 @@ void Hash::HashDigest(const FunctionCallbackInfo& args) { SignBase::Error SignBase::Init(const char* sign_type) { CHECK_NULL(mdctx_); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L // Historically, "dss1" and "DSS1" were DSA aliases for SHA-1 // exposed through the public API. if (strcmp(sign_type, "dss1") == 0 || strcmp(sign_type, "DSS1") == 0) { sign_type = "SHA1"; } +#endif const EVP_MD* md = EVP_get_digestbyname(sign_type); if (md == nullptr) return kSignUnknownDigest; @@ -5124,6 +5334,12 @@ void InitCryptoOnce() { SSL_library_init(); OpenSSL_add_all_algorithms(); +#if OPENSSL_VERSION_NUMBER < 0x10100000L + crypto_lock_init(); + CRYPTO_set_locking_callback(crypto_lock_cb); + CRYPTO_THREADID_set_callback(crypto_threadid_cb); +#endif + #ifdef NODE_FIPS_MODE /* Override FIPS settings in cnf file, if needed. */ unsigned long err = 0; // NOLINT(runtime/int) diff --git a/src/node_crypto.h b/src/node_crypto.h index 86aa3ba..e850358 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -44,8 +44,10 @@ #endif // !OPENSSL_NO_ENGINE #include #include +#if OPENSSL_VERSION_NUMBER >= 0x10100000L // TODO(shigeki) Remove this after upgrading to 1.1.1 #include +#endif #include #include #include diff --git a/test/parallel/test-tls-client-getephemeralkeyinfo.js b/test/parallel/test-tls-client-getephemeralkeyinfo.js index 9432a27..411fdc7 100644 --- a/test/parallel/test-tls-client-getephemeralkeyinfo.js +++ b/test/parallel/test-tls-client-getephemeralkeyinfo.js @@ -82,18 +82,20 @@ function testECDHE256() { } function testECDHE512() { - test(521, 'ECDH', 'secp521r1', testX25519); + test(521, 'ECDH', 'secp521r1', null); ntests++; } +/* function testX25519() { test(253, 'ECDH', 'X25519', null); ntests++; } +*/ testNOT_PFS(); process.on('exit', function() { assert.strictEqual(ntests, nsuccess); - assert.strictEqual(ntests, 6); + assert.strictEqual(ntests, 5); }); -- 1.8.3.1