diff --git a/src/crypto/crypto_common.cc b/src/crypto/crypto_common.cc index a1d0dfc16ce235..59acdd82096fc8 100644 --- a/src/crypto/crypto_common.cc +++ b/src/crypto/crypto_common.cc @@ -545,6 +545,16 @@ MaybeLocal GetKeyUsage(Environment* env, X509* cert) { return Undefined(env->isolate()); } +MaybeLocal GetCurrentCipherName(Environment* env, + const SSLPointer& ssl) { + return GetCipherName(env, SSL_get_current_cipher(ssl.get())); +} + +MaybeLocal GetCurrentCipherVersion(Environment* env, + const SSLPointer& ssl) { + return GetCipherVersion(env, SSL_get_current_cipher(ssl.get())); +} + MaybeLocal GetFingerprintDigest( Environment* env, const EVP_MD* method, diff --git a/src/crypto/crypto_common.h b/src/crypto/crypto_common.h index cf26b82ba60590..99eb83aae86792 100644 --- a/src/crypto/crypto_common.h +++ b/src/crypto/crypto_common.h @@ -111,6 +111,10 @@ v8::MaybeLocal GetFingerprintDigest( X509* cert); v8::MaybeLocal GetKeyUsage(Environment* env, X509* cert); +v8::MaybeLocal GetCurrentCipherName(Environment* env, + const SSLPointer& ssl); +v8::MaybeLocal GetCurrentCipherVersion(Environment* env, + const SSLPointer& ssl); v8::MaybeLocal GetSerialNumber(Environment* env, X509* cert); diff --git a/src/crypto/crypto_context.cc b/src/crypto/crypto_context.cc index 1c02d2e9f56d56..a232e084ea34e5 100644 --- a/src/crypto/crypto_context.cc +++ b/src/crypto/crypto_context.cc @@ -32,7 +32,10 @@ using v8::HandleScope; using v8::Int32; using v8::Integer; using v8::Isolate; +using v8::Just; using v8::Local; +using v8::Maybe; +using v8::Nothing; using v8::Object; using v8::PropertyAttribute; using v8::ReadOnly; @@ -574,6 +577,22 @@ void SecureContext::SetKeylogCallback(KeylogCb cb) { SSL_CTX_set_keylog_callback(ctx_.get(), cb); } +Maybe SecureContext::UseKey(Environment* env, + std::shared_ptr key) { + if (key->GetKeyType() != KeyType::kKeyTypePrivate) { + THROW_ERR_CRYPTO_INVALID_KEYTYPE(env); + return Nothing(); + } + + ClearErrorOnReturn clear_error_on_return; + if (!SSL_CTX_use_PrivateKey(ctx_.get(), key->GetAsymmetricKey().get())) { + ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_use_PrivateKey"); + return Nothing(); + } + + return Just(true); +} + void SecureContext::SetKey(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); @@ -662,97 +681,112 @@ void SecureContext::SetEngineKey(const FunctionCallbackInfo& args) { } #endif // !OPENSSL_NO_ENGINE -void SecureContext::SetCert(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - - SecureContext* sc; - ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); - - CHECK_GE(args.Length(), 1); // Certificate argument is mandator - - BIOPointer bio(LoadBIO(env, args[0])); - if (!bio) - return; - - sc->cert_.reset(); - sc->issuer_.reset(); +Maybe SecureContext::AddCert(Environment* env, BIOPointer&& bio) { + ClearErrorOnReturn clear_error_on_return; + if (!bio) return Just(false); + cert_.reset(); + issuer_.reset(); - if (!SSL_CTX_use_certificate_chain( - sc->ctx_.get(), - std::move(bio), - &sc->cert_, - &sc->issuer_)) { - return ThrowCryptoError( - env, - ERR_get_error(), - "SSL_CTX_use_certificate_chain"); + // The SSL_CTX_use_certificate_chain call here is not from openssl, this is + // the method implemented elsewhere in this file. The naming is a bit + // confusing, unfortunately. + if (SSL_CTX_use_certificate_chain( + ctx_.get(), std::move(bio), &cert_, &issuer_) == 0) { + ThrowCryptoError(env, ERR_get_error(), "SSL_CTX_use_certificate_chain"); + return Nothing(); } + return Just(true); } -void SecureContext::AddCACert(const FunctionCallbackInfo& args) { +void SecureContext::SetCert(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); SecureContext* sc; ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); - ClearErrorOnReturn clear_error_on_return; - CHECK_GE(args.Length(), 1); // CA certificate argument is mandatory + CHECK_GE(args.Length(), 1); // Certificate argument is mandatory BIOPointer bio(LoadBIO(env, args[0])); - if (!bio) - return; + USE(sc->AddCert(env, std::move(bio))); +} - X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_.get()); +void SecureContext::SetCACert(const BIOPointer& bio) { + ClearErrorOnReturn clear_error_on_return; + if (!bio) return; + X509_STORE* cert_store = SSL_CTX_get_cert_store(ctx_.get()); while (X509Pointer x509 = X509Pointer(PEM_read_bio_X509_AUX( bio.get(), nullptr, NoPasswordCallback, nullptr))) { if (cert_store == GetOrCreateRootCertStore()) { cert_store = NewRootCertStore(); - SSL_CTX_set_cert_store(sc->ctx_.get(), cert_store); + SSL_CTX_set_cert_store(ctx_.get(), cert_store); } - X509_STORE_add_cert(cert_store, x509.get()); - SSL_CTX_add_client_CA(sc->ctx_.get(), x509.get()); + CHECK_EQ(1, X509_STORE_add_cert(cert_store, x509.get())); + CHECK_EQ(1, SSL_CTX_add_client_CA(ctx_.get(), x509.get())); } } -void SecureContext::AddCRL(const FunctionCallbackInfo& args) { +void SecureContext::AddCACert(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); SecureContext* sc; ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); - CHECK_GE(args.Length(), 1); // CRL argument is mandatory - - ClearErrorOnReturn clear_error_on_return; + CHECK_GE(args.Length(), 1); // CA certificate argument is mandatory BIOPointer bio(LoadBIO(env, args[0])); - if (!bio) - return; + sc->SetCACert(bio); +} + +Maybe SecureContext::SetCRL(Environment* env, const BIOPointer& bio) { + ClearErrorOnReturn clear_error_on_return; + if (!bio) return Just(false); DeleteFnPtr crl( PEM_read_bio_X509_CRL(bio.get(), nullptr, NoPasswordCallback, nullptr)); - if (!crl) - return THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to parse CRL"); + if (!crl) { + THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to parse CRL"); + return Nothing(); + } - X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_.get()); + X509_STORE* cert_store = SSL_CTX_get_cert_store(ctx_.get()); if (cert_store == GetOrCreateRootCertStore()) { cert_store = NewRootCertStore(); - SSL_CTX_set_cert_store(sc->ctx_.get(), cert_store); + SSL_CTX_set_cert_store(ctx_.get(), cert_store); } - X509_STORE_add_crl(cert_store, crl.get()); - X509_STORE_set_flags(cert_store, - X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); + CHECK_EQ(1, X509_STORE_add_crl(cert_store, crl.get())); + CHECK_EQ(1, + X509_STORE_set_flags( + cert_store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL)); + return Just(true); } -void SecureContext::AddRootCerts(const FunctionCallbackInfo& args) { +void SecureContext::AddCRL(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + SecureContext* sc; ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); + + CHECK_GE(args.Length(), 1); // CRL argument is mandatory + + BIOPointer bio(LoadBIO(env, args[0])); + USE(sc->SetCRL(env, bio)); +} + +void SecureContext::SetRootCerts() { ClearErrorOnReturn clear_error_on_return; - X509_STORE* store = GetOrCreateRootCertStore(); + auto store = GetOrCreateRootCertStore(); + // Increment reference count so global store is not deleted along with CTX. X509_STORE_up_ref(store); - SSL_CTX_set_cert_store(sc->ctx_.get(), store); + SSL_CTX_set_cert_store(ctx_.get(), store); +} + +void SecureContext::AddRootCerts(const FunctionCallbackInfo& args) { + SecureContext* sc; + ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder()); + sc->SetRootCerts(); } void SecureContext::SetCipherSuites(const FunctionCallbackInfo& args) { diff --git a/src/crypto/crypto_context.h b/src/crypto/crypto_context.h index 4dfd0dfa032cf7..607b0984ba647a 100644 --- a/src/crypto/crypto_context.h +++ b/src/crypto/crypto_context.h @@ -3,8 +3,9 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "crypto/crypto_util.h" #include "base_object.h" +#include "crypto/crypto_keys.h" +#include "crypto/crypto_util.h" #include "env.h" #include "memory_tracker.h" #include "v8.h" @@ -43,6 +44,10 @@ class SecureContext final : public BaseObject { const SSLCtxPointer& ctx() const { return ctx_; } + // Non-const ctx() that allows for non-default initialization of + // the SecureContext. + SSLCtxPointer& ctx() { return ctx_; } + SSLPointer CreateSSL(); void SetGetSessionCallback(GetSessionCb cb); @@ -50,6 +55,16 @@ class SecureContext final : public BaseObject { void SetNewSessionCallback(NewSessionCb cb); void SetSelectSNIContextCallback(SelectSNIContextCb cb); + inline const X509Pointer& issuer() const { return issuer_; } + inline const X509Pointer& cert() const { return cert_; } + + v8::Maybe AddCert(Environment* env, BIOPointer&& bio); + v8::Maybe SetCRL(Environment* env, const BIOPointer& bio); + v8::Maybe UseKey(Environment* env, std::shared_ptr key); + + void SetCACert(const BIOPointer& bio); + void SetRootCerts(); + // TODO(joyeecheung): track the memory used by OpenSSL types SET_NO_MEMORY_INFO() SET_MEMORY_INFO_NAME(SecureContext) diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index f5661ccedad4f7..ed633f334e25c4 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -889,33 +889,36 @@ size_t KeyObjectData::GetSymmetricKeySize() const { return symmetric_key_.size(); } +bool KeyObjectHandle::HasInstance(Environment* env, Local value) { + Local t = env->crypto_key_object_handle_constructor(); + return !t.IsEmpty() && t->HasInstance(value); +} + v8::Local KeyObjectHandle::Initialize(Environment* env) { - Local templ = env->crypto_key_object_handle_constructor(); - if (!templ.IsEmpty()) { - return templ; + Local templ = env->crypto_key_object_handle_constructor(); + if (templ.IsEmpty()) { + Isolate* isolate = env->isolate(); + templ = NewFunctionTemplate(isolate, New); + templ->InstanceTemplate()->SetInternalFieldCount( + KeyObjectHandle::kInternalFieldCount); + templ->Inherit(BaseObject::GetConstructorTemplate(env)); + + SetProtoMethod(isolate, templ, "init", Init); + SetProtoMethodNoSideEffect( + isolate, templ, "getSymmetricKeySize", GetSymmetricKeySize); + SetProtoMethodNoSideEffect( + isolate, templ, "getAsymmetricKeyType", GetAsymmetricKeyType); + SetProtoMethod(isolate, templ, "export", Export); + SetProtoMethod(isolate, templ, "exportJwk", ExportJWK); + SetProtoMethod(isolate, templ, "initECRaw", InitECRaw); + SetProtoMethod(isolate, templ, "initEDRaw", InitEDRaw); + SetProtoMethod(isolate, templ, "initJwk", InitJWK); + SetProtoMethod(isolate, templ, "keyDetail", GetKeyDetail); + SetProtoMethod(isolate, templ, "equals", Equals); + + env->set_crypto_key_object_handle_constructor(templ); } - Isolate* isolate = env->isolate(); - Local t = NewFunctionTemplate(isolate, New); - t->InstanceTemplate()->SetInternalFieldCount( - KeyObjectHandle::kInternalFieldCount); - t->Inherit(BaseObject::GetConstructorTemplate(env)); - - SetProtoMethod(isolate, t, "init", Init); - SetProtoMethodNoSideEffect( - isolate, t, "getSymmetricKeySize", GetSymmetricKeySize); - SetProtoMethodNoSideEffect( - isolate, t, "getAsymmetricKeyType", GetAsymmetricKeyType); - SetProtoMethod(isolate, t, "export", Export); - SetProtoMethod(isolate, t, "exportJwk", ExportJWK); - SetProtoMethod(isolate, t, "initECRaw", InitECRaw); - SetProtoMethod(isolate, t, "initEDRaw", InitEDRaw); - SetProtoMethod(isolate, t, "initJwk", InitJWK); - SetProtoMethod(isolate, t, "keyDetail", GetKeyDetail); - SetProtoMethod(isolate, t, "equals", Equals); - - auto function = t->GetFunction(env->context()).ToLocalChecked(); - env->set_crypto_key_object_handle_constructor(function); - return function; + return templ->GetFunction(env->context()).ToLocalChecked(); } void KeyObjectHandle::RegisterExternalReferences( diff --git a/src/crypto/crypto_keys.h b/src/crypto/crypto_keys.h index 7b9c8d7e4ff55f..eb4f5222670e89 100644 --- a/src/crypto/crypto_keys.h +++ b/src/crypto/crypto_keys.h @@ -163,6 +163,7 @@ class KeyObjectData : public MemoryRetainer { class KeyObjectHandle : public BaseObject { public: + static bool HasInstance(Environment* env, v8::Local value); static v8::Local Initialize(Environment* env); static void RegisterExternalReferences(ExternalReferenceRegistry* registry); diff --git a/src/env_properties.h b/src/env_properties.h index d621ebbd09425d..3960b0add85d79 100644 --- a/src/env_properties.h +++ b/src/env_properties.h @@ -332,6 +332,7 @@ V(contextify_global_template, v8::ObjectTemplate) \ V(contextify_wrapper_template, v8::ObjectTemplate) \ V(compiled_fn_entry_template, v8::ObjectTemplate) \ + V(crypto_key_object_handle_constructor, v8::FunctionTemplate) \ V(env_proxy_template, v8::ObjectTemplate) \ V(env_proxy_ctor_template, v8::FunctionTemplate) \ V(dir_instance_template, v8::ObjectTemplate) \ @@ -374,7 +375,6 @@ V(async_hooks_promise_resolve_function, v8::Function) \ V(buffer_prototype_object, v8::Object) \ V(crypto_key_object_constructor, v8::Function) \ - V(crypto_key_object_handle_constructor, v8::Function) \ V(crypto_key_object_private_constructor, v8::Function) \ V(crypto_key_object_public_constructor, v8::Function) \ V(crypto_key_object_secret_constructor, v8::Function) \