Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: quic #44325

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
src: update src/crypto to support quic
  • Loading branch information
jasnell committed Oct 22, 2022
commit ee6f310a3b4de9a2579b24e756dcba1f9d54b790
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));
jasnell marked this conversation as resolved.
Show resolved Hide resolved
}

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));
}
jasnell marked this conversation as resolved.
Show resolved Hide resolved

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_)) {
jasnell marked this conversation as resolved.
Show resolved Hide resolved
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();
anonrig marked this conversation as resolved.
Show resolved Hide resolved

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);
jasnell marked this conversation as resolved.
Show resolved Hide resolved
X509_free(x509);
jasnell marked this conversation as resolved.
Show resolved Hide resolved
}
}

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);
jasnell marked this conversation as resolved.
Show resolved Hide resolved
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_);
}
jasnell marked this conversation as resolved.
Show resolved Hide resolved

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);
jasnell marked this conversation as resolved.
Show resolved Hide resolved

// 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);
jasnell marked this conversation as resolved.
Show resolved Hide resolved
}

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