diff options
author | James M Snell <jasnell@gmail.com> | 2020-02-29 04:13:08 +0300 |
---|---|---|
committer | Myles Borins <mylesborins@google.com> | 2020-03-05 00:30:29 +0300 |
commit | 755da035ceff4fd3f347efba1d731fce0038f968 (patch) | |
tree | f510c9b94e77d65f338ea476a796be3b925b3ca2 /src/node_crypto.cc | |
parent | 1539928ed915f54f5c2c1a1cafdb29d3b898f897 (diff) |
src: add node_crypto_common and refactor
Two things in one on this commit:
(a) For the QUIC implementation, we need to separate out various bits
from node_crypto.cc to allow them to be reused. That's where this
commit starts.
(b) Quite a bit of the node_crypto.cc code was just messy in terms of
it's organization and lack of error handling and use of Local vs.
MaybeLocal. This cleans that up a bit and hopefully makes certain
parts a bit more manageable also.
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/32016
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
Diffstat (limited to 'src/node_crypto.cc')
-rw-r--r-- | src/node_crypto.cc | 637 |
1 files changed, 27 insertions, 610 deletions
diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 0b48821cf6c..fdaf91acdc0 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -22,6 +22,7 @@ #include "node_crypto.h" #include "node_buffer.h" #include "node_crypto_bio.h" +#include "node_crypto_common.h" #include "node_crypto_clienthello-inl.h" #include "node_crypto_groups.h" #include "node_errors.h" @@ -59,11 +60,6 @@ #include <utility> #include <vector> -static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL - | ASN1_STRFLGS_UTF8_CONVERT - | XN_FLAG_SEP_MULTILINE - | XN_FLAG_FN_SN; - namespace node { namespace crypto { @@ -75,7 +71,6 @@ using v8::Boolean; using v8::ConstructorBehavior; using v8::Context; using v8::DontDelete; -using v8::EscapableHandleScope; using v8::Exception; using v8::External; using v8::False; @@ -110,24 +105,6 @@ using v8::Value; # define IS_OCB_MODE(mode) ((mode) == EVP_CIPH_OCB_MODE) #endif -struct StackOfX509Deleter { - void operator()(STACK_OF(X509)* p) const { sk_X509_pop_free(p, X509_free); } -}; -using StackOfX509 = std::unique_ptr<STACK_OF(X509), StackOfX509Deleter>; - -struct StackOfXASN1Deleter { - void operator()(STACK_OF(ASN1_OBJECT)* p) const { - sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free); - } -}; -using StackOfASN1 = std::unique_ptr<STACK_OF(ASN1_OBJECT), StackOfXASN1Deleter>; - -// OPENSSL_free is a macro, so we need a wrapper function. -struct OpenSSLBufferDeleter { - void operator()(char* pointer) const { OPENSSL_free(pointer); } -}; -using OpenSSLBuffer = std::unique_ptr<char[], OpenSSLBufferDeleter>; - static const char* const root_certs[] = { #include "node_root_certs.h" // NOLINT(build/include_order) }; @@ -386,7 +363,7 @@ void ThrowCryptoError(Environment* env, unsigned long err, // NOLINT(runtime/int) // Default, only used if there is no SSL `err` which can // be used to create a long-style message string. - const char* message = nullptr) { + const char* message) { char message_buffer[128] = {0}; if (err != 0 || message == nullptr) { ERR_error_string_n(err, message_buffer, sizeof(message_buffer)); @@ -453,15 +430,6 @@ bool EntropySource(unsigned char* buffer, size_t length) { return RAND_bytes(buffer, length) != -1; } - -template <typename T> -static T* MallocOpenSSL(size_t count) { - void* mem = OPENSSL_malloc(MultiplyWithOverflowCheck(count, sizeof(T))); - CHECK_IMPLIES(mem == nullptr, count == 0); - return static_cast<T*>(mem); -} - - void SecureContext::Initialize(Environment* env, Local<Object> target) { Local<FunctionTemplate> t = env->NewFunctionTemplate(New); t->InstanceTemplate()->SetInternalFieldCount( @@ -831,16 +799,6 @@ void SecureContext::SetEngineKey(const FunctionCallbackInfo<Value>& args) { } #endif // !OPENSSL_NO_ENGINE -int SSL_CTX_get_issuer(SSL_CTX* ctx, X509* cert, X509** issuer) { - X509_STORE* store = SSL_CTX_get_cert_store(ctx); - DeleteFnPtr<X509_STORE_CTX, X509_STORE_CTX_free> store_ctx( - X509_STORE_CTX_new()); - return store_ctx.get() != nullptr && - X509_STORE_CTX_init(store_ctx.get(), store, nullptr, nullptr) == 1 && - X509_STORE_CTX_get1_issuer(issuer, store_ctx.get(), cert) == 1; -} - - int SSL_CTX_use_certificate_chain(SSL_CTX* ctx, X509Pointer&& x, STACK_OF(X509)* extra_certs, @@ -1893,381 +1851,6 @@ void SSLWrap<Base>::OnClientHello(void* arg, w->MakeCallback(env->onclienthello_string(), arraysize(argv), argv); } - -static bool SafeX509ExtPrint(BIO* out, X509_EXTENSION* ext) { - const X509V3_EXT_METHOD* method = X509V3_EXT_get(ext); - - if (method != X509V3_EXT_get_nid(NID_subject_alt_name)) - return false; - - GENERAL_NAMES* names = static_cast<GENERAL_NAMES*>(X509V3_EXT_d2i(ext)); - if (names == nullptr) - return false; - - for (int i = 0; i < sk_GENERAL_NAME_num(names); i++) { - GENERAL_NAME* gen = sk_GENERAL_NAME_value(names, i); - - if (i != 0) - BIO_write(out, ", ", 2); - - if (gen->type == GEN_DNS) { - ASN1_IA5STRING* name = gen->d.dNSName; - - BIO_write(out, "DNS:", 4); - BIO_write(out, name->data, name->length); - } else { - STACK_OF(CONF_VALUE)* nval = i2v_GENERAL_NAME( - const_cast<X509V3_EXT_METHOD*>(method), gen, nullptr); - if (nval == nullptr) - return false; - X509V3_EXT_val_prn(out, nval, 0, 0); - sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); - } - } - sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); - - return true; -} - - -static void AddFingerprintDigest(const unsigned char* md, - unsigned int md_size, - char (*fingerprint)[3 * EVP_MAX_MD_SIZE + 1]) { - unsigned int i; - const char hex[] = "0123456789ABCDEF"; - - for (i = 0; i < md_size; i++) { - (*fingerprint)[3*i] = hex[(md[i] & 0xf0) >> 4]; - (*fingerprint)[(3*i)+1] = hex[(md[i] & 0x0f)]; - (*fingerprint)[(3*i)+2] = ':'; - } - - if (md_size > 0) { - (*fingerprint)[(3*(md_size-1))+2] = '\0'; - } else { - (*fingerprint)[0] = '\0'; - } -} - - -static MaybeLocal<Object> ECPointToBuffer(Environment* env, - const EC_GROUP* group, - const EC_POINT* point, - point_conversion_form_t form, - const char** error) { - size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr); - if (len == 0) { - if (error != nullptr) *error = "Failed to get public key length"; - return MaybeLocal<Object>(); - } - AllocatedBuffer buf = env->AllocateManaged(len); - len = EC_POINT_point2oct(group, - point, - form, - reinterpret_cast<unsigned char*>(buf.data()), - buf.size(), - nullptr); - if (len == 0) { - if (error != nullptr) *error = "Failed to get public key"; - return MaybeLocal<Object>(); - } - return buf.ToBuffer(); -} - - -static Local<Object> X509ToObject(Environment* env, X509* cert) { - EscapableHandleScope scope(env->isolate()); - Local<Context> context = env->context(); - Local<Object> info = Object::New(env->isolate()); - - BIOPointer bio(BIO_new(BIO_s_mem())); - BUF_MEM* mem; - if (X509_NAME_print_ex(bio.get(), - X509_get_subject_name(cert), - 0, - X509_NAME_FLAGS) > 0) { - BIO_get_mem_ptr(bio.get(), &mem); - info->Set(context, env->subject_string(), - String::NewFromUtf8(env->isolate(), mem->data, - NewStringType::kNormal, - mem->length).ToLocalChecked()).Check(); - } - USE(BIO_reset(bio.get())); - - X509_NAME* issuer_name = X509_get_issuer_name(cert); - if (X509_NAME_print_ex(bio.get(), issuer_name, 0, X509_NAME_FLAGS) > 0) { - BIO_get_mem_ptr(bio.get(), &mem); - info->Set(context, env->issuer_string(), - String::NewFromUtf8(env->isolate(), mem->data, - NewStringType::kNormal, - mem->length).ToLocalChecked()).Check(); - } - USE(BIO_reset(bio.get())); - - int nids[] = { NID_subject_alt_name, NID_info_access }; - Local<String> keys[] = { env->subjectaltname_string(), - env->infoaccess_string() }; - CHECK_EQ(arraysize(nids), arraysize(keys)); - for (size_t i = 0; i < arraysize(nids); i++) { - int index = X509_get_ext_by_NID(cert, nids[i], -1); - if (index < 0) - continue; - - X509_EXTENSION* ext = X509_get_ext(cert, index); - CHECK_NOT_NULL(ext); - - if (!SafeX509ExtPrint(bio.get(), ext) && - X509V3_EXT_print(bio.get(), ext, 0, 0) != 1) { - info->Set(context, keys[i], Null(env->isolate())).Check(); - USE(BIO_reset(bio.get())); - continue; - } - - BIO_get_mem_ptr(bio.get(), &mem); - info->Set(context, keys[i], - String::NewFromUtf8(env->isolate(), mem->data, - NewStringType::kNormal, - mem->length).ToLocalChecked()).Check(); - - USE(BIO_reset(bio.get())); - } - - EVPKeyPointer pkey(X509_get_pubkey(cert)); - RSAPointer rsa; - ECPointer ec; - if (pkey) { - switch (EVP_PKEY_id(pkey.get())) { - case EVP_PKEY_RSA: - rsa.reset(EVP_PKEY_get1_RSA(pkey.get())); - break; - case EVP_PKEY_EC: - ec.reset(EVP_PKEY_get1_EC_KEY(pkey.get())); - break; - } - } - - if (rsa) { - const BIGNUM* n; - const BIGNUM* e; - RSA_get0_key(rsa.get(), &n, &e, nullptr); - BN_print(bio.get(), n); - BIO_get_mem_ptr(bio.get(), &mem); - info->Set(context, env->modulus_string(), - String::NewFromUtf8(env->isolate(), mem->data, - NewStringType::kNormal, - mem->length).ToLocalChecked()).Check(); - USE(BIO_reset(bio.get())); - - int bits = BN_num_bits(n); - info->Set(context, env->bits_string(), - Integer::New(env->isolate(), bits)).Check(); - - uint64_t exponent_word = static_cast<uint64_t>(BN_get_word(e)); - uint32_t lo = static_cast<uint32_t>(exponent_word); - uint32_t hi = static_cast<uint32_t>(exponent_word >> 32); - if (hi == 0) { - BIO_printf(bio.get(), "0x%x", lo); - } else { - BIO_printf(bio.get(), "0x%x%08x", hi, lo); - } - BIO_get_mem_ptr(bio.get(), &mem); - info->Set(context, env->exponent_string(), - String::NewFromUtf8(env->isolate(), mem->data, - NewStringType::kNormal, - mem->length).ToLocalChecked()).Check(); - USE(BIO_reset(bio.get())); - - int size = i2d_RSA_PUBKEY(rsa.get(), nullptr); - CHECK_GE(size, 0); - Local<Object> pubbuff = Buffer::New(env, size).ToLocalChecked(); - unsigned char* pubserialized = - reinterpret_cast<unsigned char*>(Buffer::Data(pubbuff)); - i2d_RSA_PUBKEY(rsa.get(), &pubserialized); - info->Set(env->context(), env->pubkey_string(), pubbuff).Check(); - } else if (ec) { - const EC_GROUP* group = EC_KEY_get0_group(ec.get()); - if (group != nullptr) { - int bits = EC_GROUP_order_bits(group); - if (bits > 0) { - info->Set(context, env->bits_string(), - Integer::New(env->isolate(), bits)).Check(); - } - } - - const EC_POINT* pubkey = EC_KEY_get0_public_key(ec.get()); - Local<Object> buf; - if (pubkey != nullptr && - ECPointToBuffer( - env, group, pubkey, EC_KEY_get_conv_form(ec.get()), nullptr) - .ToLocal(&buf)) { - info->Set(context, env->pubkey_string(), buf).Check(); - } - - const int nid = EC_GROUP_get_curve_name(group); - if (nid != 0) { - // Curve is well-known, get its OID and NIST nick-name (if it has one). - - if (const char* sn = OBJ_nid2sn(nid)) { - info->Set(context, env->asn1curve_string(), - OneByteString(env->isolate(), sn)).Check(); - } - - if (const char* nist = EC_curve_nid2nist(nid)) { - info->Set(context, env->nistcurve_string(), - OneByteString(env->isolate(), nist)).Check(); - } - } else { - // Unnamed curves can be described by their mathematical properties, - // but aren't used much (at all?) with X.509/TLS. Support later if needed. - } - } - - pkey.reset(); - rsa.reset(); - ec.reset(); - - ASN1_TIME_print(bio.get(), X509_get0_notBefore(cert)); - BIO_get_mem_ptr(bio.get(), &mem); - info->Set(context, env->valid_from_string(), - String::NewFromUtf8(env->isolate(), mem->data, - NewStringType::kNormal, - mem->length).ToLocalChecked()).Check(); - USE(BIO_reset(bio.get())); - - ASN1_TIME_print(bio.get(), X509_get0_notAfter(cert)); - BIO_get_mem_ptr(bio.get(), &mem); - info->Set(context, env->valid_to_string(), - String::NewFromUtf8(env->isolate(), mem->data, - NewStringType::kNormal, - mem->length).ToLocalChecked()).Check(); - bio.reset(); - - unsigned char md[EVP_MAX_MD_SIZE]; - unsigned int md_size; - char fingerprint[EVP_MAX_MD_SIZE * 3 + 1]; - if (X509_digest(cert, EVP_sha1(), md, &md_size)) { - AddFingerprintDigest(md, md_size, &fingerprint); - info->Set(context, env->fingerprint_string(), - OneByteString(env->isolate(), fingerprint)).Check(); - } - if (X509_digest(cert, EVP_sha256(), md, &md_size)) { - AddFingerprintDigest(md, md_size, &fingerprint); - info->Set(context, env->fingerprint256_string(), - OneByteString(env->isolate(), fingerprint)).Check(); - } - - StackOfASN1 eku(static_cast<STACK_OF(ASN1_OBJECT)*>( - X509_get_ext_d2i(cert, NID_ext_key_usage, nullptr, nullptr))); - if (eku) { - const int count = sk_ASN1_OBJECT_num(eku.get()); - MaybeStackBuffer<Local<Value>, 16> ext_key_usage(count); - char buf[256]; - - int j = 0; - for (int i = 0; i < count; i++) { - if (OBJ_obj2txt(buf, - sizeof(buf), - sk_ASN1_OBJECT_value(eku.get(), i), 1) >= 0) { - ext_key_usage[j++] = OneByteString(env->isolate(), buf); - } - } - - eku.reset(); - info->Set(context, env->ext_key_usage_string(), - Array::New(env->isolate(), ext_key_usage.out(), count)).Check(); - } - - if (ASN1_INTEGER* serial_number = X509_get_serialNumber(cert)) { - BignumPointer bn(ASN1_INTEGER_to_BN(serial_number, nullptr)); - if (bn) { - OpenSSLBuffer buf(BN_bn2hex(bn.get())); - if (buf) { - info->Set(context, env->serial_number_string(), - OneByteString(env->isolate(), buf.get())).Check(); - } - } - } - - // Raw DER certificate - int size = i2d_X509(cert, nullptr); - Local<Object> buff = Buffer::New(env, size).ToLocalChecked(); - unsigned char* serialized = reinterpret_cast<unsigned char*>( - Buffer::Data(buff)); - i2d_X509(cert, &serialized); - info->Set(context, env->raw_string(), buff).Check(); - - return scope.Escape(info); -} - - -static Local<Object> AddIssuerChainToObject(X509Pointer* cert, - Local<Object> object, - StackOfX509&& peer_certs, - Environment* const env) { - Local<Context> context = env->isolate()->GetCurrentContext(); - cert->reset(sk_X509_delete(peer_certs.get(), 0)); - for (;;) { - int i; - for (i = 0; i < sk_X509_num(peer_certs.get()); i++) { - X509* ca = sk_X509_value(peer_certs.get(), i); - if (X509_check_issued(ca, cert->get()) != X509_V_OK) - continue; - - Local<Object> ca_info = X509ToObject(env, ca); - object->Set(context, env->issuercert_string(), ca_info).Check(); - object = ca_info; - - // NOTE: Intentionally freeing cert that is not used anymore. - // Delete cert and continue aggregating issuers. - cert->reset(sk_X509_delete(peer_certs.get(), i)); - break; - } - - // Issuer not found, break out of the loop. - if (i == sk_X509_num(peer_certs.get())) - break; - } - return object; -} - - -static StackOfX509 CloneSSLCerts(X509Pointer&& cert, - const STACK_OF(X509)* const ssl_certs) { - StackOfX509 peer_certs(sk_X509_new(nullptr)); - if (cert) - sk_X509_push(peer_certs.get(), cert.release()); - for (int i = 0; i < sk_X509_num(ssl_certs); i++) { - X509Pointer cert(X509_dup(sk_X509_value(ssl_certs, i))); - if (!cert || !sk_X509_push(peer_certs.get(), cert.get())) - return StackOfX509(); - // `cert` is now managed by the stack. - cert.release(); - } - return peer_certs; -} - - -static Local<Object> GetLastIssuedCert(X509Pointer* cert, - const SSLPointer& ssl, - Local<Object> issuer_chain, - Environment* const env) { - Local<Context> context = env->isolate()->GetCurrentContext(); - while (X509_check_issued(cert->get(), cert->get()) != X509_V_OK) { - X509* ca; - if (SSL_CTX_get_issuer(SSL_get_SSL_CTX(ssl.get()), cert->get(), &ca) <= 0) - break; - - Local<Object> ca_info = X509ToObject(env, ca); - issuer_chain->Set(context, env->issuercert_string(), ca_info).Check(); - issuer_chain = ca_info; - - // Delete previous cert and continue aggregating issuers. - cert->reset(ca); - } - return issuer_chain; -} - - template <class Base> void SSLWrap<Base>::GetPeerCertificate( const FunctionCallbackInfo<Value>& args) { @@ -2275,44 +1858,11 @@ void SSLWrap<Base>::GetPeerCertificate( ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); Environment* env = w->ssl_env(); - ClearErrorOnReturn clear_error_on_return; + bool abbreviated = args.Length() < 1 || !args[0]->IsTrue(); - Local<Object> result; - // Used to build the issuer certificate chain. - Local<Object> issuer_chain; - - // NOTE: This is because of the odd OpenSSL behavior. On client `cert_chain` - // contains the `peer_certificate`, but on server it doesn't. - X509Pointer cert( - w->is_server() ? SSL_get_peer_certificate(w->ssl_.get()) : nullptr); - STACK_OF(X509)* ssl_certs = SSL_get_peer_cert_chain(w->ssl_.get()); - if (!cert && (ssl_certs == nullptr || sk_X509_num(ssl_certs) == 0)) - goto done; - - // Short result requested. - if (args.Length() < 1 || !args[0]->IsTrue()) { - result = X509ToObject(env, cert ? cert.get() : sk_X509_value(ssl_certs, 0)); - goto done; - } - - if (auto peer_certs = CloneSSLCerts(std::move(cert), ssl_certs)) { - // First and main certificate. - X509Pointer cert(sk_X509_value(peer_certs.get(), 0)); - CHECK(cert); - result = X509ToObject(env, cert.release()); - - issuer_chain = - AddIssuerChainToObject(&cert, result, std::move(peer_certs), env); - issuer_chain = GetLastIssuedCert(&cert, w->ssl_, issuer_chain, env); - // Last certificate should be self-signed. - if (X509_check_issued(cert.get(), cert.get()) == X509_V_OK) - issuer_chain->Set(env->context(), - env->issuercert_string(), - issuer_chain).Check(); - } - - done: - args.GetReturnValue().Set(result); + Local<Value> ret; + if (GetPeerCert(env, w->ssl_, abbreviated, w->is_server()).ToLocal(&ret)) + args.GetReturnValue().Set(ret); } @@ -2323,16 +1873,9 @@ void SSLWrap<Base>::GetCertificate( ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); Environment* env = w->ssl_env(); - ClearErrorOnReturn clear_error_on_return; - - Local<Object> result; - - X509* cert = SSL_get_certificate(w->ssl_.get()); - - if (cert != nullptr) - result = X509ToObject(env, cert); - - args.GetReturnValue().Set(result); + Local<Value> ret; + if (GetCert(env, w->ssl_).ToLocal(&ret)) + args.GetReturnValue().Set(ret); } @@ -2411,22 +1954,16 @@ void SSLWrap<Base>::SetSession(const FunctionCallbackInfo<Value>& args) { Base* w; ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); - if (args.Length() < 1) { + if (args.Length() < 1) return THROW_ERR_MISSING_ARGS(env, "Session argument is mandatory"); - } THROW_AND_RETURN_IF_NOT_BUFFER(env, args[0], "Session"); - ArrayBufferViewContents<unsigned char> sbuf(args[0].As<ArrayBufferView>()); - - const unsigned char* p = sbuf.data(); - SSLSessionPointer sess(d2i_SSL_SESSION(nullptr, &p, sbuf.length())); + SSLSessionPointer sess = GetTLSSession(args[0]); if (sess == nullptr) return; - int r = SSL_set_session(w->ssl_.get(), sess.get()); - - if (!r) + if (!SetTLSSession(w->ssl_, sess)) return env->ThrowError("SSL_set_session error"); } @@ -2542,7 +2079,6 @@ void SSLWrap<Base>::GetEphemeralKeyInfo( Base* w; ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); Environment* env = Environment::GetCurrent(args); - Local<Context> context = env->context(); CHECK(w->ssl_); @@ -2550,51 +2086,12 @@ void SSLWrap<Base>::GetEphemeralKeyInfo( if (w->is_server()) return args.GetReturnValue().SetNull(); - Local<Object> info = Object::New(env->isolate()); + Local<Object> ret; + if (GetEphemeralKey(env, w->ssl_).ToLocal(&ret)) + args.GetReturnValue().Set(ret); - EVP_PKEY* raw_key; - if (SSL_get_server_tmp_key(w->ssl_.get(), &raw_key)) { - EVPKeyPointer key(raw_key); - int kid = EVP_PKEY_id(key.get()); - switch (kid) { - case EVP_PKEY_DH: - info->Set(context, env->type_string(), - FIXED_ONE_BYTE_STRING(env->isolate(), "DH")).Check(); - info->Set(context, env->size_string(), - Integer::New(env->isolate(), EVP_PKEY_bits(key.get()))) - .Check(); - break; - case EVP_PKEY_EC: - case EVP_PKEY_X25519: - case EVP_PKEY_X448: - { - const char* curve_name; - if (kid == EVP_PKEY_EC) { - EC_KEY* ec = EVP_PKEY_get1_EC_KEY(key.get()); - int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); - curve_name = OBJ_nid2sn(nid); - EC_KEY_free(ec); - } else { - curve_name = OBJ_nid2sn(kid); - } - info->Set(context, env->type_string(), - FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH")).Check(); - info->Set(context, env->name_string(), - OneByteString(args.GetIsolate(), - curve_name)).Check(); - info->Set(context, env->size_string(), - Integer::New(env->isolate(), - EVP_PKEY_bits(key.get()))).Check(); - } - break; - default: - break; - } - } // TODO(@sam-github) semver-major: else return ThrowCryptoError(env, // ERR_get_error()) - - return args.GetReturnValue().Set(info); } @@ -2624,58 +2121,14 @@ void SSLWrap<Base>::VerifyError(const FunctionCallbackInfo<Value>& args) { // peer certificate is questionable but it's compatible with what was // here before. long x509_verify_error = // NOLINT(runtime/int) - X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; - if (X509* peer_cert = SSL_get_peer_certificate(w->ssl_.get())) { - X509_free(peer_cert); - x509_verify_error = SSL_get_verify_result(w->ssl_.get()); - } else { - const SSL_CIPHER* curr_cipher = SSL_get_current_cipher(w->ssl_.get()); - const SSL_SESSION* sess = SSL_get_session(w->ssl_.get()); - // Allow no-cert for PSK authentication in TLS1.2 and lower. - // In TLS1.3 check that session was reused because TLS1.3 PSK - // looks like session resumption. Is there a better way? - if (SSL_CIPHER_get_auth_nid(curr_cipher) == NID_auth_psk || - (SSL_SESSION_get_protocol_version(sess) == TLS1_3_VERSION && - SSL_session_reused(w->ssl_.get()))) - return args.GetReturnValue().SetNull(); - } + VerifyPeerCertificate(w->ssl_, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT); if (x509_verify_error == X509_V_OK) return args.GetReturnValue().SetNull(); const char* reason = X509_verify_cert_error_string(x509_verify_error); const char* code = reason; -#define CASE_X509_ERR(CODE) case X509_V_ERR_##CODE: code = #CODE; break; - switch (x509_verify_error) { - CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT) - CASE_X509_ERR(UNABLE_TO_GET_CRL) - CASE_X509_ERR(UNABLE_TO_DECRYPT_CERT_SIGNATURE) - CASE_X509_ERR(UNABLE_TO_DECRYPT_CRL_SIGNATURE) - CASE_X509_ERR(UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY) - CASE_X509_ERR(CERT_SIGNATURE_FAILURE) - CASE_X509_ERR(CRL_SIGNATURE_FAILURE) - CASE_X509_ERR(CERT_NOT_YET_VALID) - CASE_X509_ERR(CERT_HAS_EXPIRED) - CASE_X509_ERR(CRL_NOT_YET_VALID) - CASE_X509_ERR(CRL_HAS_EXPIRED) - CASE_X509_ERR(ERROR_IN_CERT_NOT_BEFORE_FIELD) - CASE_X509_ERR(ERROR_IN_CERT_NOT_AFTER_FIELD) - CASE_X509_ERR(ERROR_IN_CRL_LAST_UPDATE_FIELD) - CASE_X509_ERR(ERROR_IN_CRL_NEXT_UPDATE_FIELD) - CASE_X509_ERR(OUT_OF_MEM) - CASE_X509_ERR(DEPTH_ZERO_SELF_SIGNED_CERT) - CASE_X509_ERR(SELF_SIGNED_CERT_IN_CHAIN) - CASE_X509_ERR(UNABLE_TO_GET_ISSUER_CERT_LOCALLY) - CASE_X509_ERR(UNABLE_TO_VERIFY_LEAF_SIGNATURE) - CASE_X509_ERR(CERT_CHAIN_TOO_LONG) - CASE_X509_ERR(CERT_REVOKED) - CASE_X509_ERR(INVALID_CA) - CASE_X509_ERR(PATH_LENGTH_EXCEEDED) - CASE_X509_ERR(INVALID_PURPOSE) - CASE_X509_ERR(CERT_UNTRUSTED) - CASE_X509_ERR(CERT_REJECTED) - } -#undef CASE_X509_ERR + code = X509ErrorCode(x509_verify_error); Isolate* isolate = args.GetIsolate(); Local<String> reason_string = OneByteString(isolate, reason); @@ -2693,23 +2146,14 @@ void SSLWrap<Base>::GetCipher(const FunctionCallbackInfo<Value>& args) { Base* w; ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder()); Environment* env = w->ssl_env(); - Local<Context> context = env->context(); const SSL_CIPHER* c = SSL_get_current_cipher(w->ssl_.get()); if (c == nullptr) return; - Local<Object> info = Object::New(env->isolate()); - const char* cipher_name = SSL_CIPHER_get_name(c); - info->Set(context, env->name_string(), - OneByteString(args.GetIsolate(), cipher_name)).Check(); - const char* cipher_standard_name = SSL_CIPHER_standard_name(c); - info->Set(context, env->standard_name_string(), - OneByteString(args.GetIsolate(), cipher_standard_name)).Check(); - const char* cipher_version = SSL_CIPHER_get_version(c); - info->Set(context, env->version_string(), - OneByteString(args.GetIsolate(), cipher_version)).Check(); - args.GetReturnValue().Set(info); + Local<Object> ret; + if (GetCipherInfo(env, w->ssl_).ToLocal(&ret)) + args.GetReturnValue().Set(ret); } @@ -2904,10 +2348,7 @@ void SSLWrap<Base>::SetALPNProtocols(const FunctionCallbackInfo<Value>& args) { return env->ThrowTypeError("Must give a Buffer as first argument"); if (w->is_client()) { - ArrayBufferViewContents<unsigned char> alpn_protos(args[0]); - int r = SSL_set_alpn_protos( - w->ssl_.get(), alpn_protos.data(), alpn_protos.length()); - CHECK_EQ(r, 0); + CHECK(SetALPN(w->ssl_, args[0])); } else { CHECK( w->object()->SetPrivate( @@ -2930,18 +2371,10 @@ int SSLWrap<Base>::TLSExtStatusCallback(SSL* s, void* arg) { if (w->is_client()) { // Incoming response - const unsigned char* resp; - int len = SSL_get_tlsext_status_ocsp_resp(s, &resp); Local<Value> arg; - if (resp == nullptr) { - arg = Null(env->isolate()); - } else { - arg = - Buffer::Copy(env, reinterpret_cast<const char*>(resp), len) - .ToLocalChecked(); - } - - w->MakeCallback(env->onocspresponse_string(), 1, &arg); + MaybeLocal<Value> ret = GetSSLOCSPResponse(env, s, Null(env->isolate())); + if (ret.ToLocal(&arg)) + w->MakeCallback(env->onocspresponse_string(), 1, &arg); // No async acceptance is possible, so always return 1 to accept the // response. The listener for 'OCSPResponse' event has no control over @@ -3000,7 +2433,7 @@ int SSLWrap<Base>::SSLCertCallback(SSL* s, void* arg) { Local<Object> info = Object::New(env->isolate()); - const char* servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); + const char* servername = GetServerName(s); if (servername == nullptr) { info->Set(context, env->servername_string(), @@ -3049,23 +2482,7 @@ void SSLWrap<Base>::CertCbDone(const FunctionCallbackInfo<Value>& args) { // Store the SNI context for later use. w->sni_context_ = BaseObjectPtr<SecureContext>(sc); - int rv; - - // NOTE: reference count is not increased by this API methods - X509* x509 = SSL_CTX_get0_certificate(sc->ctx_.get()); - EVP_PKEY* pkey = SSL_CTX_get0_privatekey(sc->ctx_.get()); - STACK_OF(X509)* chain; - - rv = SSL_CTX_get0_chain_certs(sc->ctx_.get(), &chain); - if (rv) - rv = SSL_use_certificate(w->ssl_.get(), x509); - if (rv) - rv = SSL_use_PrivateKey(w->ssl_.get(), pkey); - if (rv && chain != nullptr) - rv = SSL_set1_chain(w->ssl_.get(), chain); - if (rv) - rv = w->SetCACerts(sc); - if (!rv) { + if (UseSNIContext(w->ssl_, sc) && !w->SetCACerts(sc)) { // Not clear why sometimes we throw error, and sometimes we call // onerror(). Both cause .destroy(), but onerror does a bit more. unsigned long err = ERR_get_error(); // NOLINT(runtime/int) @@ -4255,7 +3672,7 @@ void CipherBase::InitIv(const FunctionCallbackInfo<Value>& args) { reinterpret_cast<const unsigned char*>(key.get()), key.size(), iv_buf.data(), - iv_len, + static_cast<int>(iv_len), auth_tag_len); } |