--- node-v8.8.1-orig/src/node_crypto.cc 2017-10-26 07:10:32.000000000 +1100 +++ node-v8.8.1/src/node_crypto.cc 2017-10-29 11:51:11.037518215 +1100 @@ -116,6 +116,120 @@ using v8::Value; +#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) + +#if !defined(OPENSSL_IS_BORINGSSL) +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; +} +#endif // !OPENSSL_IS_BORINGSSL + +#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 + // Subject DER of CNNIC ROOT CA and CNNIC EV ROOT CA are taken from // https://hg.mozilla.org/mozilla-central/file/98820360ab66/security/ // certverifier/NSSCertDBTrustDomain.cpp#l672 @@ -144,8 +258,6 @@ d2i_X509_NAME(nullptr, &cnnic_ev_p, sizeof(CNNIC_EV_ROOT_CA_SUBJECT_DATA)-1); -static Mutex* mutexes; - static const char* const root_certs[] = { #include "node_root_certs.h" // NOLINT(build/include_order) }; @@ -160,11 +272,19 @@ template void SSLWrap::InitNPN(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( @@ -204,6 +324,9 @@ void* arg); #endif // TLSEXT_TYPE_application_layer_protocol_negotiation +#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"); @@ -226,6 +349,7 @@ else mutex->Unlock(); } +#endif static int PasswordCallback(char *buf, int size, int rwflag, void *u) { @@ -429,12 +553,12 @@ ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); Environment* env = sc->env(); - const SSL_METHOD* method = SSLv23_method(); + const SSL_METHOD* method = TLS_method(); if (args.Length() == 1 && args[0]->IsString()) { const node::Utf8Value sslmethod(env->isolate(), args[0]); - // Note that SSLv2 and SSLv3 are disallowed but SSLv2_method and friends + // Note that SSLv2 and SSLv3 are disallowed but SSLv23_method and friends // are still accepted. They are OpenSSL's way of saying that all known // protocols are supported unless explicitly disabled (which we do below // for SSLv2 and SSLv3.) @@ -482,7 +606,7 @@ sc->ctx_ = SSL_CTX_new(method); SSL_CTX_set_app_data(sc->ctx_, sc); - // Disable SSLv2 in the case when method == SSLv23_method() and the + // Disable SSLv2 in the case when method == TLS_method() and the // cipher list contains SSLv2 ciphers (not the default, should be rare.) // The bundled OpenSSL doesn't have SSLv2 support but the system OpenSSL may. // SSLv3 is disabled because it's susceptible to downgrade attacks (POODLE.) @@ -496,6 +620,19 @@ SSL_SESS_CACHE_NO_AUTO_CLEAR); SSL_CTX_sess_set_get_cb(sc->ctx_, SSLWrap::GetSessionCallback); SSL_CTX_sess_set_new_cb(sc->ctx_, SSLWrap::NewSessionCallback); + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + // OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was + // exposed in the public API. To retain compatibility, install a callback + // which restores the old algorithm. + if (RAND_bytes(sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) <= 0 || + RAND_bytes(sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_)) <= 0 || + RAND_bytes(sc->ticket_key_aes_, sizeof(sc->ticket_key_aes_)) <= 0) { + return env->ThrowError("Error generating ticket keys"); + } + SSL_CTX_set_tlsext_ticket_key_cb(sc->ctx_, + SecureContext::TicketCompatibilityCallback); +#endif } @@ -573,19 +710,12 @@ int SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert, X509** issuer) { - int ret; - X509_STORE* store = SSL_CTX_get_cert_store(ctx); - X509_STORE_CTX store_ctx; - - ret = X509_STORE_CTX_init(&store_ctx, store, nullptr, nullptr); - if (!ret) - goto end; - - ret = X509_STORE_CTX_get1_issuer(issuer, &store_ctx, cert); - X509_STORE_CTX_cleanup(&store_ctx); - - end: + X509_STORE_CTX* store_ctx = X509_STORE_CTX_new(); + int ret = store_ctx != nullptr && + X509_STORE_CTX_init(store_ctx, store, nullptr, nullptr) == 1 && + X509_STORE_CTX_get1_issuer(issuer, store_ctx, cert) == 1; + X509_STORE_CTX_free(store_ctx); return ret; } @@ -676,7 +806,6 @@ x = PEM_read_bio_X509_AUX(in, nullptr, NoPasswordCallback, nullptr); if (x == nullptr) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); return 0; } @@ -687,7 +816,6 @@ // Read extra certs STACK_OF(X509)* extra_certs = sk_X509_new_null(); if (extra_certs == nullptr) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_MALLOC_FAILURE); goto done; } @@ -770,22 +898,6 @@ } -#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) -// This section contains OpenSSL 1.1.0 functions reimplemented for OpenSSL -// 1.0.2 so that the following code can be written without lots of #if lines. - -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; -} -#endif // OPENSSL_VERSION_NUMBER < 0x10100000L && !OPENSSL_IS_BORINGSSL - - static X509_STORE* NewRootCertStore() { static std::vector root_certs_vector; if (root_certs_vector.empty()) { @@ -975,8 +1087,10 @@ 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; @@ -1008,7 +1122,9 @@ if (dh == nullptr) return; - const int size = BN_num_bits(dh->p); + const BIGNUM* p; + DH_get0_pqg(dh, &p, nullptr, nullptr); + const int size = BN_num_bits(p); if (size < 1024) { return env->ThrowError("DH parameter is less than 1024 bits"); } else if (size < 2048) { @@ -1193,11 +1309,17 @@ 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) @@ -1220,11 +1342,17 @@ return env->ThrowTypeError("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) @@ -1335,6 +1463,42 @@ } +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +int SecureContext::TicketCompatibilityCallback(SSL* ssl, + unsigned char* name, + unsigned char* iv, + EVP_CIPHER_CTX* ectx, + HMAC_CTX* hctx, + int enc) { + SecureContext* sc = static_cast( + SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl))); + + if (enc) { + memcpy(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)); + if (RAND_bytes(iv, 16) <= 0 || + EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, + sc->ticket_key_aes_, iv) <= 0 || + HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_), + EVP_sha256(), nullptr) <= 0) { + return -1; + } + return 1; + } + + if (memcmp(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) != 0) { + // The ticket key name does not match. Discard the ticket. + return 0; + } + + if (EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, sc->ticket_key_aes_, + iv) <= 0 || + HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_), + EVP_sha256(), nullptr) <= 0) { + return -1; + } + return 1; +} +#endif void SecureContext::CtxGetter(Local property, @@ -1439,11 +1603,19 @@ } +#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; @@ -1620,14 +1792,17 @@ rsa = EVP_PKEY_get1_RSA(pkey); if (rsa != nullptr) { - BN_print(bio, rsa->n); + const BIGNUM* n; + const BIGNUM* e; + RSA_get0_key(rsa, &n, &e, nullptr); + BN_print(bio, n); BIO_get_mem_ptr(bio, &mem); info->Set(env->modulus_string(), String::NewFromUtf8(env->isolate(), mem->data, String::kNormalString, mem->length)); (void) BIO_reset(bio); - uint64_t exponent_word = static_cast(BN_get_word(rsa->e)); + uint64_t exponent_word = static_cast(BN_get_word(e)); uint32_t lo = static_cast(exponent_word); uint32_t hi = static_cast(exponent_word >> 32); if (hi == 0) { @@ -1953,13 +2128,18 @@ Environment* env = w->ssl_env(); SSL_SESSION* sess = SSL_get_session(w->ssl_); - if (sess == nullptr || sess->tlsext_tick == nullptr) + if (sess == nullptr) + return; + + const unsigned char *ticket; + size_t length; + SSL_SESSION_get0_ticket(sess, &ticket, &length); + + if (ticket == nullptr) return; Local buff = Buffer::Copy( - env, - reinterpret_cast(sess->tlsext_tick), - sess->tlsext_ticklen).ToLocalChecked(); + env, reinterpret_cast(ticket), length).ToLocalChecked(); args.GetReturnValue().Set(buff); } @@ -2150,9 +2330,8 @@ Local info = Object::New(env->isolate()); const char* cipher_name = SSL_CIPHER_get_name(c); info->Set(env->name_string(), OneByteString(args.GetIsolate(), cipher_name)); - const char* cipher_version = SSL_CIPHER_get_version(c); info->Set(env->version_string(), - OneByteString(args.GetIsolate(), cipher_version)); + OneByteString(args.GetIsolate(), "TLSv1/SSLv3")); args.GetReturnValue().Set(info); } @@ -2332,20 +2511,12 @@ unsigned alpn_protos_len = Buffer::Length(alpn_buffer); int status = SSL_select_next_proto(const_cast(out), outlen, alpn_protos, alpn_protos_len, in, inlen); - - switch (status) { - case OPENSSL_NPN_NO_OVERLAP: - // According to 3.2. Protocol Selection of RFC7301, - // fatal no_application_protocol alert shall be sent - // but current openssl does not support it yet. See - // https://rt.openssl.org/Ticket/Display.html?id=3463&user=guest&pass=guest - // Instead, we send a warning alert for now. - return SSL_TLSEXT_ERR_ALERT_WARNING; - case OPENSSL_NPN_NEGOTIATED: - return SSL_TLSEXT_ERR_OK; - default: - return SSL_TLSEXT_ERR_ALERT_FATAL; - } + // According to 3.2. Protocol Selection of RFC7301, fatal + // no_application_protocol alert shall be sent but OpenSSL 1.0.2 does not + // support it yet. See + // https://rt.openssl.org/Ticket/Display.html?id=3463&user=guest&pass=guest + return status == OPENSSL_NPN_NEGOTIATED ? SSL_TLSEXT_ERR_OK + : SSL_TLSEXT_ERR_NOACK; } #endif // TLSEXT_TYPE_application_layer_protocol_negotiation @@ -2486,7 +2657,7 @@ bool ocsp = false; #ifdef NODE__HAVE_TLSEXT_STATUS_CB - ocsp = s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp; + ocsp = SSL_get_tlsext_status_type(s) == TLSEXT_STATUSTYPE_ocsp; #endif info->Set(env->ocsp_request_string(), Boolean::New(env->isolate(), ocsp)); @@ -3363,7 +3534,7 @@ } #endif // NODE_FIPS_MODE - CHECK_EQ(initialised_, false); + CHECK_EQ(ctx_, nullptr); const EVP_CIPHER* const cipher = EVP_get_cipherbyname(cipher_type); if (cipher == nullptr) { return env()->ThrowError("Unknown cipher"); @@ -3381,11 +3552,11 @@ key, iv); - EVP_CIPHER_CTX_init(&ctx_); + ctx_ = EVP_CIPHER_CTX_new(); const bool encrypt = (kind_ == kCipher); - EVP_CipherInit_ex(&ctx_, cipher, nullptr, nullptr, nullptr, encrypt); + EVP_CipherInit_ex(ctx_, cipher, nullptr, nullptr, nullptr, encrypt); - int mode = EVP_CIPHER_CTX_mode(&ctx_); + int mode = EVP_CIPHER_CTX_mode(ctx_); if (encrypt && (mode == EVP_CIPH_CTR_MODE || mode == EVP_CIPH_GCM_MODE || mode == EVP_CIPH_CCM_MODE)) { ProcessEmitWarning(env(), "Use Cipheriv for counter mode of %s", @@ -3393,17 +3564,16 @@ } if (mode == EVP_CIPH_WRAP_MODE) - EVP_CIPHER_CTX_set_flags(&ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + EVP_CIPHER_CTX_set_flags(ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); - CHECK_EQ(1, EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)); + CHECK_EQ(1, EVP_CIPHER_CTX_set_key_length(ctx_, key_len)); - EVP_CipherInit_ex(&ctx_, + EVP_CipherInit_ex(ctx_, nullptr, nullptr, reinterpret_cast(key), reinterpret_cast(iv), kind_ == kCipher); - initialised_ = true; } @@ -3446,32 +3616,33 @@ return env()->ThrowError("Invalid IV length"); } - EVP_CIPHER_CTX_init(&ctx_); + ctx_ = EVP_CIPHER_CTX_new(); if (mode == EVP_CIPH_WRAP_MODE) - EVP_CIPHER_CTX_set_flags(&ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + EVP_CIPHER_CTX_set_flags(ctx_, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); const bool encrypt = (kind_ == kCipher); - EVP_CipherInit_ex(&ctx_, cipher, nullptr, nullptr, nullptr, encrypt); + EVP_CipherInit_ex(ctx_, cipher, nullptr, nullptr, nullptr, encrypt); if (is_gcm_mode && - !EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) { - EVP_CIPHER_CTX_cleanup(&ctx_); + !EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) { + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; return env()->ThrowError("Invalid IV length"); } - if (!EVP_CIPHER_CTX_set_key_length(&ctx_, key_len)) { - EVP_CIPHER_CTX_cleanup(&ctx_); + if (!EVP_CIPHER_CTX_set_key_length(ctx_, key_len)) { + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; return env()->ThrowError("Invalid key length"); } - EVP_CipherInit_ex(&ctx_, + EVP_CipherInit_ex(ctx_, nullptr, nullptr, reinterpret_cast(key), reinterpret_cast(iv), kind_ == kCipher); - initialised_ = true; } @@ -3499,8 +3670,8 @@ bool CipherBase::IsAuthenticatedMode() const { // Check if this cipher operates in an AEAD mode that we support. - CHECK_EQ(initialised_, true); - const EVP_CIPHER* const cipher = EVP_CIPHER_CTX_cipher(&ctx_); + CHECK_NE(ctx_, nullptr); + const EVP_CIPHER* const cipher = EVP_CIPHER_CTX_cipher(ctx_); int mode = EVP_CIPHER_mode(cipher); return mode == EVP_CIPH_GCM_MODE; } @@ -3512,7 +3683,7 @@ ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder()); // Only callable after Final and if encrypting. - if (cipher->initialised_ || + if (cipher->ctx_ || cipher->kind_ != kCipher || cipher->auth_tag_len_ == 0) { return env->ThrowError("Attempting to get auth tag in unsupported state"); @@ -3533,7 +3704,7 @@ CipherBase* cipher; ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder()); - if (!cipher->initialised_ || + if (!cipher->ctx_ || !cipher->IsAuthenticatedMode() || cipher->kind_ != kDecipher) { return env->ThrowError("Attempting to set auth tag in unsupported state"); @@ -3551,10 +3722,10 @@ bool CipherBase::SetAAD(const char* data, unsigned int len) { - if (!initialised_ || !IsAuthenticatedMode()) + if (!ctx_ || !IsAuthenticatedMode()) return false; int outlen; - if (!EVP_CipherUpdate(&ctx_, + if (!EVP_CipherUpdate(ctx_, nullptr, &outlen, reinterpret_cast(data), @@ -3582,21 +3753,21 @@ int len, unsigned char** out, int* out_len) { - if (!initialised_) + if (!ctx_) return 0; // on first update: if (kind_ == kDecipher && IsAuthenticatedMode() && auth_tag_len_ > 0) { - EVP_CIPHER_CTX_ctrl(&ctx_, + EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_TAG, auth_tag_len_, reinterpret_cast(auth_tag_)); auth_tag_len_ = 0; } - *out_len = len + EVP_CIPHER_CTX_block_size(&ctx_); + *out_len = len + EVP_CIPHER_CTX_block_size(ctx_); *out = Malloc(static_cast(*out_len)); - return EVP_CipherUpdate(&ctx_, + return EVP_CipherUpdate(ctx_, *out, out_len, reinterpret_cast(data), @@ -3644,9 +3815,9 @@ bool CipherBase::SetAutoPadding(bool auto_padding) { - if (!initialised_) + if (!ctx_) return false; - return EVP_CIPHER_CTX_set_padding(&ctx_, auto_padding); + return EVP_CIPHER_CTX_set_padding(ctx_, auto_padding); } @@ -3662,22 +3833,22 @@ bool CipherBase::Final(unsigned char** out, int *out_len) { - if (!initialised_) + if (!ctx_) return false; *out = Malloc( - static_cast(EVP_CIPHER_CTX_block_size(&ctx_))); - int r = EVP_CipherFinal_ex(&ctx_, *out, out_len); + static_cast(EVP_CIPHER_CTX_block_size(ctx_))); + int r = EVP_CipherFinal_ex(ctx_, *out, out_len); if (r == 1 && kind_ == kCipher && IsAuthenticatedMode()) { auth_tag_len_ = sizeof(auth_tag_); - r = EVP_CIPHER_CTX_ctrl(&ctx_, EVP_CTRL_GCM_GET_TAG, auth_tag_len_, + r = EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_GET_TAG, auth_tag_len_, reinterpret_cast(auth_tag_)); CHECK_EQ(r, 1); } - EVP_CIPHER_CTX_cleanup(&ctx_); - initialised_ = false; + EVP_CIPHER_CTX_free(ctx_); + ctx_ = nullptr; return r == 1; } @@ -3688,7 +3859,7 @@ CipherBase* cipher; ASSIGN_OR_RETURN_UNWRAP(&cipher, args.Holder()); - if (!cipher->initialised_) return env->ThrowError("Unsupported state"); + if (!cipher->ctx_) return env->ThrowError("Unsupported state"); unsigned char* out_value = nullptr; int out_len = -1; @@ -3720,6 +3891,11 @@ } +Hmac::~Hmac() { + HMAC_CTX_free(ctx_); +} + + void Hmac::Initialize(Environment* env, v8::Local target) { Local t = env->NewFunctionTemplate(New); @@ -3747,14 +3923,16 @@ if (md == nullptr) { return env()->ThrowError("Unknown message digest"); } - HMAC_CTX_init(&ctx_); if (key_len == 0) { key = ""; } - if (!HMAC_Init_ex(&ctx_, key, key_len, md, nullptr)) { + ctx_ = HMAC_CTX_new(); + if (ctx_ == nullptr || + !HMAC_Init_ex(ctx_, key, key_len, md, nullptr)) { + HMAC_CTX_free(ctx_); + ctx_ = nullptr; return ThrowCryptoError(env(), ERR_get_error()); } - initialised_ = true; } @@ -3778,9 +3956,9 @@ bool Hmac::HmacUpdate(const char* data, int len) { - if (!initialised_) + if (!ctx_) return false; - int r = HMAC_Update(&ctx_, reinterpret_cast(data), len); + int r = HMAC_Update(ctx_, reinterpret_cast(data), len); return r == 1; } @@ -3831,10 +4009,10 @@ unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len = 0; - if (hmac->initialised_) { - HMAC_Final(&hmac->ctx_, md_value, &md_len); - HMAC_CTX_cleanup(&hmac->ctx_); - hmac->initialised_ = false; + if (hmac->ctx_) { + HMAC_Final(hmac->ctx_, md_value, &md_len); + HMAC_CTX_free(hmac->ctx_); + hmac->ctx_ = nullptr; } Local error; @@ -3853,6 +4031,11 @@ } +Hash::~Hash() { + EVP_MD_CTX_free(mdctx_); +} + + void Hash::Initialize(Environment* env, v8::Local target) { Local t = env->NewFunctionTemplate(New); @@ -3887,20 +4070,22 @@ const EVP_MD* md = EVP_get_digestbyname(hash_type); if (md == nullptr) return false; - EVP_MD_CTX_init(&mdctx_); - if (EVP_DigestInit_ex(&mdctx_, md, nullptr) <= 0) { + mdctx_ = EVP_MD_CTX_new(); + if (mdctx_ == nullptr || + EVP_DigestInit_ex(mdctx_, md, nullptr) <= 0) { + EVP_MD_CTX_free(mdctx_); + mdctx_ = nullptr; return false; } - initialised_ = true; finalized_ = false; return true; } bool Hash::HashUpdate(const char* data, int len) { - if (!initialised_) + if (!mdctx_) return false; - EVP_DigestUpdate(&mdctx_, data, len); + EVP_DigestUpdate(mdctx_, data, len); return true; } @@ -3965,8 +4150,7 @@ unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len; - EVP_DigestFinal_ex(&hash->mdctx_, md_value, &md_len); - EVP_MD_CTX_cleanup(&hash->mdctx_); + EVP_DigestFinal_ex(hash->mdctx_, md_value, &md_len); hash->finalized_ = true; Local error; @@ -3985,6 +4169,46 @@ } +SignBase::~SignBase() { + EVP_MD_CTX_free(mdctx_); +} + + +SignBase::Error SignBase::Init(const char* sign_type) { + CHECK_EQ(mdctx_, nullptr); +#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; + + mdctx_ = EVP_MD_CTX_new(); + if (mdctx_ == nullptr || + !EVP_DigestInit_ex(mdctx_, md, nullptr)) { + EVP_MD_CTX_free(mdctx_); + mdctx_ = nullptr; + return kSignInit; + } + + return kSignOk; +} + + +SignBase::Error SignBase::Update(const char* data, int len) { + if (!mdctx_) + return kSignNotInitialised; + if (!EVP_DigestUpdate(mdctx_, data, len)) + return kSignUpdate; + return kSignOk; +} + + void SignBase::CheckThrow(SignBase::Error error) { HandleScope scope(env()->isolate()); @@ -4058,21 +4282,6 @@ } -SignBase::Error Sign::SignInit(const char* sign_type) { - CHECK_EQ(initialised_, false); - const EVP_MD* md = EVP_get_digestbyname(sign_type); - if (md == nullptr) - return kSignUnknownDigest; - - EVP_MD_CTX_init(&mdctx_); - if (!EVP_DigestInit_ex(&mdctx_, md, nullptr)) - return kSignInit; - initialised_ = true; - - return kSignOk; -} - - void Sign::SignInit(const FunctionCallbackInfo& args) { Sign* sign; ASSIGN_OR_RETURN_UNWRAP(&sign, args.Holder()); @@ -4085,16 +4294,7 @@ THROW_AND_RETURN_IF_NOT_STRING(args[0], "Sign type"); const node::Utf8Value sign_type(args.GetIsolate(), args[0]); - sign->CheckThrow(sign->SignInit(*sign_type)); -} - - -SignBase::Error Sign::SignUpdate(const char* data, int len) { - if (!initialised_) - return kSignNotInitialised; - if (!EVP_DigestUpdate(&mdctx_, data, len)) - return kSignUpdate; - return kSignOk; + sign->CheckThrow(sign->Init(*sign_type)); } @@ -4112,11 +4312,11 @@ StringBytes::InlineDecoder decoder; if (!decoder.Decode(env, args[0].As(), args[1], UTF8)) return; - err = sign->SignUpdate(decoder.out(), decoder.size()); + err = sign->Update(decoder.out(), decoder.size()); } else { char* buf = Buffer::Data(args[0]); size_t buflen = Buffer::Length(args[0]); - err = sign->SignUpdate(buf, buflen); + err = sign->Update(buf, buflen); } sign->CheckThrow(err); @@ -4160,7 +4360,7 @@ unsigned int* sig_len, int padding, int salt_len) { - if (!initialised_) + if (!mdctx_) return kSignNotInitialised; BIO* bp = nullptr; @@ -4205,18 +4405,17 @@ } #endif // NODE_FIPS_MODE - if (Node_SignFinal(&mdctx_, sig, sig_len, pkey, padding, salt_len)) + if (Node_SignFinal(mdctx_, sig, sig_len, pkey, padding, salt_len)) fatal = false; - initialised_ = false; - exit: if (pkey != nullptr) EVP_PKEY_free(pkey); if (bp != nullptr) BIO_free_all(bp); - EVP_MD_CTX_cleanup(&mdctx_); + EVP_MD_CTX_free(mdctx_); + mdctx_ = nullptr; if (fatal) return kSignPrivateKey; @@ -4291,21 +4490,6 @@ } -SignBase::Error Verify::VerifyInit(const char* verify_type) { - CHECK_EQ(initialised_, false); - const EVP_MD* md = EVP_get_digestbyname(verify_type); - if (md == nullptr) - return kSignUnknownDigest; - - EVP_MD_CTX_init(&mdctx_); - if (!EVP_DigestInit_ex(&mdctx_, md, nullptr)) - return kSignInit; - initialised_ = true; - - return kSignOk; -} - - void Verify::VerifyInit(const FunctionCallbackInfo& args) { Verify* verify; ASSIGN_OR_RETURN_UNWRAP(&verify, args.Holder()); @@ -4318,18 +4502,7 @@ THROW_AND_RETURN_IF_NOT_STRING(args[0], "Verify type"); const node::Utf8Value verify_type(args.GetIsolate(), args[0]); - verify->CheckThrow(verify->VerifyInit(*verify_type)); -} - - -SignBase::Error Verify::VerifyUpdate(const char* data, int len) { - if (!initialised_) - return kSignNotInitialised; - - if (!EVP_DigestUpdate(&mdctx_, data, len)) - return kSignUpdate; - - return kSignOk; + verify->CheckThrow(verify->Init(*verify_type)); } @@ -4347,11 +4520,11 @@ StringBytes::InlineDecoder decoder; if (!decoder.Decode(env, args[0].As(), args[1], UTF8)) return; - err = verify->VerifyUpdate(decoder.out(), decoder.size()); + err = verify->Update(decoder.out(), decoder.size()); } else { char* buf = Buffer::Data(args[0]); size_t buflen = Buffer::Length(args[0]); - err = verify->VerifyUpdate(buf, buflen); + err = verify->Update(buf, buflen); } verify->CheckThrow(err); @@ -4365,7 +4538,7 @@ int padding, int saltlen, bool* verify_result) { - if (!initialised_) + if (!mdctx_) return kSignNotInitialised; EVP_PKEY* pkey = nullptr; @@ -4410,7 +4583,7 @@ goto exit; } - if (!EVP_DigestFinal_ex(&mdctx_, m, &m_len)) { + if (!EVP_DigestFinal_ex(mdctx_, m, &m_len)) { goto exit; } @@ -4423,7 +4596,7 @@ goto err; if (!ApplyRSAOptions(pkey, pkctx, padding, saltlen)) goto err; - if (EVP_PKEY_CTX_set_signature_md(pkctx, mdctx_.digest) <= 0) + if (EVP_PKEY_CTX_set_signature_md(pkctx, EVP_MD_CTX_md(mdctx_)) <= 0) goto err; r = EVP_PKEY_verify(pkctx, reinterpret_cast(sig), @@ -4442,8 +4615,8 @@ if (x509 != nullptr) X509_free(x509); - EVP_MD_CTX_cleanup(&mdctx_); - initialised_ = false; + EVP_MD_CTX_free(mdctx_); + mdctx_ = nullptr; if (fatal) return kSignPublicKey; @@ -4695,10 +4868,15 @@ bool DiffieHellman::Init(const char* p, int p_len, int g) { dh = DH_new(); - dh->p = BN_bin2bn(reinterpret_cast(p), p_len, 0); - dh->g = BN_new(); - if (!BN_set_word(dh->g, g)) + BIGNUM* bn_p = + BN_bin2bn(reinterpret_cast(p), p_len, nullptr); + BIGNUM* bn_g = BN_new(); + if (!BN_set_word(bn_g, g) || + !DH_set0_pqg(dh, bn_p, nullptr, bn_g)) { + BN_free(bn_p); + BN_free(bn_g); return false; + } bool result = VerifyContext(); if (!result) return false; @@ -4709,8 +4887,13 @@ bool DiffieHellman::Init(const char* p, int p_len, const char* g, int g_len) { dh = DH_new(); - dh->p = BN_bin2bn(reinterpret_cast(p), p_len, 0); - dh->g = BN_bin2bn(reinterpret_cast(g), g_len, 0); + BIGNUM *bn_p = BN_bin2bn(reinterpret_cast(p), p_len, 0); + BIGNUM *bn_g = BN_bin2bn(reinterpret_cast(g), g_len, 0); + if (!DH_set0_pqg(dh, bn_p, nullptr, bn_g)) { + BN_free(bn_p); + BN_free(bn_g); + return false; + } bool result = VerifyContext(); if (!result) return false; @@ -4798,22 +4981,25 @@ return ThrowCryptoError(env, ERR_get_error(), "Key generation failed"); } - size_t size = BN_num_bytes(diffieHellman->dh->pub_key); + const BIGNUM* pub_key; + DH_get0_key(diffieHellman->dh, &pub_key, nullptr); + size_t size = BN_num_bytes(pub_key); char* data = Malloc(size); - BN_bn2bin(diffieHellman->dh->pub_key, reinterpret_cast(data)); + BN_bn2bin(pub_key, reinterpret_cast(data)); args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked()); } void DiffieHellman::GetField(const FunctionCallbackInfo& args, - BIGNUM* (DH::*field), const char* err_if_null) { + const BIGNUM* (*get_field)(const DH*), + const char* err_if_null) { Environment* env = Environment::GetCurrent(args); DiffieHellman* dh; ASSIGN_OR_RETURN_UNWRAP(&dh, args.Holder()); if (!dh->initialised_) return env->ThrowError("Not initialized"); - const BIGNUM* num = (dh->dh)->*field; + const BIGNUM* num = get_field(dh->dh); if (num == nullptr) return env->ThrowError(err_if_null); size_t size = BN_num_bytes(num); @@ -4823,24 +5009,38 @@ } void DiffieHellman::GetPrime(const FunctionCallbackInfo& args) { - GetField(args, &DH::p, "p is null"); + GetField(args, [](const DH* dh) -> const BIGNUM* { + const BIGNUM* p; + DH_get0_pqg(dh, &p, nullptr, nullptr); + return p; + }, "p is null"); } void DiffieHellman::GetGenerator(const FunctionCallbackInfo& args) { - GetField(args, &DH::g, "g is null"); + GetField(args, [](const DH* dh) -> const BIGNUM* { + const BIGNUM* g; + DH_get0_pqg(dh, nullptr, nullptr, &g); + return g; + }, "g is null"); } void DiffieHellman::GetPublicKey(const FunctionCallbackInfo& args) { - GetField(args, &DH::pub_key, - "No public key - did you forget to generate one?"); + GetField(args, [](const DH* dh) -> const BIGNUM* { + const BIGNUM* pub_key; + DH_get0_key(dh, &pub_key, nullptr); + return pub_key; + }, "No public key - did you forget to generate one?"); } void DiffieHellman::GetPrivateKey(const FunctionCallbackInfo& args) { - GetField(args, &DH::priv_key, - "No private key - did you forget to generate one?"); + GetField(args, [](const DH* dh) -> const BIGNUM* { + const BIGNUM* priv_key; + DH_get0_key(dh, nullptr, &priv_key); + return priv_key; + }, "No private key - did you forget to generate one?"); } @@ -4916,16 +5116,14 @@ args.GetReturnValue().Set(rc); } - void DiffieHellman::SetKey(const v8::FunctionCallbackInfo& args, - BIGNUM* (DH::*field), const char* what) { + void (*set_field)(DH*, BIGNUM*), const char* what) { Environment* env = Environment::GetCurrent(args); DiffieHellman* dh; ASSIGN_OR_RETURN_UNWRAP(&dh, args.Holder()); if (!dh->initialised_) return env->ThrowError("Not initialized"); - BIGNUM** num = &((dh->dh)->*field); char errmsg[64]; if (args.Length() == 0) { @@ -4938,19 +5136,28 @@ return env->ThrowTypeError(errmsg); } - *num = BN_bin2bn(reinterpret_cast(Buffer::Data(args[0])), - Buffer::Length(args[0]), *num); - CHECK_NE(*num, nullptr); + BIGNUM* num = + BN_bin2bn(reinterpret_cast(Buffer::Data(args[0])), + Buffer::Length(args[0]), nullptr); + CHECK_NE(num, nullptr); + set_field(dh->dh, num); } void DiffieHellman::SetPublicKey(const FunctionCallbackInfo& args) { - SetKey(args, &DH::pub_key, "Public key"); + SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, num, nullptr); }, + "Public key"); } - void DiffieHellman::SetPrivateKey(const FunctionCallbackInfo& args) { - SetKey(args, &DH::priv_key, "Private key"); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + OPENSSL_VERSION_NUMBER < 0x10100070L +// Older versions of OpenSSL 1.1.0 have a DH_set0_key which does not work for +// Node. See https://github.com/openssl/openssl/pull/4384. +#error "OpenSSL 1.1.0 revisions before 1.1.0g are not supported" +#endif + SetKey(args, [](DH* dh, BIGNUM* num) { DH_set0_key(dh, nullptr, num); }, + "Private key"); } @@ -5738,7 +5945,7 @@ void GetSSLCiphers(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - SSL_CTX* ctx = SSL_CTX_new(TLSv1_server_method()); + SSL_CTX* ctx = SSL_CTX_new(TLS_method()); if (ctx == nullptr) { return env->ThrowError("SSL_CTX_new() failed."); } @@ -6028,9 +6235,11 @@ 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. */ --- node-v8.8.1-orig/src/node_crypto_bio.cc 2017-10-26 07:10:33.000000000 +1100 +++ node-v8.8.1/src/node_crypto_bio.cc 2017-10-29 11:51:11.003518215 +1100 @@ -29,24 +29,20 @@ namespace node { namespace crypto { -const BIO_METHOD NodeBIO::method = { - BIO_TYPE_MEM, - "node.js SSL buffer", - NodeBIO::Write, - NodeBIO::Read, - NodeBIO::Puts, - NodeBIO::Gets, - NodeBIO::Ctrl, - NodeBIO::New, - NodeBIO::Free, - nullptr -}; +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define BIO_set_data(bio, data) bio->ptr = data +#define BIO_get_data(bio) bio->ptr +#define BIO_set_shutdown(bio, shutdown_) bio->shutdown = shutdown_ +#define BIO_get_shutdown(bio) bio->shutdown +#define BIO_set_init(bio, init_) bio->init = init_ +#define BIO_get_init(bio) bio->init +#endif BIO* NodeBIO::New() { // The const_cast doesn't violate const correctness. OpenSSL's usage of // BIO_METHOD is effectively const but BIO_new() takes a non-const argument. - return BIO_new(const_cast(&method)); + return BIO_new(const_cast(GetMethod())); } @@ -71,12 +67,11 @@ int NodeBIO::New(BIO* bio) { - bio->ptr = new NodeBIO(); + BIO_set_data(bio, new NodeBIO()); // XXX Why am I doing it?! - bio->shutdown = 1; - bio->init = 1; - bio->num = -1; + BIO_set_shutdown(bio, 1); + BIO_set_init(bio, 1); return 1; } @@ -86,10 +81,10 @@ if (bio == nullptr) return 0; - if (bio->shutdown) { - if (bio->init && bio->ptr != nullptr) { + if (BIO_get_shutdown(bio)) { + if (BIO_get_init(bio) && BIO_get_data(bio) != nullptr) { delete FromBIO(bio); - bio->ptr = nullptr; + BIO_set_data(bio, nullptr); } } @@ -98,13 +93,13 @@ int NodeBIO::Read(BIO* bio, char* out, int len) { - int bytes; BIO_clear_retry_flags(bio); - bytes = FromBIO(bio)->Read(out, len); + NodeBIO* nbio = FromBIO(bio); + int bytes = nbio->Read(out, len); if (bytes == 0) { - bytes = bio->num; + bytes = nbio->eof_return(); if (bytes != 0) { BIO_set_retry_read(bio); } @@ -162,7 +157,7 @@ int NodeBIO::Gets(BIO* bio, char* out, int size) { - NodeBIO* nbio = FromBIO(bio); + NodeBIO* nbio = FromBIO(bio); if (nbio->Length() == 0) return 0; @@ -202,7 +197,7 @@ ret = nbio->Length() == 0; break; case BIO_C_SET_BUF_MEM_EOF_RETURN: - bio->num = num; + nbio->set_eof_return(num); break; case BIO_CTRL_INFO: ret = nbio->Length(); @@ -217,10 +212,10 @@ ret = 0; break; case BIO_CTRL_GET_CLOSE: - ret = bio->shutdown; + ret = BIO_get_shutdown(bio); break; case BIO_CTRL_SET_CLOSE: - bio->shutdown = num; + BIO_set_shutdown(bio, num); break; case BIO_CTRL_WPENDING: ret = 0; @@ -242,6 +237,41 @@ } +const BIO_METHOD* NodeBIO::GetMethod() { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + static const BIO_METHOD method = { + BIO_TYPE_MEM, + "node.js SSL buffer", + Write, + Read, + Puts, + Gets, + Ctrl, + New, + Free, + nullptr + }; + + return &method; +#else + static BIO_METHOD* method = nullptr; + + if (method == nullptr) { + method = BIO_meth_new(BIO_TYPE_MEM, "node.js SSL buffer"); + BIO_meth_set_write(method, Write); + BIO_meth_set_read(method, Read); + BIO_meth_set_puts(method, Puts); + BIO_meth_set_gets(method, Gets); + BIO_meth_set_ctrl(method, Ctrl); + BIO_meth_set_create(method, New); + BIO_meth_set_destroy(method, Free); + } + + return method; +#endif +} + + void NodeBIO::TryMoveReadHead() { // `read_pos_` and `write_pos_` means the position of the reader and writer // inside the buffer, respectively. When they're equal - its safe to reset @@ -489,5 +519,12 @@ write_head_ = nullptr; } + +NodeBIO* NodeBIO::FromBIO(BIO* bio) { + CHECK_NE(BIO_get_data(bio), nullptr); + return static_cast(BIO_get_data(bio)); +} + + } // namespace crypto } // namespace node --- node-v8.8.1-orig/src/node_crypto_bio.h 2017-10-26 07:10:33.000000000 +1100 +++ node-v8.8.1/src/node_crypto_bio.h 2017-10-29 11:51:11.004518215 +1100 @@ -39,6 +39,7 @@ NodeBIO() : env_(nullptr), initial_(kInitialBufferLength), length_(0), + eof_return_(-1), read_head_(nullptr), write_head_(nullptr) { } @@ -97,14 +98,19 @@ return length_; } + inline void set_eof_return(int num) { + eof_return_ = num; + } + + inline int eof_return() { + return eof_return_; + } + inline void set_initial(size_t initial) { initial_ = initial; } - static inline NodeBIO* FromBIO(BIO* bio) { - CHECK_NE(bio->ptr, nullptr); - return static_cast(bio->ptr); - } + static NodeBIO* FromBIO(BIO* bio); private: static int New(BIO* bio); @@ -116,12 +122,12 @@ static long Ctrl(BIO* bio, int cmd, long num, // NOLINT(runtime/int) void* ptr); + static const BIO_METHOD* GetMethod(); + // Enough to handle the most of the client hellos static const size_t kInitialBufferLength = 1024; static const size_t kThroughputBufferLength = 16384; - static const BIO_METHOD method; - class Buffer { public: Buffer(Environment* env, size_t len) : env_(env), @@ -153,6 +159,7 @@ Environment* env_; size_t initial_; size_t length_; + int eof_return_; Buffer* read_head_; Buffer* write_head_; }; --- node-v8.8.1-orig/src/node_crypto.h 2017-10-26 07:10:32.000000000 +1100 +++ node-v8.8.1/src/node_crypto.h 2017-10-29 14:06:40.775558946 +1100 @@ -53,8 +53,6 @@ #include #include -#define EVP_F_EVP_DECRYPTFINAL 101 - #if !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb) # define NODE__HAVE_TLSEXT_STATUS_CB #endif // !defined(OPENSSL_NO_TLSEXT) && defined(SSL_CTX_set_tlsext_status_cb) @@ -107,8 +105,20 @@ static const int kTicketKeyNameIndex = 3; static const int kTicketKeyIVIndex = 4; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + unsigned char ticket_key_name_[16]; + unsigned char ticket_key_aes_[16]; + unsigned char ticket_key_hmac_[16]; +#endif + protected: +#if OPENSSL_VERSION_NUMBER < 0x10100000L static const int64_t kExternalSize = sizeof(SSL_CTX); +#else + // OpenSSL 1.1.0 has opaque structures. This is an estimate based on the size + // as of OpenSSL 1.1.0f. + static const int64_t kExternalSize = 872; +#endif static void New(const v8::FunctionCallbackInfo& args); static void Init(const v8::FunctionCallbackInfo& args); @@ -146,6 +156,15 @@ HMAC_CTX* hctx, int enc); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + static int TicketCompatibilityCallback(SSL* ssl, + unsigned char* name, + unsigned char* iv, + EVP_CIPHER_CTX* ectx, + HMAC_CTX* hctx, + int enc); +#endif + SecureContext(Environment* env, v8::Local wrap) : BaseObject(env, wrap), ctx_(nullptr), @@ -222,19 +241,32 @@ protected: typedef void (*CertCb)(void* arg); +#if OPENSSL_VERSION_NUMBER < 0x10100000L // Size allocated by OpenSSL: one for SSL structure, one for SSL3_STATE and // some for buffers. // NOTE: Actually it is much more than this static const int64_t kExternalSize = sizeof(SSL) + sizeof(SSL3_STATE) + 42 * 1024; +#else + // OpenSSL 1.1.0 has opaque structures. This is an estimate based on the size + // as of OpenSSL 1.1.0f. + static const int64_t kExternalSize = 4448 + 1024 + 42 * 1024; +#endif static void InitNPN(SecureContext* sc); static void AddMethods(Environment* env, v8::Local t); +#if OPENSSL_VERSION_NUMBER < 0x10100000L static SSL_SESSION* GetSessionCallback(SSL* s, unsigned char* key, int len, int* copy); +#else + static SSL_SESSION* GetSessionCallback(SSL* s, + const unsigned char* key, + int len, + int* copy); +#endif static int NewSessionCallback(SSL* s, SSL_SESSION* sess); static void OnClientHello(void* arg, const ClientHelloParser::ClientHello& hello); @@ -425,9 +457,7 @@ class CipherBase : public BaseObject { public: ~CipherBase() override { - if (!initialised_) - return; - EVP_CIPHER_CTX_cleanup(&ctx_); + EVP_CIPHER_CTX_free(ctx_); } static void Initialize(Environment* env, v8::Local target); @@ -466,15 +496,14 @@ v8::Local wrap, CipherKind kind) : BaseObject(env, wrap), - initialised_(false), + ctx_(nullptr), kind_(kind), auth_tag_len_(0) { MakeWeak(this); } private: - EVP_CIPHER_CTX ctx_; /* coverity[member_decl] */ - bool initialised_; + EVP_CIPHER_CTX* ctx_; const CipherKind kind_; unsigned int auth_tag_len_; char auth_tag_[EVP_GCM_TLS_TAG_LEN]; @@ -482,11 +511,7 @@ class Hmac : public BaseObject { public: - ~Hmac() override { - if (!initialised_) - return; - HMAC_CTX_cleanup(&ctx_); - } + ~Hmac() override; static void Initialize(Environment* env, v8::Local target); @@ -501,22 +526,17 @@ Hmac(Environment* env, v8::Local wrap) : BaseObject(env, wrap), - initialised_(false) { + ctx_(nullptr) { MakeWeak(this); } private: - HMAC_CTX ctx_; /* coverity[member_decl] */ - bool initialised_; + HMAC_CTX* ctx_; }; class Hash : public BaseObject { public: - ~Hash() override { - if (!initialised_) - return; - EVP_MD_CTX_cleanup(&mdctx_); - } + ~Hash() override; static void Initialize(Environment* env, v8::Local target); @@ -530,13 +550,13 @@ Hash(Environment* env, v8::Local wrap) : BaseObject(env, wrap), - initialised_(false) { + mdctx_(nullptr), + finalized_(false) { MakeWeak(this); } private: - EVP_MD_CTX mdctx_; /* coverity[member_decl] */ - bool initialised_; + EVP_MD_CTX* mdctx_; bool finalized_; }; @@ -554,28 +574,24 @@ SignBase(Environment* env, v8::Local wrap) : BaseObject(env, wrap), - initialised_(false) { + mdctx_(nullptr) { } - ~SignBase() override { - if (!initialised_) - return; - EVP_MD_CTX_cleanup(&mdctx_); - } + ~SignBase() override; + + Error Init(const char* sign_type); + Error Update(const char* data, int len); protected: void CheckThrow(Error error); - EVP_MD_CTX mdctx_; /* coverity[member_decl] */ - bool initialised_; + EVP_MD_CTX* mdctx_; }; class Sign : public SignBase { public: static void Initialize(Environment* env, v8::Local target); - Error SignInit(const char* sign_type); - Error SignUpdate(const char* data, int len); Error SignFinal(const char* key_pem, int key_pem_len, const char* passphrase, @@ -599,8 +615,6 @@ public: static void Initialize(Environment* env, v8::Local target); - Error VerifyInit(const char* verify_type); - Error VerifyUpdate(const char* data, int len); Error VerifyFinal(const char* key_pem, int key_pem_len, const char* sig, @@ -690,9 +704,10 @@ private: static void GetField(const v8::FunctionCallbackInfo& args, - BIGNUM* (DH::*field), const char* err_if_null); + const BIGNUM* (*get_field)(const DH*), + const char* err_if_null); static void SetKey(const v8::FunctionCallbackInfo& args, - BIGNUM* (DH::*field), const char* what); + void (*set_field)(DH*, BIGNUM*), const char* what); bool VerifyContext(); bool initialised_; --- node-v8.8.1-orig/test/parallel/test-crypto-dh.js 2017-10-26 07:10:33.000000000 +1100 +++ node-v8.8.1/test/parallel/test-crypto-dh.js 2017-10-29 11:51:11.008518215 +1100 @@ -58,6 +58,19 @@ assert.strictEqual(secret1, secret3); +// computeSecret works without a public key set at all. +const dh4 = crypto.createDiffieHellman(p1, 'buffer'); +dh4.setPrivateKey(privkey1); + +assert.deepStrictEqual(dh1.getPrime(), dh4.getPrime()); +assert.deepStrictEqual(dh1.getGenerator(), dh4.getGenerator()); +assert.deepStrictEqual(dh1.getPrivateKey(), dh4.getPrivateKey()); +assert.strictEqual(dh4.verifyError, 0); + +const secret4 = dh4.computeSecret(key2, 'hex', 'base64'); + +assert.strictEqual(secret1, secret4); + const wrongBlockLength = /^Error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length$/; --- node-v8.8.1-orig/doc/api/tls.md 2017-10-26 07:10:31.000000000 +1100 +++ node-v8.8.1/doc/api/tls.md 2017-10-29 11:51:11.023518215 +1100 @@ -575,12 +575,12 @@ added: v0.11.4 --> -Returns an object representing the cipher name and the SSL/TLS protocol version -that first defined the cipher. +Returns an object representing the cipher name. The `version` key is a legacy +field which always contains the value `'TLSv1/SSLv3'`. For example: `{ name: 'AES256-SHA', version: 'TLSv1/SSLv3' }` -See `SSL_CIPHER_get_name()` and `SSL_CIPHER_get_version()` in +See `SSL_CIPHER_get_name()` in https://www.openssl.org/docs/man1.0.2/ssl/SSL_CIPHER_get_name.html for more information. --- node-v8.8.1-orig/test/parallel/test-crypto.js 2017-10-26 07:10:33.000000000 +1100 +++ node-v8.8.1/test/parallel/test-crypto.js 2017-10-29 11:51:11.027518215 +1100 @@ -129,12 +129,12 @@ assert(tlsCiphers.every((value) => noCapitals.test(value))); validateList(tlsCiphers); -// Assert that we have sha and sha1 but not SHA and SHA1. +// Assert that we have sha1 and sha256 but not SHA1 and SHA256. assert.notStrictEqual(0, crypto.getHashes().length); assert(crypto.getHashes().includes('sha1')); -assert(crypto.getHashes().includes('sha')); +assert(crypto.getHashes().includes('sha256')); assert(!crypto.getHashes().includes('SHA1')); -assert(!crypto.getHashes().includes('SHA')); +assert(!crypto.getHashes().includes('SHA156')); assert(crypto.getHashes().includes('RSA-SHA1')); assert(!crypto.getHashes().includes('rsa-sha1')); validateList(crypto.getHashes()); @@ -257,7 +257,7 @@ // Throws crypto error, so there is an opensslErrorStack property. // The openSSL stack should have content. if ((err instanceof Error) && - /asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag/.test(err) && + /asn1 encoding routines:[^:]*:wrong tag/.test(err) && err.opensslErrorStack !== undefined && Array.isArray(err.opensslErrorStack) && err.opensslErrorStack.length > 0) { --- node-v8.8.1-orig/test/parallel/test-tls-junk-server.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-tls-junk-server.js 2017-10-29 11:51:11.026518215 +1100 @@ -21,7 +21,9 @@ req.end(); req.once('error', common.mustCall(function(err) { - assert(/unknown protocol/.test(err.message)); + // OpenSSL 1.0.x and 1.1.x use different error messages for junk inputs. + assert(/unknown protocol/.test(err.message) || + /wrong version number/.test(err.message)); server.close(); })); }); --- node-v8.8.1-orig/test/parallel/test-tls-no-sslv3.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-tls-no-sslv3.js 2017-10-29 11:51:11.026518215 +1100 @@ -46,6 +46,8 @@ common.printSkipMessage('`openssl s_client -ssl3` not supported.'); } else { assert.strictEqual(errors.length, 1); - assert(/:wrong version number/.test(errors[0].message)); + // OpenSSL 1.0.x and 1.1.x report invalid client versions differently. + assert(/:wrong version number/.test(errors[0].message) || + /:version too low/.test(errors[0].message)); } }); --- node-v8.8.1-orig/test/parallel/test-tls-server-failed-handshake-emits-clienterror.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-tls-server-failed-handshake-emits-clienterror.js 2017-10-29 11:51:11.026518215 +1100 @@ -20,8 +20,10 @@ }).on('tlsClientError', common.mustCall(function(e) { assert.ok(e instanceof Error, 'Instance of Error should be passed to error handler'); + // OpenSSL 1.0.x and 1.1.x use different error codes for junk inputs. assert.ok( - /SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol/.test(e.message), + /SSL routines:[^:]*:(unknown protocol|wrong version number)/.test( + e.message), 'Expecting SSL unknown protocol'); server.close(); --- node-v8.8.1-orig/test/parallel/test-tls-socket-failed-handshake-emits-error.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-tls-socket-failed-handshake-emits-error.js 2017-10-29 11:51:11.027518215 +1100 @@ -20,8 +20,10 @@ s.on('error', common.mustCall(function(e) { assert.ok(e instanceof Error, 'Instance of Error should be passed to error handler'); + // OpenSSL 1.0.x and 1.1.x use different error codes for junk inputs. assert.ok( - /SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol/.test(e.message), + /SSL routines:[^:]*:(unknown protocol|wrong version number)/.test( + e.message), 'Expecting SSL unknown protocol'); })); --- node-v8.8.1-orig/test/parallel/test-tls-cert-regression.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-tls-cert-regression.js 2017-10-29 11:51:11.030518215 +1100 @@ -27,29 +27,43 @@ const tls = require('tls'); - const cert = `-----BEGIN CERTIFICATE----- -MIIBfjCCASgCCQDmmNjAojbDQjANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMCAXDTE0MDExNjE3NTMxM1oYDzIyODcxMDMxMTc1MzEzWjBFMQsw -CQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJu -ZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAPKwlfMX -6HGZIt1xm7fna72eWcOYfUfSxSugghvqYgJt2Oi3lH+wsU1O9FzRIVmpeIjDXhbp -Mjsa1HtzSiccPXsCAwEAATANBgkqhkiG9w0BAQUFAANBAHOoKy0NkyfiYH7Ne5ka -uvCyndyeB4d24FlfqEUlkfaWCZlNKRaV9YhLDiEg3BcIreFo4brtKQfZzTRs0GVm -KHg= +MIIDNDCCAp2gAwIBAgIJAJvXLQpGPpm7MA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV +BAYTAkdCMRAwDgYDVQQIEwdHd3luZWRkMREwDwYDVQQHEwhXYXVuZmF3cjEUMBIG +A1UEChMLQWNrbmFjayBMdGQxEjAQBgNVBAsTCVRlc3QgQ2VydDESMBAGA1UEAxMJ +bG9jYWxob3N0MB4XDTA5MTEwMjE5MzMwNVoXDTEwMTEwMjE5MzMwNVowcDELMAkG +A1UEBhMCR0IxEDAOBgNVBAgTB0d3eW5lZGQxETAPBgNVBAcTCFdhdW5mYXdyMRQw +EgYDVQQKEwtBY2tuYWNrIEx0ZDESMBAGA1UECxMJVGVzdCBDZXJ0MRIwEAYDVQQD +Ewlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANdym7nGe2yw +6LlJfJrQtC5TmKOGrSXiyolYCbGOy4xZI4KD31d3097jhlQFJyF+10gwkE62DuJe +fLvBZDUsvLe1R8bzlVhZnBVn+3QJyUIWQAL+DsRj8P3KoD7k363QN5dIaA1GOAg2 +vZcPy1HCUsvOgvDXGRUCZqNLAyt+h/cpAgMBAAGjgdUwgdIwHQYDVR0OBBYEFK4s +VBV4shKUj3UX/fvSJnFaaPBjMIGiBgNVHSMEgZowgZeAFK4sVBV4shKUj3UX/fvS +JnFaaPBjoXSkcjBwMQswCQYDVQQGEwJHQjEQMA4GA1UECBMHR3d5bmVkZDERMA8G +A1UEBxMIV2F1bmZhd3IxFDASBgNVBAoTC0Fja25hY2sgTHRkMRIwEAYDVQQLEwlU +ZXN0IENlcnQxEjAQBgNVBAMTCWxvY2FsaG9zdIIJAJvXLQpGPpm7MAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAFxR7BA1mUlsYqPiogtxSIfLzHWh+s0bJ +SBuhNrHes4U8QxS8+x/KWjd/81gzsf9J1C2VzTlFaydAgigz3SkQYgs+TMnFkT2o +9jqoJrcdf4WpZ2DQXUALaZgwNzPumMUSx8Ac5gO+BY/RHyP6fCodYvdNwyKslnI3 +US7eCSHZsVo= -----END CERTIFICATE-----`; const key = `-----BEGIN RSA PRIVATE KEY----- -MIIBPQIBAAJBAPKwlfMX6HGZIt1xm7fna72eWcOYfUfSxSugghvqYgJt2Oi3lH+w -sU1O9FzRIVmpeIjDXhbpMjsa1HtzSiccPXsCAwEAAQJBAM4uU9aJE0OfdE1p/X+K -LrCT3XMdFCJ24GgmHyOURtwDy18upQJecDVdcZp16fjtOPmaW95GoYRyifB3R4I5 -RxECIQD7jRM9slCSVV8xp9kOJQNpHjhRQYVGBn+pyllS2sb+RQIhAPb7Y+BIccri -NWnuhwCW8hA7Fkj/kaBdAwyW7L3Tvui/AiEAiqLCovMecre4Yi6GcsQ1b/6mvSmm -IOS+AT6zIfXPTB0CIQCJKGR3ymN/Qw5crL1GQ41cHCQtF9ickOq/lBUW+j976wIh -AOaJnkQrmurlRdePX6LvN/LgGAQoxwovfjcOYNnZsIVY +MIICXgIBAAKBgQDXcpu5xntssOi5SXya0LQuU5ijhq0l4sqJWAmxjsuMWSOCg99X +d9Pe44ZUBSchftdIMJBOtg7iXny7wWQ1LLy3tUfG85VYWZwVZ/t0CclCFkAC/g7E +Y/D9yqA+5N+t0DeXSGgNRjgINr2XD8tRwlLLzoLw1xkVAmajSwMrfof3KQIDAQAB +AoGBAIBHR/tT93ce2mJAJAXV0AJpWc+7x2pwX2FpXtQujnlxNZhnRlrBCRCD7h4m +t0bVS/86kyGaesBDvAbavfx/N5keYzzmmSp5Ht8IPqKPydGWdigk4x90yWvktai7 +dWuRKF94FXr0GUuBONb/dfHdp4KBtzN7oIF9WydYGGXA9ZmBAkEA8/k01bfwQZIu +AgcdNEM94Zcug1gSspXtUu8exNQX4+PNVbadghZb1+OnUO4d3gvWfqvAnaXD3KV6 +N4OtUhQQ0QJBAOIRbKMfaymQ9yE3CQQxYfKmEhHXWARXVwuYqIFqjmhSjSXx0l/P +7mSHz1I9uDvxkJev8sQgu1TKIyTOdqPH1tkCQQDPa6H1yYoj1Un0Q2Qa2Mg1kTjk +Re6vkjPQ/KcmJEOjZjtekgFbZfLzmwLXFXqjG2FjFFaQMSxR3QYJSJQEYjbhAkEA +sy7OZcjcXnjZeEkv61Pc57/7qIp/6Aj2JGnefZ1gvI1Z9Q5kCa88rA/9Iplq8pA4 +ZBKAoDW1ZbJGAsFmxc/6mQJAdPilhci0qFN86IGmf+ZBnwsDflIwHKDaVofti4wQ +sPWhSOb9VQjMXekI4Y2l8fqAVTS2Fn6+8jkVKxXBywSVCw== -----END RSA PRIVATE KEY-----`; function test(cert, key, cb) { --- node-v8.8.1-orig/test/parallel/test-tls-econnreset.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-tls-econnreset.js 2017-10-29 11:51:11.030518215 +1100 @@ -25,72 +25,28 @@ common.skip('missing crypto'); const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const net = require('net'); const tls = require('tls'); -const cacert = -`-----BEGIN CERTIFICATE----- -MIIBxTCCAX8CAnXnMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD -VQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQU3Ryb25n -TG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRowGAYDVQQDExFjYS5zdHJv -bmdsb29wLmNvbTAeFw0xNDAxMTcyMjE1MDdaFw00MTA2MDMyMjE1MDdaMH0xCzAJ -BgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZ -MBcGA1UEChMQU3Ryb25nTG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRow -GAYDVQQDExFjYS5zdHJvbmdsb29wLmNvbTBMMA0GCSqGSIb3DQEBAQUAAzsAMDgC -MQDKbQ6rIR5t1q1v4Ha36jrq0IkyUohy9EYNvLnXUly1PGqxby0ILlAVJ8JawpY9 -AVkCAwEAATANBgkqhkiG9w0BAQUFAAMxALA1uS4CqQXRSAyYTfio5oyLGz71a+NM -+0AFLBwh5AQjhGd0FcenU4OfHxyDEOJT/Q== ------END CERTIFICATE-----`; - -const cert = -`-----BEGIN CERTIFICATE----- -MIIBfDCCATYCAgQaMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNVBAYTAlVTMQswCQYD -VQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQU3Ryb25n -TG9vcCwgSW5jLjESMBAGA1UECxMJU3Ryb25nT3BzMRowGAYDVQQDExFjYS5zdHJv -bmdsb29wLmNvbTAeFw0xNDAxMTcyMjE1MDdaFw00MTA2MDMyMjE1MDdaMBkxFzAV -BgNVBAMTDnN0cm9uZ2xvb3AuY29tMEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxAMfk -I0LWU15pPUwIQNMnRVhhOibi0TQmAau8FBtgwEfGK01WpfGUaJr1a41K8Uq7xwID -AQABoxkwFzAVBgNVHREEDjAMhwQAAAAAhwR/AAABMA0GCSqGSIb3DQEBBQUAAzEA -cGpYrhkrb7mIh9DNhV0qp7pGjqBzlHqB7KQXw2luLDp//6dyHBMexDCQznkhZKRU ------END CERTIFICATE-----`; - -const key = -`-----BEGIN RSA PRIVATE KEY----- -MIH0AgEAAjEAx+QjQtZTXmk9TAhA0ydFWGE6JuLRNCYBq7wUG2DAR8YrTVal8ZRo -mvVrjUrxSrvHAgMBAAECMBCGccvSwC2r8Z9Zh1JtirQVxaL1WWpAQfmVwLe0bAgg -/JWMU/6hS36TsYyZMxwswQIZAPTAfht/zDLb7Hwgu2twsS1Ra9w/yyvtlwIZANET -26votwJAHK1yUrZGA5nnp5qcmQ/JUQIZAII5YV/UUZvF9D/fUplJ7puENPWNY9bN -pQIZAMMwxuS3XiO7two2sQF6W+JTYyX1DPCwAQIZAOYg1TvEGT38k8e8jygv8E8w -YqrWTeQFNQ== ------END RSA PRIVATE KEY-----`; - -const ca = [ cert, cacert ]; - let clientError = null; -let connectError = null; -const server = tls.createServer({ ca: ca, cert: cert, key: key }, () => { - assert.fail('should be unreachable'); -}).on('tlsClientError', function(err, conn) { +const server = tls.createServer({ + cert: fixtures.readKey('agent1-cert.pem'), + key: fixtures.readKey('agent1-key.pem'), +}, common.mustNotCall()).on('tlsClientError', function(err, conn) { assert(!clientError && conn); clientError = err; + server.close(); }).listen(0, function() { - const options = { - ciphers: 'AES128-GCM-SHA256', - port: this.address().port, - ca: ca - }; - tls.connect(options).on('error', function(err) { - assert(!connectError); - - connectError = err; + net.connect(this.address().port, function() { + // Destroy the socket once it is connected, so the server sees ECONNRESET. this.destroy(); - server.close(); - }).write('123'); + }).on('error', common.mustNotCall()); }); process.on('exit', function() { assert(clientError); - assert(connectError); assert(/socket hang up/.test(clientError.message)); assert(/ECONNRESET/.test(clientError.code)); }); --- node-v8.8.1-orig/test/parallel/test-https-connect-address-family.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-https-connect-address-family.js 2017-10-29 11:51:11.032518215 +1100 @@ -7,12 +7,15 @@ common.skip('no IPv6 support'); const assert = require('assert'); +const fixtures = require('../common/fixtures'); const https = require('https'); const dns = require('dns'); function runTest() { - const ciphers = 'AECDH-NULL-SHA'; - https.createServer({ ciphers }, common.mustCall(function(req, res) { + https.createServer({ + cert: fixtures.readKey('agent1-cert.pem'), + key: fixtures.readKey('agent1-key.pem'), + }, common.mustCall(function(req, res) { this.close(); res.end(); })).listen(0, '::1', common.mustCall(function() { @@ -20,7 +23,6 @@ host: 'localhost', port: this.address().port, family: 6, - ciphers: ciphers, rejectUnauthorized: false, }; // Will fail with ECONNREFUSED if the address family is not honored. --- node-v8.8.1-orig/test/parallel/test-tls-connect-address-family.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-tls-connect-address-family.js 2017-10-29 11:51:11.033518215 +1100 @@ -7,19 +7,21 @@ common.skip('no IPv6 support'); const assert = require('assert'); +const fixtures = require('../common/fixtures'); const tls = require('tls'); const dns = require('dns'); function runTest() { - const ciphers = 'AECDH-NULL-SHA'; - tls.createServer({ ciphers }, common.mustCall(function() { + tls.createServer({ + cert: fixtures.readKey('agent1-cert.pem'), + key: fixtures.readKey('agent1-key.pem'), + }, common.mustCall(function() { this.close(); })).listen(0, '::1', common.mustCall(function() { const options = { host: 'localhost', port: this.address().port, family: 6, - ciphers: ciphers, rejectUnauthorized: false, }; // Will fail with ECONNREFUSED if the address family is not honored. --- node-v8.8.1-orig/src/node_constants.cc 2017-10-26 07:10:32.000000000 +1100 +++ node-v8.8.1/src/node_constants.cc 2017-10-29 11:51:11.033518215 +1100 @@ -755,6 +755,10 @@ } void DefineOpenSSLConstants(Local target) { +#ifdef OPENSSL_VERSION_NUMBER + NODE_DEFINE_CONSTANT(target, OPENSSL_VERSION_NUMBER); +#endif + #ifdef SSL_OP_ALL NODE_DEFINE_CONSTANT(target, SSL_OP_ALL); #endif --- node-v8.8.1-orig/test/parallel/test-https-agent-session-eviction.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-https-agent-session-eviction.js 2017-10-29 11:51:11.034518215 +1100 @@ -8,7 +8,8 @@ const assert = require('assert'); const https = require('https'); -const SSL_OP_NO_TICKET = require('crypto').constants.SSL_OP_NO_TICKET; +const { OPENSSL_VERSION_NUMBER, SSL_OP_NO_TICKET } = + require('crypto').constants; const options = { key: readKey('agent1-key.pem'), @@ -58,14 +59,25 @@ res.resume(); }); - // Let it fail - req.on('error', common.mustCall(function(err) { - assert(/wrong version number/.test(err.message)); - - req.on('close', function() { - third(server); - }); - })); + if (OPENSSL_VERSION_NUMBER >= 0x10100000) { + // Although we have a TLS 1.2 session to offer to the TLS 1.0 server, + // connection to the TLS 1.0 server should work. + req.on('response', common.mustCall(function(res) { + // The test is now complete for OpenSSL 1.1.0. + server.close(); + })); + } else { + // OpenSSL 1.0.x mistakenly locked versions based on the session it was + // offering. This causes this sequent request to fail. Let it fail, but + // test that this is mitigated on the next try by invalidating the session. + req.on('error', common.mustCall(function(err) { + assert(/wrong version number/.test(err.message)); + + req.on('close', function() { + third(server); + }); + })); + } req.end(); } --- node-v8.8.1-orig/test/parallel/test-http2-create-client-connect.js 2017-10-26 07:10:33.000000000 +1100 +++ node-v8.8.1/test/parallel/test-http2-create-client-connect.js 2017-10-29 11:51:11.037518215 +1100 @@ -3,6 +3,7 @@ // Tests http2.connect() const common = require('../common'); +const Countdown = require('../common/countdown'); if (!common.hasCrypto) common.skip('missing crypto'); const fixtures = require('../common/fixtures'); @@ -25,13 +26,12 @@ [{ port: port, hostname: '127.0.0.1' }, { protocol: 'http:' }] ]; - let count = items.length; + const serverClose = new Countdown(items.length + 1, + () => setImmediate(() => server.close())); const maybeClose = common.mustCall((client) => { client.destroy(); - if (--count === 0) { - setImmediate(() => server.close()); - } + serverClose.dec(); }, items.length); items.forEach((i) => { @@ -42,7 +42,7 @@ // Will fail because protocol does not match the server. h2.connect({ port: port, protocol: 'https:' }) - .on('socketError', common.mustCall()); + .on('socketError', common.mustCall(() => serverClose.dec())); })); } @@ -70,13 +70,12 @@ [{ port: port, hostname: '127.0.0.1', protocol: 'https:' }, opts] ]; - let count = items.length; + const serverClose = new Countdown(items.length, + () => setImmediate(() => server.close())); const maybeClose = common.mustCall((client) => { client.destroy(); - if (--count === 0) { - setImmediate(() => server.close()); - } + serverClose.dec(); }, items.length); items.forEach((i) => { --- node-v8.8.1-orig/test/parallel/test-tls-ecdh-disable.js 2017-10-26 07:10:34.000000000 +1100 +++ node-v8.8.1/test/parallel/test-tls-ecdh-disable.js 2017-10-29 11:51:11.038518215 +1100 @@ -27,6 +27,11 @@ if (!common.opensslCli) common.skip('missing openssl-cli'); +const OPENSSL_VERSION_NUMBER = + require('crypto').constants.OPENSSL_VERSION_NUMBER; +if (OPENSSL_VERSION_NUMBER >= 0x10100000) + common.skip('false ecdhCurve not supported in OpenSSL 1.1.0') + const assert = require('assert'); const tls = require('tls'); const exec = require('child_process').exec;