Skip to content

Commit

Permalink
src: update src/crypto to support quic
Browse files Browse the repository at this point in the history
  • Loading branch information
jasnell committed Oct 16, 2022
1 parent 79b0396 commit 80e3d21
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 52 deletions.
24 changes: 21 additions & 3 deletions src/crypto/crypto_common.cc
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "crypto/crypto_common.h"
#include "base_object-inl.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "node.h"
#include "node_buffer.h"
#include "node_crypto.h"
#include "crypto/crypto_common.h"
#include "node.h"
#include "node_internals.h"
#include "node_url.h"
#include "openssl/ssl.h"
#include "string_bytes.h"
#include "memory_tracker-inl.h"
#include "v8.h"

#include <openssl/ec.h>
Expand Down Expand Up @@ -550,6 +551,23 @@ MaybeLocal<Value> GetKeyUsage(Environment* env, X509* cert) {
return Undefined(env->isolate());
}

MaybeLocal<Value> GetCurrentCipherName(Environment* env,
const SSLPointer& ssl) {
const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl.get());
if (cipher == nullptr) return Undefined(env->isolate());

// TODO(@jasnell): SSL_CIPHER_standard_name() might be a better option here?
return OneByteString(env->isolate(), SSL_CIPHER_get_name(cipher));
}

MaybeLocal<Value> GetCurrentCipherVersion(Environment* env,
const SSLPointer& ssl) {
const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl.get());
if (cipher == nullptr) return Undefined(env->isolate());

return OneByteString(env->isolate(), SSL_CIPHER_get_version(cipher));
}

MaybeLocal<Value> GetFingerprintDigest(
Environment* env,
const EVP_MD* method,
Expand Down
4 changes: 4 additions & 0 deletions src/crypto/crypto_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ v8::MaybeLocal<v8::Value> GetFingerprintDigest(
X509* cert);

v8::MaybeLocal<v8::Value> GetKeyUsage(Environment* env, X509* cert);
v8::MaybeLocal<v8::Value> GetCurrentCipherName(Environment* env,
const SSLPointer& ssl);
v8::MaybeLocal<v8::Value> GetCurrentCipherVersion(Environment* env,
const SSLPointer& ssl);

v8::MaybeLocal<v8::Value> GetSerialNumber(Environment* env, X509* cert);

Expand Down
94 changes: 65 additions & 29 deletions src/crypto/crypto_context.cc
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "crypto/crypto_context.h"
#include "base_object-inl.h"
#include "crypto/crypto_bio.h"
#include "crypto/crypto_common.h"
#include "crypto/crypto_util.h"
#include "base_object-inl.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "node.h"
#include "node_buffer.h"
#include "node_options.h"
#include "openssl/ssl.h"
#include "util.h"
#include "v8.h"

Expand Down Expand Up @@ -570,6 +571,12 @@ void SecureContext::SetKeylogCallback(KeylogCb cb) {
SSL_CTX_set_keylog_callback(ctx_.get(), cb);
}

bool SecureContext::UseKey(std::shared_ptr<KeyObjectData> key) {
if (key->GetKeyType() != KeyType::kKeyTypePrivate) return false;

return SSL_CTX_use_PrivateKey(ctx_.get(), key->GetAsymmetricKey().get());
}

void SecureContext::SetKey(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Expand Down Expand Up @@ -658,33 +665,53 @@ void SecureContext::SetEngineKey(const FunctionCallbackInfo<Value>& args) {
}
#endif // !OPENSSL_NO_ENGINE

bool SecureContext::AddCert(BIOPointer&& bio) {
if (!bio) return false;
cert_.reset();
issuer_.reset();

if (!SSL_CTX_use_certificate_chain(
ctx_.get(), std::forward<BIOPointer>(bio), &cert_, &issuer_)) {
return false;
}

return true;
}

void SecureContext::SetCert(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

SecureContext* sc;
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder());

CHECK_GE(args.Length(), 1); // Certificate argument is mandator
CHECK_GE(args.Length(), 1); // Certificate argument is mandatory

BIOPointer bio(LoadBIO(env, args[0]));
if (!bio)
return;

sc->cert_.reset();
sc->issuer_.reset();

if (!SSL_CTX_use_certificate_chain(
sc->ctx_.get(),
std::move(bio),
&sc->cert_,
&sc->issuer_)) {
if (!sc->AddCert(std::move(bio))) {
return ThrowCryptoError(
env,
ERR_get_error(),
"SSL_CTX_use_certificate_chain");
}
}

void SecureContext::SetCACert(const BIOPointer& bio) {
X509_STORE* cert_store = SSL_CTX_get_cert_store(ctx_.get());
while (X509* x509 = PEM_read_bio_X509_AUX(
bio.get(), nullptr, NoPasswordCallback, nullptr)) {
if (cert_store == root_cert_store) {
cert_store = NewRootCertStore();
SSL_CTX_set_cert_store(ctx_.get(), cert_store);
}
X509_STORE_add_cert(cert_store, x509);
SSL_CTX_add_client_CA(ctx_.get(), x509);
X509_free(x509);
}
}

void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Expand All @@ -710,6 +737,24 @@ void SecureContext::AddCACert(const FunctionCallbackInfo<Value>& args) {
}
}

bool SecureContext::SetCRL(const BIOPointer& bio) {
DeleteFnPtr<X509_CRL, X509_CRL_free> crl(
PEM_read_bio_X509_CRL(bio.get(), nullptr, NoPasswordCallback, nullptr));

if (!crl) return false;

X509_STORE* cert_store = SSL_CTX_get_cert_store(ctx_.get());
if (cert_store == root_cert_store) {
cert_store = NewRootCertStore();
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);
return true;
}

void SecureContext::AddCRL(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

Expand All @@ -724,35 +769,26 @@ void SecureContext::AddCRL(const FunctionCallbackInfo<Value>& args) {
if (!bio)
return;

DeleteFnPtr<X509_CRL, X509_CRL_free> 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 (!sc->SetCRL(bio))
THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to parse CRL");
}

X509_STORE* cert_store = SSL_CTX_get_cert_store(sc->ctx_.get());
if (cert_store == root_cert_store) {
cert_store = NewRootCertStore();
SSL_CTX_set_cert_store(sc->ctx_.get(), cert_store);
void SecureContext::SetRootCerts() {
if (root_cert_store == nullptr) {
root_cert_store = NewRootCertStore();
}

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);
// Increment reference count so global store is not deleted along with CTX.
X509_STORE_up_ref(root_cert_store);
SSL_CTX_set_cert_store(ctx_.get(), root_cert_store);
}

void SecureContext::AddRootCerts(const FunctionCallbackInfo<Value>& args) {
SecureContext* sc;
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder());
ClearErrorOnReturn clear_error_on_return;

if (root_cert_store == nullptr) {
root_cert_store = NewRootCertStore();
}

// Increment reference count so global store is not deleted along with CTX.
X509_STORE_up_ref(root_cert_store);
SSL_CTX_set_cert_store(sc->ctx_.get(), root_cert_store);
sc->SetRootCerts();
}

void SecureContext::SetCipherSuites(const FunctionCallbackInfo<Value>& args) {
Expand Down
17 changes: 16 additions & 1 deletion src/crypto/crypto_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -43,13 +44,27 @@ class SecureContext final : public BaseObject {

const SSLCtxPointer& ctx() const { return ctx_; }

template <typename Func = void(SSLCtxPointer&)>
inline void Initialize(Func fn) {
fn(ctx_);
}

inline X509Pointer& issuer() { return issuer_; }
inline X509Pointer& cert() { return cert_; }

SSLPointer CreateSSL();

void SetGetSessionCallback(GetSessionCb cb);
void SetKeylogCallback(KeylogCb cb);
void SetNewSessionCallback(NewSessionCb cb);
void SetSelectSNIContextCallback(SelectSNIContextCb cb);

bool AddCert(BIOPointer&& bio);
void SetCACert(const BIOPointer& bio);
void SetRootCerts();
bool SetCRL(const BIOPointer& bio);
bool UseKey(std::shared_ptr<KeyObjectData> key);

// TODO(joyeecheung): track the memory used by OpenSSL types
SET_NO_MEMORY_INFO()
SET_MEMORY_INFO_NAME(SecureContext)
Expand Down
52 changes: 33 additions & 19 deletions src/crypto/crypto_keys.cc
Original file line number Diff line number Diff line change
Expand Up @@ -892,30 +892,44 @@ size_t KeyObjectData::GetSymmetricKeySize() const {
return symmetric_key_.size();
}

bool KeyObjectHandle::HasInstance(Environment* env,
v8::Local<v8::Value> value) {
return !value.IsEmpty() && value->IsObject() &&
GetConstructorTemplate(env)->HasInstance(value);
}

v8::Local<v8::FunctionTemplate> KeyObjectHandle::GetConstructorTemplate(
Environment* env) {
Local<FunctionTemplate> tmpl = env->keyobjecthandle_ctor_template();
if (tmpl.IsEmpty()) {
Isolate* isolate = env->isolate();
tmpl = NewFunctionTemplate(isolate, New);
tmpl->InstanceTemplate()->SetInternalFieldCount(
KeyObjectHandle::kInternalFieldCount);
tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
SetProtoMethod(isolate, tmpl, "init", Init);
SetProtoMethodNoSideEffect(
isolate, tmpl, "getSymmetricKeySize", GetSymmetricKeySize);
SetProtoMethodNoSideEffect(
isolate, tmpl, "getAsymmetricKeyType", GetAsymmetricKeyType);
SetProtoMethod(isolate, tmpl, "export", Export);
SetProtoMethod(isolate, tmpl, "exportJwk", ExportJWK);
SetProtoMethod(isolate, tmpl, "initECRaw", InitECRaw);
SetProtoMethod(isolate, tmpl, "initEDRaw", InitEDRaw);
SetProtoMethod(isolate, tmpl, "initJwk", InitJWK);
SetProtoMethod(isolate, tmpl, "keyDetail", GetKeyDetail);
SetProtoMethod(isolate, tmpl, "equals", Equals);
env->set_keyobjecthandle_ctor_template(tmpl);
}
return tmpl;
}

v8::Local<v8::Function> KeyObjectHandle::Initialize(Environment* env) {
Local<Function> templ = env->crypto_key_object_handle_constructor();
if (!templ.IsEmpty()) {
return templ;
}
Isolate* isolate = env->isolate();
Local<FunctionTemplate> 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);

Local<FunctionTemplate> t = GetConstructorTemplate(env);
auto function = t->GetFunction(env->context()).ToLocalChecked();
env->set_crypto_key_object_handle_constructor(function);
return function;
Expand Down
3 changes: 3 additions & 0 deletions src/crypto/crypto_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ class KeyObjectData : public MemoryRetainer {

class KeyObjectHandle : public BaseObject {
public:
static bool HasInstance(Environment* env, v8::Local<v8::Value> value);
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
Environment* env);
static v8::Local<v8::Function> Initialize(Environment* env);
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);

Expand Down
1 change: 1 addition & 0 deletions src/env_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@
V(http2ping_constructor_template, v8::ObjectTemplate) \
V(i18n_converter_template, v8::ObjectTemplate) \
V(intervalhistogram_constructor_template, v8::FunctionTemplate) \
V(keyobjecthandle_ctor_template, v8::FunctionTemplate) \
V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \
V(message_port_constructor_template, v8::FunctionTemplate) \
V(microtask_queue_ctor_template, v8::FunctionTemplate) \
Expand Down

0 comments on commit 80e3d21

Please sign in to comment.