mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
src: move evp stuff to ncrypto
PR-URL: https://github.com/nodejs/node/pull/54911 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
This commit is contained in:
parent
6a6c957be7
commit
c4681d55ae
209
deps/ncrypto/ncrypto.cc
vendored
209
deps/ncrypto/ncrypto.cc
vendored
@ -1425,4 +1425,213 @@ DataPointer pbkdf2(const EVP_MD* md,
|
||||
return {};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
EVPKeyPointer EVPKeyPointer::New() {
|
||||
return EVPKeyPointer(EVP_PKEY_new());
|
||||
}
|
||||
|
||||
EVPKeyPointer EVPKeyPointer::NewRawPublic(int id, const Buffer<const unsigned char>& data) {
|
||||
if (id == 0) return {};
|
||||
return EVPKeyPointer(EVP_PKEY_new_raw_public_key(id, nullptr, data.data, data.len));
|
||||
}
|
||||
|
||||
EVPKeyPointer EVPKeyPointer::NewRawPrivate(int id, const Buffer<const unsigned char>& data) {
|
||||
if (id == 0) return {};
|
||||
return EVPKeyPointer(EVP_PKEY_new_raw_private_key(id, nullptr, data.data, data.len));
|
||||
}
|
||||
|
||||
EVPKeyPointer::EVPKeyPointer(EVP_PKEY* pkey) : pkey_(pkey) {}
|
||||
|
||||
EVPKeyPointer::EVPKeyPointer(EVPKeyPointer&& other) noexcept
|
||||
: pkey_(other.release()) {}
|
||||
|
||||
EVPKeyPointer& EVPKeyPointer::operator=(EVPKeyPointer&& other) noexcept {
|
||||
if (this == &other) return *this;
|
||||
this->~EVPKeyPointer();
|
||||
return *new (this) EVPKeyPointer(std::move(other));
|
||||
}
|
||||
|
||||
EVPKeyPointer::~EVPKeyPointer() { reset(); }
|
||||
|
||||
void EVPKeyPointer::reset(EVP_PKEY* pkey) {
|
||||
pkey_.reset(pkey);
|
||||
}
|
||||
|
||||
EVP_PKEY* EVPKeyPointer::release() {
|
||||
return pkey_.release();
|
||||
}
|
||||
|
||||
int EVPKeyPointer::id(const EVP_PKEY* key) {
|
||||
if (key == nullptr) return 0;
|
||||
return EVP_PKEY_id(key);
|
||||
}
|
||||
|
||||
int EVPKeyPointer::base_id(const EVP_PKEY* key) {
|
||||
if (key == nullptr) return 0;
|
||||
return EVP_PKEY_base_id(key);
|
||||
}
|
||||
|
||||
int EVPKeyPointer::id() const {
|
||||
return id(get());
|
||||
}
|
||||
|
||||
int EVPKeyPointer::base_id() const {
|
||||
return base_id(get());
|
||||
}
|
||||
|
||||
int EVPKeyPointer::bits() const {
|
||||
if (get() == nullptr) return 0;
|
||||
return EVP_PKEY_bits(get());
|
||||
}
|
||||
|
||||
size_t EVPKeyPointer::size() const {
|
||||
if (get() == nullptr) return 0;
|
||||
return EVP_PKEY_size(get());
|
||||
}
|
||||
|
||||
EVPKeyCtxPointer EVPKeyPointer::newCtx() const {
|
||||
if (!pkey_) return {};
|
||||
return EVPKeyCtxPointer(EVP_PKEY_CTX_new(get(), nullptr));
|
||||
}
|
||||
|
||||
size_t EVPKeyPointer::rawPublicKeySize() const {
|
||||
if (!pkey_) return 0;
|
||||
size_t len = 0;
|
||||
if (EVP_PKEY_get_raw_public_key(get(), nullptr, &len) == 1) return len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t EVPKeyPointer::rawPrivateKeySize() const {
|
||||
if (!pkey_) return 0;
|
||||
size_t len = 0;
|
||||
if (EVP_PKEY_get_raw_private_key(get(), nullptr, &len) == 1) return len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DataPointer EVPKeyPointer::rawPublicKey() const {
|
||||
if (!pkey_) return {};
|
||||
if (auto data = DataPointer::Alloc(rawPublicKeySize())) {
|
||||
const Buffer<unsigned char> buf = data;
|
||||
size_t len = data.size();
|
||||
if (EVP_PKEY_get_raw_public_key(get(),
|
||||
buf.data,
|
||||
&len) != 1) return {};
|
||||
return data;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
DataPointer EVPKeyPointer::rawPrivateKey() const {
|
||||
if (!pkey_) return {};
|
||||
if (auto data = DataPointer::Alloc(rawPrivateKeySize())) {
|
||||
const Buffer<unsigned char> buf = data;
|
||||
size_t len = data.size();
|
||||
if (EVP_PKEY_get_raw_private_key(get(),
|
||||
buf.data,
|
||||
&len) != 1) return {};
|
||||
return data;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
BIOPointer EVPKeyPointer::derPublicKey() const {
|
||||
if (!pkey_) return {};
|
||||
auto bio = BIOPointer::NewMem();
|
||||
if (!bio) return {};
|
||||
if (!i2d_PUBKEY_bio(bio.get(), get())) return {};
|
||||
return bio;
|
||||
}
|
||||
|
||||
namespace {
|
||||
EVPKeyPointer::ParseKeyResult TryParsePublicKeyInner(
|
||||
const BIOPointer& bp,
|
||||
const char* name,
|
||||
auto&& parse) {
|
||||
if (!bp.resetBio()) {
|
||||
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED);
|
||||
}
|
||||
unsigned char* der_data;
|
||||
long der_len;
|
||||
|
||||
// This skips surrounding data and decodes PEM to DER.
|
||||
{
|
||||
MarkPopErrorOnReturn mark_pop_error_on_return;
|
||||
if (PEM_bytes_read_bio(&der_data, &der_len, nullptr, name,
|
||||
bp.get(), nullptr, nullptr) != 1)
|
||||
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::NOT_RECOGNIZED);
|
||||
}
|
||||
DataPointer data(der_data, der_len);
|
||||
|
||||
// OpenSSL might modify the pointer, so we need to make a copy before parsing.
|
||||
const unsigned char* p = der_data;
|
||||
EVPKeyPointer pkey(parse(&p, der_len));
|
||||
if (!pkey) return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED);
|
||||
return EVPKeyPointer::ParseKeyResult(std::move(pkey));
|
||||
}
|
||||
|
||||
EVPKeyPointer::ParseKeyResult TryParsePublicKeyPEM(
|
||||
const Buffer<const unsigned char>& buffer) {
|
||||
auto bp = BIOPointer::New(buffer.data, buffer.len);
|
||||
if (!bp)
|
||||
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::FAILED);
|
||||
|
||||
// Try parsing as SubjectPublicKeyInfo (SPKI) first.
|
||||
if (auto ret = TryParsePublicKeyInner(bp, "PUBLIC KEY",
|
||||
[](const unsigned char** p, long l) { // NOLINT(runtime/int)
|
||||
return d2i_PUBKEY(nullptr, p, l);
|
||||
})) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Maybe it is PKCS#1.
|
||||
if (auto ret = TryParsePublicKeyInner(bp, "RSA PUBLIC KEY",
|
||||
[](const unsigned char** p, long l) { // NOLINT(runtime/int)
|
||||
return d2i_PublicKey(EVP_PKEY_RSA, nullptr, p, l);
|
||||
})) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// X.509 fallback.
|
||||
if (auto ret = TryParsePublicKeyInner(bp, "CERTIFICATE",
|
||||
[](const unsigned char** p, long l) { // NOLINT(runtime/int)
|
||||
X509Pointer x509(d2i_X509(nullptr, p, l));
|
||||
return x509 ? X509_get_pubkey(x509.get()) : nullptr;
|
||||
})) {
|
||||
return ret;
|
||||
};
|
||||
|
||||
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer::PKParseError::NOT_RECOGNIZED);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
EVPKeyPointer::ParseKeyResult EVPKeyPointer::TryParsePublicKey(
|
||||
PKFormatType format,
|
||||
PKEncodingType encoding,
|
||||
const Buffer<const unsigned char>& buffer) {
|
||||
if (format == PKFormatType::PEM) {
|
||||
return TryParsePublicKeyPEM(buffer);
|
||||
}
|
||||
|
||||
if (format != PKFormatType::DER) {
|
||||
return ParseKeyResult(PKParseError::FAILED);
|
||||
}
|
||||
|
||||
const unsigned char* start = buffer.data;
|
||||
|
||||
EVP_PKEY* key = nullptr;
|
||||
|
||||
if (encoding == PKEncodingType::PKCS1 &&
|
||||
(key = d2i_PublicKey(EVP_PKEY_RSA, nullptr, &start, buffer.len))) {
|
||||
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key));
|
||||
}
|
||||
|
||||
if (encoding == PKEncodingType::SPKI &&
|
||||
(key = d2i_PUBKEY(nullptr, &start, buffer.len))) {
|
||||
return EVPKeyPointer::ParseKeyResult(EVPKeyPointer(key));
|
||||
}
|
||||
|
||||
return ParseKeyResult(PKParseError::FAILED);
|
||||
}
|
||||
|
||||
} // namespace ncrypto
|
||||
|
83
deps/ncrypto/ncrypto.h
vendored
83
deps/ncrypto/ncrypto.h
vendored
@ -172,12 +172,16 @@ private:
|
||||
CryptoErrorList* errors_;
|
||||
};
|
||||
|
||||
// TODO(@jasnell): Eventually replace with std::expected when we are able to
|
||||
// bump up to c++23.
|
||||
template <typename T, typename E>
|
||||
struct Result final {
|
||||
const bool has_value;
|
||||
T value;
|
||||
std::optional<E> error;
|
||||
Result(T&& value) : value(std::move(value)) {}
|
||||
Result(E&& error) : error(std::move(error)) {}
|
||||
Result(T&& value) : has_value(true), value(std::move(value)) {}
|
||||
Result(E&& error) : has_value(false), error(std::move(error)) {}
|
||||
inline operator bool() const { return has_value; }
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
@ -202,7 +206,6 @@ using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>;
|
||||
using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
||||
using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>;
|
||||
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
||||
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
|
||||
using EVPMDCtxPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
|
||||
using HMACCtxPointer = DeleteFnPtr<HMAC_CTX, HMAC_CTX_free>;
|
||||
using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>;
|
||||
@ -252,9 +255,10 @@ class DataPointer final {
|
||||
Buffer<void> release();
|
||||
|
||||
// Returns a Buffer struct that is a view of the underlying data.
|
||||
inline operator const Buffer<void>() const {
|
||||
template <typename T = void>
|
||||
inline operator const Buffer<T>() const {
|
||||
return {
|
||||
.data = data_,
|
||||
.data = static_cast<T*>(data_),
|
||||
.len = len_,
|
||||
};
|
||||
}
|
||||
@ -359,6 +363,75 @@ class BignumPointer final {
|
||||
DeleteFnPtr<BIGNUM, BN_clear_free> bn_;
|
||||
};
|
||||
|
||||
class EVPKeyPointer final {
|
||||
public:
|
||||
static EVPKeyPointer New();
|
||||
static EVPKeyPointer NewRawPublic(int id, const Buffer<const unsigned char>& data);
|
||||
static EVPKeyPointer NewRawPrivate(int id, const Buffer<const unsigned char>& data);
|
||||
|
||||
enum class PKEncodingType {
|
||||
// RSAPublicKey / RSAPrivateKey according to PKCS#1.
|
||||
PKCS1,
|
||||
// PrivateKeyInfo or EncryptedPrivateKeyInfo according to PKCS#8.
|
||||
PKCS8,
|
||||
// SubjectPublicKeyInfo according to X.509.
|
||||
SPKI,
|
||||
// ECPrivateKey according to SEC1.
|
||||
SEC1
|
||||
};
|
||||
|
||||
enum class PKFormatType {
|
||||
DER,
|
||||
PEM,
|
||||
JWK
|
||||
};
|
||||
|
||||
enum class PKParseError {
|
||||
NOT_RECOGNIZED,
|
||||
NEED_PASSPHRASE,
|
||||
FAILED
|
||||
};
|
||||
using ParseKeyResult = Result<EVPKeyPointer, PKParseError>;
|
||||
|
||||
static ParseKeyResult TryParsePublicKey(
|
||||
PKFormatType format,
|
||||
PKEncodingType encoding,
|
||||
const Buffer<const unsigned char>& buffer);
|
||||
|
||||
EVPKeyPointer() = default;
|
||||
explicit EVPKeyPointer(EVP_PKEY* pkey);
|
||||
EVPKeyPointer(EVPKeyPointer&& other) noexcept;
|
||||
EVPKeyPointer& operator=(EVPKeyPointer&& other) noexcept;
|
||||
NCRYPTO_DISALLOW_COPY(EVPKeyPointer)
|
||||
~EVPKeyPointer();
|
||||
|
||||
inline bool operator==(std::nullptr_t) const noexcept { return pkey_ == nullptr; }
|
||||
inline operator bool() const { return pkey_ != nullptr; }
|
||||
inline EVP_PKEY* get() const { return pkey_.get(); }
|
||||
void reset(EVP_PKEY* pkey = nullptr);
|
||||
EVP_PKEY* release();
|
||||
|
||||
static int id(const EVP_PKEY* key);
|
||||
static int base_id(const EVP_PKEY* key);
|
||||
|
||||
int id() const;
|
||||
int base_id() const;
|
||||
int bits() const;
|
||||
size_t size() const;
|
||||
|
||||
size_t rawPublicKeySize() const;
|
||||
size_t rawPrivateKeySize() const;
|
||||
DataPointer rawPublicKey() const;
|
||||
DataPointer rawPrivateKey() const;
|
||||
|
||||
BIOPointer derPublicKey() const;
|
||||
|
||||
EVPKeyCtxPointer newCtx() const;
|
||||
|
||||
private:
|
||||
DeleteFnPtr<EVP_PKEY, EVP_PKEY_free> pkey_;
|
||||
};
|
||||
|
||||
class DHPointer final {
|
||||
public:
|
||||
|
||||
|
@ -995,7 +995,7 @@ bool PublicKeyCipher::Cipher(
|
||||
const ArrayBufferOrViewContents<unsigned char>& oaep_label,
|
||||
const ArrayBufferOrViewContents<unsigned char>& data,
|
||||
std::unique_ptr<BackingStore>* out) {
|
||||
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
|
||||
EVPKeyCtxPointer ctx = pkey.newCtx();
|
||||
if (!ctx)
|
||||
return false;
|
||||
if (EVP_PKEY_cipher_init(ctx.get()) <= 0)
|
||||
@ -1071,7 +1071,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
if (EVP_PKEY_cipher == EVP_PKEY_decrypt &&
|
||||
operation == PublicKeyCipher::kPrivate && padding == RSA_PKCS1_PADDING) {
|
||||
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
|
||||
EVPKeyCtxPointer ctx = pkey.newCtx();
|
||||
CHECK(ctx);
|
||||
|
||||
if (EVP_PKEY_decrypt_init(ctx.get()) <= 0) {
|
||||
|
@ -449,15 +449,14 @@ MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
|
||||
Local<Context> context = env->context();
|
||||
crypto::EVPKeyPointer key(raw_key);
|
||||
|
||||
int kid = EVP_PKEY_id(key.get());
|
||||
int bits = EVP_PKEY_bits(key.get());
|
||||
int kid = key.id();
|
||||
switch (kid) {
|
||||
case EVP_PKEY_DH:
|
||||
if (!Set<String>(context, info, env->type_string(), env->dh_string()) ||
|
||||
!Set<Integer>(context,
|
||||
info,
|
||||
env->size_string(),
|
||||
Integer::New(env->isolate(), bits))) {
|
||||
info,
|
||||
env->size_string(),
|
||||
Integer::New(env->isolate(), key.bits()))) {
|
||||
return MaybeLocal<Object>();
|
||||
}
|
||||
break;
|
||||
@ -473,18 +472,16 @@ MaybeLocal<Object> GetEphemeralKey(Environment* env, const SSLPointer& ssl) {
|
||||
} else {
|
||||
curve_name = OBJ_nid2sn(kid);
|
||||
}
|
||||
if (!Set<String>(context,
|
||||
info,
|
||||
env->type_string(),
|
||||
env->ecdh_string()) ||
|
||||
if (!Set<String>(
|
||||
context, info, env->type_string(), env->ecdh_string()) ||
|
||||
!Set<String>(context,
|
||||
info,
|
||||
env->name_string(),
|
||||
OneByteString(env->isolate(), curve_name)) ||
|
||||
info,
|
||||
env->name_string(),
|
||||
OneByteString(env->isolate(), curve_name)) ||
|
||||
!Set<Integer>(context,
|
||||
info,
|
||||
env->size_string(),
|
||||
Integer::New(env->isolate(), bits))) {
|
||||
info,
|
||||
env->size_string(),
|
||||
Integer::New(env->isolate(), key.bits()))) {
|
||||
return MaybeLocal<Object>();
|
||||
}
|
||||
}
|
||||
|
@ -395,7 +395,7 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
|
||||
auto dh = DHPointer::New(std::move(prime), std::move(bn_g));
|
||||
if (!dh) return {};
|
||||
|
||||
key_params = EVPKeyPointer(EVP_PKEY_new());
|
||||
key_params = EVPKeyPointer::New();
|
||||
CHECK(key_params);
|
||||
CHECK_EQ(EVP_PKEY_assign_DH(key_params.get(), dh.release()), 1);
|
||||
} else if (int* prime_size = std::get_if<int>(¶ms->params.prime)) {
|
||||
@ -418,7 +418,7 @@ EVPKeyCtxPointer DhKeyGenTraits::Setup(DhKeyPairGenConfig* params) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(key_params.get(), nullptr));
|
||||
EVPKeyCtxPointer ctx = key_params.newCtx();
|
||||
if (!ctx || EVP_PKEY_keygen_init(ctx.get()) <= 0) return {};
|
||||
|
||||
return ctx;
|
||||
@ -533,7 +533,7 @@ bool DHBitsTraits::DeriveBits(
|
||||
Maybe<void> GetDhKeyDetail(Environment* env,
|
||||
const KeyObjectData& key,
|
||||
Local<Object> target) {
|
||||
CHECK_EQ(EVP_PKEY_id(key.GetAsymmetricKey().get()), EVP_PKEY_DH);
|
||||
CHECK_EQ(key.GetAsymmetricKey().id(), EVP_PKEY_DH);
|
||||
return JustVoid();
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ EVPKeyCtxPointer DsaKeyGenTraits::Setup(DsaKeyPairGenConfig* params) {
|
||||
return EVPKeyCtxPointer();
|
||||
|
||||
EVPKeyPointer key_params(raw_params);
|
||||
EVPKeyCtxPointer key_ctx(EVP_PKEY_CTX_new(key_params.get(), nullptr));
|
||||
EVPKeyCtxPointer key_ctx = key_params.newCtx();
|
||||
|
||||
if (!key_ctx || EVP_PKEY_keygen_init(key_ctx.get()) <= 0)
|
||||
return EVPKeyCtxPointer();
|
||||
@ -134,7 +134,7 @@ Maybe<void> GetDsaKeyDetail(Environment* env,
|
||||
|
||||
Mutex::ScopedLock lock(key.mutex());
|
||||
const auto& m_pkey = key.GetAsymmetricKey();
|
||||
int type = EVP_PKEY_id(m_pkey.get());
|
||||
int type = m_pkey.id();
|
||||
CHECK(type == EVP_PKEY_DSA);
|
||||
|
||||
const DSA* dsa = EVP_PKEY_get0_DSA(m_pkey.get());
|
||||
|
@ -486,10 +486,7 @@ bool ECDHBitsTraits::DeriveBits(Environment* env,
|
||||
case EVP_PKEY_X25519:
|
||||
// Fall through
|
||||
case EVP_PKEY_X448: {
|
||||
EVPKeyCtxPointer ctx = nullptr;
|
||||
{
|
||||
ctx.reset(EVP_PKEY_CTX_new(m_privkey.get(), nullptr));
|
||||
}
|
||||
EVPKeyCtxPointer ctx = m_privkey.newCtx();
|
||||
Mutex::ScopedLock pub_lock(params.public_.mutex());
|
||||
if (EVP_PKEY_derive_init(ctx.get()) <= 0 ||
|
||||
EVP_PKEY_derive_set_peer(
|
||||
@ -568,7 +565,7 @@ EVPKeyCtxPointer EcKeyGenTraits::Setup(EcKeyPairGenConfig* params) {
|
||||
return EVPKeyCtxPointer();
|
||||
}
|
||||
EVPKeyPointer key_params(raw_params);
|
||||
key_ctx.reset(EVP_PKEY_CTX_new(key_params.get(), nullptr));
|
||||
key_ctx = key_params.newCtx();
|
||||
}
|
||||
}
|
||||
|
||||
@ -626,29 +623,23 @@ WebCryptoKeyExportStatus EC_Raw_Export(const KeyObjectData& key_data,
|
||||
|
||||
const EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(m_pkey.get());
|
||||
|
||||
size_t len = 0;
|
||||
|
||||
if (ec_key == nullptr) {
|
||||
typedef int (*export_fn)(const EVP_PKEY*, unsigned char*, size_t* len);
|
||||
export_fn fn = nullptr;
|
||||
switch (key_data.GetKeyType()) {
|
||||
case kKeyTypePrivate:
|
||||
fn = EVP_PKEY_get_raw_private_key;
|
||||
case kKeyTypePrivate: {
|
||||
auto data = m_pkey.rawPrivateKey();
|
||||
if (!data) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
||||
*out = ByteSource::Allocated(data.release());
|
||||
break;
|
||||
case kKeyTypePublic:
|
||||
fn = EVP_PKEY_get_raw_public_key;
|
||||
}
|
||||
case kKeyTypePublic: {
|
||||
auto data = m_pkey.rawPublicKey();
|
||||
if (!data) return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
||||
*out = ByteSource::Allocated(data.release());
|
||||
break;
|
||||
}
|
||||
case kKeyTypeSecret:
|
||||
UNREACHABLE();
|
||||
}
|
||||
CHECK_NOT_NULL(fn);
|
||||
// Get the size of the raw key data
|
||||
if (fn(m_pkey.get(), nullptr, &len) == 0)
|
||||
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
||||
ByteSource::Builder data(len);
|
||||
if (fn(m_pkey.get(), data.data<unsigned char>(), &len) == 0)
|
||||
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
||||
*out = std::move(data).release(len);
|
||||
} else {
|
||||
if (key_data.GetKeyType() != kKeyTypePublic)
|
||||
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
||||
@ -657,7 +648,7 @@ WebCryptoKeyExportStatus EC_Raw_Export(const KeyObjectData& key_data,
|
||||
point_conversion_form_t form = POINT_CONVERSION_UNCOMPRESSED;
|
||||
|
||||
// Get the allocated data size...
|
||||
len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr);
|
||||
size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, nullptr);
|
||||
if (len == 0)
|
||||
return WebCryptoKeyExportStatus::FAILED;
|
||||
ByteSource::Builder data(len);
|
||||
@ -700,7 +691,7 @@ WebCryptoKeyExportStatus ECKeyExportTraits::DoExport(
|
||||
return WebCryptoKeyExportStatus::INVALID_KEY_TYPE;
|
||||
|
||||
const auto& m_pkey = key_data.GetAsymmetricKey();
|
||||
if (EVP_PKEY_id(m_pkey.get()) != EVP_PKEY_EC) {
|
||||
if (m_pkey.id() != EVP_PKEY_EC) {
|
||||
return PKEY_SPKI_Export(key_data, out);
|
||||
} else {
|
||||
// Ensure exported key is in uncompressed point format.
|
||||
@ -730,12 +721,10 @@ WebCryptoKeyExportStatus ECKeyExportTraits::DoExport(
|
||||
data.size(),
|
||||
nullptr));
|
||||
CHECK_EQ(1, EC_KEY_set_public_key(ec.get(), uncompressed.get()));
|
||||
EVPKeyPointer pkey(EVP_PKEY_new());
|
||||
auto pkey = EVPKeyPointer::New();
|
||||
CHECK_EQ(1, EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()));
|
||||
auto bio = BIOPointer::NewMem();
|
||||
CHECK(bio);
|
||||
if (!i2d_PUBKEY_bio(bio.get(), pkey.get()))
|
||||
return WebCryptoKeyExportStatus::FAILED;
|
||||
auto bio = pkey.derPublicKey();
|
||||
if (!bio) return WebCryptoKeyExportStatus::FAILED;
|
||||
*out = ByteSource::FromBIO(bio);
|
||||
return WebCryptoKeyExportStatus::OK;
|
||||
}
|
||||
@ -750,7 +739,7 @@ Maybe<void> ExportJWKEcKey(Environment* env,
|
||||
Local<Object> target) {
|
||||
Mutex::ScopedLock lock(key.mutex());
|
||||
const auto& m_pkey = key.GetAsymmetricKey();
|
||||
CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC);
|
||||
CHECK_EQ(m_pkey.id(), EVP_PKEY_EC);
|
||||
|
||||
const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get());
|
||||
CHECK_NOT_NULL(ec);
|
||||
@ -835,67 +824,49 @@ Maybe<void> ExportJWKEdKey(Environment* env,
|
||||
Mutex::ScopedLock lock(key.mutex());
|
||||
const auto& pkey = key.GetAsymmetricKey();
|
||||
|
||||
const char* curve = nullptr;
|
||||
switch (EVP_PKEY_id(pkey.get())) {
|
||||
case EVP_PKEY_ED25519:
|
||||
curve = "Ed25519";
|
||||
break;
|
||||
case EVP_PKEY_ED448:
|
||||
curve = "Ed448";
|
||||
break;
|
||||
case EVP_PKEY_X25519:
|
||||
curve = "X25519";
|
||||
break;
|
||||
case EVP_PKEY_X448:
|
||||
curve = "X448";
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (target->Set(
|
||||
env->context(),
|
||||
env->jwk_crv_string(),
|
||||
OneByteString(env->isolate(), curve)).IsNothing()) {
|
||||
return Nothing<void>();
|
||||
}
|
||||
|
||||
size_t len = 0;
|
||||
Local<Value> encoded;
|
||||
Local<Value> error;
|
||||
|
||||
if (!EVP_PKEY_get_raw_public_key(pkey.get(), nullptr, &len))
|
||||
return Nothing<void>();
|
||||
|
||||
ByteSource::Builder out(len);
|
||||
|
||||
if (key.GetKeyType() == kKeyTypePrivate) {
|
||||
if (!EVP_PKEY_get_raw_private_key(
|
||||
pkey.get(), out.data<unsigned char>(), &len) ||
|
||||
!StringBytes::Encode(
|
||||
env->isolate(), out.data<const char>(), len, BASE64URL, &error)
|
||||
.ToLocal(&encoded) ||
|
||||
!target->Set(env->context(), env->jwk_d_string(), encoded).IsJust()) {
|
||||
if (!error.IsEmpty())
|
||||
env->isolate()->ThrowException(error);
|
||||
return Nothing<void>();
|
||||
const char* curve = ([&] {
|
||||
switch (pkey.id()) {
|
||||
case EVP_PKEY_ED25519:
|
||||
return "Ed25519";
|
||||
case EVP_PKEY_ED448:
|
||||
return "Ed448";
|
||||
case EVP_PKEY_X25519:
|
||||
return "X25519";
|
||||
case EVP_PKEY_X448:
|
||||
return "X448";
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
if (!EVP_PKEY_get_raw_public_key(
|
||||
pkey.get(), out.data<unsigned char>(), &len) ||
|
||||
!StringBytes::Encode(
|
||||
env->isolate(), out.data<const char>(), len, BASE64URL, &error)
|
||||
.ToLocal(&encoded) ||
|
||||
!target->Set(env->context(), env->jwk_x_string(), encoded).IsJust()) {
|
||||
if (!error.IsEmpty())
|
||||
env->isolate()->ThrowException(error);
|
||||
return Nothing<void>();
|
||||
}
|
||||
static constexpr auto trySetKey = [](Environment* env,
|
||||
ncrypto::DataPointer data,
|
||||
Local<Object> target,
|
||||
Local<String> key) {
|
||||
Local<Value> encoded;
|
||||
Local<Value> error;
|
||||
if (!data) return false;
|
||||
const ncrypto::Buffer<const char> out = data;
|
||||
if (!StringBytes::Encode(
|
||||
env->isolate(), out.data, out.len, BASE64URL, &error)
|
||||
.ToLocal(&encoded) ||
|
||||
target->Set(env->context(), key, encoded).IsNothing()) {
|
||||
if (!error.IsEmpty()) env->isolate()->ThrowException(error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
if (target->Set(
|
||||
env->context(),
|
||||
env->jwk_kty_string(),
|
||||
env->jwk_okp_string()).IsNothing()) {
|
||||
if (target
|
||||
->Set(env->context(),
|
||||
env->jwk_crv_string(),
|
||||
OneByteString(env->isolate(), curve))
|
||||
.IsNothing() ||
|
||||
(key.GetKeyType() == kKeyTypePrivate &&
|
||||
!trySetKey(env, pkey.rawPrivateKey(), target, env->jwk_d_string())) ||
|
||||
!trySetKey(env, pkey.rawPublicKey(), target, env->jwk_x_string()) ||
|
||||
target->Set(env->context(), env->jwk_kty_string(), env->jwk_okp_string())
|
||||
.IsNothing()) {
|
||||
return Nothing<void>();
|
||||
}
|
||||
|
||||
@ -959,7 +930,7 @@ KeyObjectData ImportJWKEcKey(Environment* env,
|
||||
}
|
||||
}
|
||||
|
||||
EVPKeyPointer pkey(EVP_PKEY_new());
|
||||
auto pkey = EVPKeyPointer::New();
|
||||
CHECK_EQ(EVP_PKEY_set1_EC_KEY(pkey.get(), ec.get()), 1);
|
||||
|
||||
return KeyObjectData::CreateAsymmetric(type, std::move(pkey));
|
||||
@ -970,7 +941,7 @@ Maybe<void> GetEcKeyDetail(Environment* env,
|
||||
Local<Object> target) {
|
||||
Mutex::ScopedLock lock(key.mutex());
|
||||
const auto& m_pkey = key.GetAsymmetricKey();
|
||||
CHECK_EQ(EVP_PKEY_id(m_pkey.get()), EVP_PKEY_EC);
|
||||
CHECK_EQ(m_pkey.id(), EVP_PKEY_EC);
|
||||
|
||||
const EC_KEY* ec = EVP_PKEY_get0_EC_KEY(m_pkey.get());
|
||||
CHECK_NOT_NULL(ec);
|
||||
|
@ -25,7 +25,6 @@ using v8::FunctionCallbackInfo;
|
||||
using v8::FunctionTemplate;
|
||||
using v8::Int32;
|
||||
using v8::Isolate;
|
||||
using v8::Just;
|
||||
using v8::JustVoid;
|
||||
using v8::Local;
|
||||
using v8::Maybe;
|
||||
@ -60,8 +59,8 @@ void GetKeyFormatAndTypeFromJs(
|
||||
args[*offset].As<Int32>()->Value());
|
||||
|
||||
if (args[*offset + 1]->IsInt32()) {
|
||||
config->type_ = Just<PKEncodingType>(static_cast<PKEncodingType>(
|
||||
args[*offset + 1].As<Int32>()->Value()));
|
||||
config->type_ =
|
||||
static_cast<PKEncodingType>(args[*offset + 1].As<Int32>()->Value());
|
||||
} else {
|
||||
CHECK(
|
||||
(context == kKeyContextInput &&
|
||||
@ -69,7 +68,7 @@ void GetKeyFormatAndTypeFromJs(
|
||||
(context == kKeyContextGenerate &&
|
||||
config->format_ == kKeyFormatJWK));
|
||||
CHECK(args[*offset + 1]->IsNullOrUndefined());
|
||||
config->type_ = Nothing<PKEncodingType>();
|
||||
config->type_ = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,22 +139,18 @@ ParseKeyResult ParsePublicKey(EVPKeyPointer* pkey,
|
||||
const PublicKeyEncodingConfig& config,
|
||||
const char* key,
|
||||
size_t key_len) {
|
||||
if (config.format_ == kKeyFormatPEM) {
|
||||
return ParsePublicKeyPEM(pkey, key, key_len);
|
||||
} else {
|
||||
CHECK_EQ(config.format_, kKeyFormatDER);
|
||||
auto res = EVPKeyPointer::TryParsePublicKey(
|
||||
static_cast<EVPKeyPointer::PKFormatType>(config.format_),
|
||||
static_cast<EVPKeyPointer::PKEncodingType>(config.type_.value()),
|
||||
ncrypto::Buffer<const unsigned char>{
|
||||
.data = reinterpret_cast<const unsigned char*>(key),
|
||||
.len = key_len,
|
||||
});
|
||||
if (!res) return static_cast<ParseKeyResult>(res.error.value());
|
||||
|
||||
const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
|
||||
if (config.type_.ToChecked() == kKeyEncodingPKCS1) {
|
||||
pkey->reset(d2i_PublicKey(EVP_PKEY_RSA, nullptr, &p, key_len));
|
||||
} else {
|
||||
CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI);
|
||||
pkey->reset(d2i_PUBKEY(nullptr, &p, key_len));
|
||||
}
|
||||
|
||||
return *pkey ? ParseKeyResult::kParseKeyOk :
|
||||
ParseKeyResult::kParseKeyFailed;
|
||||
}
|
||||
CHECK(res.has_value);
|
||||
*pkey = std::move(res.value);
|
||||
return ParseKeyResult::kParseKeyOk;
|
||||
}
|
||||
|
||||
bool IsASN1Sequence(const unsigned char* data, size_t size,
|
||||
@ -229,10 +224,10 @@ ParseKeyResult ParsePrivateKey(EVPKeyPointer* pkey,
|
||||
} else {
|
||||
CHECK_EQ(config.format_, kKeyFormatDER);
|
||||
|
||||
if (config.type_.ToChecked() == kKeyEncodingPKCS1) {
|
||||
if (config.type_.value() == kKeyEncodingPKCS1) {
|
||||
const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
|
||||
pkey->reset(d2i_PrivateKey(EVP_PKEY_RSA, nullptr, &p, key_len));
|
||||
} else if (config.type_.ToChecked() == kKeyEncodingPKCS8) {
|
||||
} else if (config.type_.value() == kKeyEncodingPKCS8) {
|
||||
auto bio = BIOPointer::New(key, key_len);
|
||||
if (!bio)
|
||||
return ParseKeyResult::kParseKeyFailed;
|
||||
@ -249,7 +244,7 @@ ParseKeyResult ParsePrivateKey(EVPKeyPointer* pkey,
|
||||
pkey->reset(EVP_PKCS82PKEY(p8inf.get()));
|
||||
}
|
||||
} else {
|
||||
CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSEC1);
|
||||
CHECK_EQ(config.type_.value(), kKeyEncodingSEC1);
|
||||
const unsigned char* p = reinterpret_cast<const unsigned char*>(key);
|
||||
pkey->reset(d2i_PrivateKey(EVP_PKEY_EC, nullptr, &p, key_len));
|
||||
}
|
||||
@ -318,10 +313,10 @@ MaybeLocal<Value> WritePrivateKey(Environment* env,
|
||||
MarkPopErrorOnReturn mark_pop_error_on_return;
|
||||
bool err;
|
||||
|
||||
PKEncodingType encoding_type = config.type_.ToChecked();
|
||||
PKEncodingType encoding_type = config.type_.value();
|
||||
if (encoding_type == kKeyEncodingPKCS1) {
|
||||
// PKCS#1 is only permitted for RSA keys.
|
||||
CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA);
|
||||
CHECK_EQ(EVPKeyPointer::id(pkey), EVP_PKEY_RSA);
|
||||
|
||||
OSSL3_CONST RSA* rsa = EVP_PKEY_get0_RSA(pkey);
|
||||
if (config.format_ == kKeyFormatPEM) {
|
||||
@ -362,7 +357,7 @@ MaybeLocal<Value> WritePrivateKey(Environment* env,
|
||||
CHECK_EQ(encoding_type, kKeyEncodingSEC1);
|
||||
|
||||
// SEC1 is only permitted for EC keys.
|
||||
CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_EC);
|
||||
CHECK_EQ(EVPKeyPointer::id(pkey), EVP_PKEY_EC);
|
||||
|
||||
OSSL3_CONST EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey);
|
||||
if (config.format_ == kKeyFormatPEM) {
|
||||
@ -392,9 +387,9 @@ MaybeLocal<Value> WritePrivateKey(Environment* env,
|
||||
bool WritePublicKeyInner(OSSL3_CONST EVP_PKEY* pkey,
|
||||
const BIOPointer& bio,
|
||||
const PublicKeyEncodingConfig& config) {
|
||||
if (config.type_.ToChecked() == kKeyEncodingPKCS1) {
|
||||
if (config.type_.value() == kKeyEncodingPKCS1) {
|
||||
// PKCS#1 is only valid for RSA keys.
|
||||
CHECK_EQ(EVP_PKEY_id(pkey), EVP_PKEY_RSA);
|
||||
CHECK_EQ(EVPKeyPointer::id(pkey), EVP_PKEY_RSA);
|
||||
OSSL3_CONST RSA* rsa = EVP_PKEY_get0_RSA(pkey);
|
||||
if (config.format_ == kKeyFormatPEM) {
|
||||
// Encode PKCS#1 as PEM.
|
||||
@ -405,7 +400,7 @@ bool WritePublicKeyInner(OSSL3_CONST EVP_PKEY* pkey,
|
||||
return i2d_RSAPublicKey_bio(bio.get(), rsa) == 1;
|
||||
}
|
||||
} else {
|
||||
CHECK_EQ(config.type_.ToChecked(), kKeyEncodingSPKI);
|
||||
CHECK_EQ(config.type_.value(), kKeyEncodingSPKI);
|
||||
if (config.format_ == kKeyFormatPEM) {
|
||||
// Encode SPKI as PEM.
|
||||
return PEM_write_bio_PUBKEY(bio.get(), pkey) == 1;
|
||||
@ -480,7 +475,7 @@ Maybe<void> ExportJWKAsymmetricKey(Environment* env,
|
||||
const KeyObjectData& key,
|
||||
Local<Object> target,
|
||||
bool handleRsaPss) {
|
||||
switch (EVP_PKEY_id(key.GetAsymmetricKey().get())) {
|
||||
switch (key.GetAsymmetricKey().id()) {
|
||||
case EVP_PKEY_RSA_PSS: {
|
||||
if (handleRsaPss) return ExportJWKRsaKey(env, key, target);
|
||||
break;
|
||||
@ -535,7 +530,7 @@ Maybe<void> GetSecretKeyDetail(Environment* env,
|
||||
Maybe<void> GetAsymmetricKeyDetail(Environment* env,
|
||||
const KeyObjectData& key,
|
||||
Local<Object> target) {
|
||||
switch (EVP_PKEY_id(key.GetAsymmetricKey().get())) {
|
||||
switch (key.GetAsymmetricKey().id()) {
|
||||
case EVP_PKEY_RSA:
|
||||
// Fall through
|
||||
case EVP_PKEY_RSA_PSS: return GetRsaKeyDetail(env, key, target);
|
||||
@ -723,32 +718,34 @@ KeyObjectData KeyObjectData::GetPublicOrPrivateKeyFromJs(
|
||||
type = KeyType::kKeyTypePrivate;
|
||||
ret = ParsePrivateKey(&pkey, config, data.data(), data.size());
|
||||
}
|
||||
} else {
|
||||
// For DER, the type determines how to parse it. SPKI, PKCS#8 and SEC1 are
|
||||
// easy, but PKCS#1 can be a public key or a private key.
|
||||
bool is_public;
|
||||
switch (config.type_.ToChecked()) {
|
||||
case kKeyEncodingPKCS1:
|
||||
is_public = !IsRSAPrivateKey(
|
||||
reinterpret_cast<const unsigned char*>(data.data()), data.size());
|
||||
break;
|
||||
case kKeyEncodingSPKI:
|
||||
is_public = true;
|
||||
break;
|
||||
case kKeyEncodingPKCS8:
|
||||
case kKeyEncodingSEC1:
|
||||
is_public = false;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Invalid key encoding type");
|
||||
}
|
||||
return GetParsedKey(
|
||||
type, env, std::move(pkey), ret, "Failed to read asymmetric key");
|
||||
}
|
||||
|
||||
if (is_public) {
|
||||
ret = ParsePublicKey(&pkey, config, data.data(), data.size());
|
||||
} else {
|
||||
type = KeyType::kKeyTypePrivate;
|
||||
ret = ParsePrivateKey(&pkey, config, data.data(), data.size());
|
||||
}
|
||||
// For DER, the type determines how to parse it. SPKI, PKCS#8 and SEC1 are
|
||||
// easy, but PKCS#1 can be a public key or a private key.
|
||||
bool is_public;
|
||||
switch (config.type_.value()) {
|
||||
case kKeyEncodingPKCS1:
|
||||
is_public = !IsRSAPrivateKey(
|
||||
reinterpret_cast<const unsigned char*>(data.data()), data.size());
|
||||
break;
|
||||
case kKeyEncodingSPKI:
|
||||
is_public = true;
|
||||
break;
|
||||
case kKeyEncodingPKCS8:
|
||||
case kKeyEncodingSEC1:
|
||||
is_public = false;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE("Invalid key encoding type");
|
||||
}
|
||||
|
||||
if (is_public) {
|
||||
ret = ParsePublicKey(&pkey, config, data.data(), data.size());
|
||||
} else {
|
||||
type = KeyType::kKeyTypePrivate;
|
||||
ret = ParsePrivateKey(&pkey, config, data.data(), data.size());
|
||||
}
|
||||
|
||||
return GetParsedKey(
|
||||
@ -809,17 +806,10 @@ void KeyObjectData::MemoryInfo(MemoryTracker* tracker) const {
|
||||
// Fall through
|
||||
case kKeyTypePublic: {
|
||||
if (data_->asymmetric_key) {
|
||||
size_t size = kSizeOf_EVP_PKEY;
|
||||
size_t len = 0;
|
||||
if (EVP_PKEY_get_raw_private_key(
|
||||
data_->asymmetric_key.get(), nullptr, &len) == 1) {
|
||||
size += len;
|
||||
}
|
||||
if (EVP_PKEY_get_raw_public_key(
|
||||
data_->asymmetric_key.get(), nullptr, &len) == 1) {
|
||||
size += len;
|
||||
}
|
||||
tracker->TrackFieldWithSize("key", size);
|
||||
tracker->TrackFieldWithSize(
|
||||
"key",
|
||||
kSizeOf_EVP_PKEY + data_->asymmetric_key.rawPublicKeySize() +
|
||||
data_->asymmetric_key.rawPrivateKeySize());
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1047,7 +1037,7 @@ void KeyObjectHandle::InitECRaw(const FunctionCallbackInfo<Value>& args) {
|
||||
return args.GetReturnValue().Set(false);
|
||||
}
|
||||
|
||||
EVPKeyPointer pkey(EVP_PKEY_new());
|
||||
auto pkey = EVPKeyPointer::New();
|
||||
if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()))
|
||||
args.GetReturnValue().Set(false);
|
||||
|
||||
@ -1071,10 +1061,10 @@ void KeyObjectHandle::InitEDRaw(const FunctionCallbackInfo<Value>& args) {
|
||||
|
||||
MarkPopErrorOnReturn mark_pop_error_on_return;
|
||||
|
||||
typedef EVP_PKEY* (*new_key_fn)(int, ENGINE*, const unsigned char*, size_t);
|
||||
new_key_fn fn = type == kKeyTypePrivate
|
||||
? EVP_PKEY_new_raw_private_key
|
||||
: EVP_PKEY_new_raw_public_key;
|
||||
typedef EVPKeyPointer (*new_key_fn)(
|
||||
int, const ncrypto::Buffer<const unsigned char>&);
|
||||
new_key_fn fn = type == kKeyTypePrivate ? EVPKeyPointer::NewRawPrivate
|
||||
: EVPKeyPointer::NewRawPublic;
|
||||
|
||||
int id = GetOKPCurveFromName(*name);
|
||||
|
||||
@ -1083,9 +1073,14 @@ void KeyObjectHandle::InitEDRaw(const FunctionCallbackInfo<Value>& args) {
|
||||
case EVP_PKEY_X448:
|
||||
case EVP_PKEY_ED25519:
|
||||
case EVP_PKEY_ED448: {
|
||||
EVPKeyPointer pkey(fn(id, nullptr, key_data.data(), key_data.size()));
|
||||
if (!pkey)
|
||||
auto pkey = fn(id,
|
||||
ncrypto::Buffer<const unsigned char>{
|
||||
.data = key_data.data(),
|
||||
.len = key_data.size(),
|
||||
});
|
||||
if (!pkey) {
|
||||
return args.GetReturnValue().Set(false);
|
||||
}
|
||||
key->data_ = KeyObjectData::CreateAsymmetric(type, std::move(pkey));
|
||||
CHECK(key->data_);
|
||||
break;
|
||||
@ -1171,28 +1166,27 @@ void KeyObjectHandle::GetKeyDetail(const FunctionCallbackInfo<Value>& args) {
|
||||
}
|
||||
|
||||
Local<Value> KeyObjectHandle::GetAsymmetricKeyType() const {
|
||||
const auto& key = data_.GetAsymmetricKey();
|
||||
switch (EVP_PKEY_id(key.get())) {
|
||||
case EVP_PKEY_RSA:
|
||||
return env()->crypto_rsa_string();
|
||||
case EVP_PKEY_RSA_PSS:
|
||||
return env()->crypto_rsa_pss_string();
|
||||
case EVP_PKEY_DSA:
|
||||
return env()->crypto_dsa_string();
|
||||
case EVP_PKEY_DH:
|
||||
return env()->crypto_dh_string();
|
||||
case EVP_PKEY_EC:
|
||||
return env()->crypto_ec_string();
|
||||
case EVP_PKEY_ED25519:
|
||||
return env()->crypto_ed25519_string();
|
||||
case EVP_PKEY_ED448:
|
||||
return env()->crypto_ed448_string();
|
||||
case EVP_PKEY_X25519:
|
||||
return env()->crypto_x25519_string();
|
||||
case EVP_PKEY_X448:
|
||||
return env()->crypto_x448_string();
|
||||
default:
|
||||
return Undefined(env()->isolate());
|
||||
switch (data_.GetAsymmetricKey().id()) {
|
||||
case EVP_PKEY_RSA:
|
||||
return env()->crypto_rsa_string();
|
||||
case EVP_PKEY_RSA_PSS:
|
||||
return env()->crypto_rsa_pss_string();
|
||||
case EVP_PKEY_DSA:
|
||||
return env()->crypto_dsa_string();
|
||||
case EVP_PKEY_DH:
|
||||
return env()->crypto_dh_string();
|
||||
case EVP_PKEY_EC:
|
||||
return env()->crypto_ec_string();
|
||||
case EVP_PKEY_ED25519:
|
||||
return env()->crypto_ed25519_string();
|
||||
case EVP_PKEY_ED448:
|
||||
return env()->crypto_ed448_string();
|
||||
case EVP_PKEY_X25519:
|
||||
return env()->crypto_x25519_string();
|
||||
case EVP_PKEY_X448:
|
||||
return env()->crypto_x448_string();
|
||||
default:
|
||||
return Undefined(env()->isolate());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1208,9 +1202,9 @@ bool KeyObjectHandle::CheckEcKeyData() const {
|
||||
MarkPopErrorOnReturn mark_pop_error_on_return;
|
||||
|
||||
const auto& key = data_.GetAsymmetricKey();
|
||||
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(key.get(), nullptr));
|
||||
EVPKeyCtxPointer ctx = key.newCtx();
|
||||
CHECK(ctx);
|
||||
CHECK_EQ(EVP_PKEY_id(key.get()), EVP_PKEY_EC);
|
||||
CHECK_EQ(key.id(), EVP_PKEY_EC);
|
||||
|
||||
if (data_.GetKeyType() == kKeyTypePrivate) {
|
||||
return EVP_PKEY_check(ctx.get()) == 1;
|
||||
@ -1409,12 +1403,8 @@ WebCryptoKeyExportStatus PKEY_SPKI_Export(const KeyObjectData& key_data,
|
||||
ByteSource* out) {
|
||||
CHECK_EQ(key_data.GetKeyType(), kKeyTypePublic);
|
||||
Mutex::ScopedLock lock(key_data.mutex());
|
||||
const auto& m_pkey = key_data.GetAsymmetricKey();
|
||||
auto bio = BIOPointer::NewMem();
|
||||
CHECK(bio);
|
||||
if (!i2d_PUBKEY_bio(bio.get(), m_pkey.get()))
|
||||
return WebCryptoKeyExportStatus::FAILED;
|
||||
|
||||
auto bio = key_data.GetAsymmetricKey().derPublicKey();
|
||||
if (!bio) return WebCryptoKeyExportStatus::FAILED;
|
||||
*out = ByteSource::FromBIO(bio);
|
||||
return WebCryptoKeyExportStatus::OK;
|
||||
}
|
||||
|
@ -18,21 +18,23 @@
|
||||
|
||||
namespace node {
|
||||
namespace crypto {
|
||||
// TODO(@jasnell): These static casts are temporarily while this code
|
||||
// is being shifted over into ncrypto
|
||||
enum PKEncodingType {
|
||||
// RSAPublicKey / RSAPrivateKey according to PKCS#1.
|
||||
kKeyEncodingPKCS1,
|
||||
kKeyEncodingPKCS1 = static_cast<int>(EVPKeyPointer::PKEncodingType::PKCS1),
|
||||
// PrivateKeyInfo or EncryptedPrivateKeyInfo according to PKCS#8.
|
||||
kKeyEncodingPKCS8,
|
||||
kKeyEncodingPKCS8 = static_cast<int>(EVPKeyPointer::PKEncodingType::PKCS8),
|
||||
// SubjectPublicKeyInfo according to X.509.
|
||||
kKeyEncodingSPKI,
|
||||
kKeyEncodingSPKI = static_cast<int>(EVPKeyPointer::PKEncodingType::SPKI),
|
||||
// ECPrivateKey according to SEC1.
|
||||
kKeyEncodingSEC1
|
||||
kKeyEncodingSEC1 = static_cast<int>(EVPKeyPointer::PKEncodingType::SEC1),
|
||||
};
|
||||
|
||||
enum PKFormatType {
|
||||
kKeyFormatDER,
|
||||
kKeyFormatPEM,
|
||||
kKeyFormatJWK
|
||||
kKeyFormatDER = static_cast<int>(EVPKeyPointer::PKFormatType::DER),
|
||||
kKeyFormatPEM = static_cast<int>(EVPKeyPointer::PKFormatType::PEM),
|
||||
kKeyFormatJWK = static_cast<int>(EVPKeyPointer::PKFormatType::JWK),
|
||||
};
|
||||
|
||||
enum KeyType {
|
||||
@ -48,16 +50,18 @@ enum KeyEncodingContext {
|
||||
};
|
||||
|
||||
enum class ParseKeyResult {
|
||||
kParseKeyNotRecognized =
|
||||
static_cast<int>(EVPKeyPointer::PKParseError::NOT_RECOGNIZED),
|
||||
kParseKeyNeedPassphrase =
|
||||
static_cast<int>(EVPKeyPointer::PKParseError::NEED_PASSPHRASE),
|
||||
kParseKeyFailed = static_cast<int>(EVPKeyPointer::PKParseError::FAILED),
|
||||
kParseKeyOk,
|
||||
kParseKeyNotRecognized,
|
||||
kParseKeyNeedPassphrase,
|
||||
kParseKeyFailed
|
||||
};
|
||||
|
||||
struct AsymmetricKeyEncodingConfig {
|
||||
bool output_key_object_ = false;
|
||||
PKFormatType format_ = kKeyFormatDER;
|
||||
v8::Maybe<PKEncodingType> type_ = v8::Nothing<PKEncodingType>();
|
||||
std::optional<PKEncodingType> type_ = std::nullopt;
|
||||
};
|
||||
|
||||
using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig;
|
||||
|
@ -203,7 +203,7 @@ WebCryptoCipherStatus RSA_Cipher(Environment* env,
|
||||
Mutex::ScopedLock lock(key_data.mutex());
|
||||
const auto& m_pkey = key_data.GetAsymmetricKey();
|
||||
|
||||
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(m_pkey.get(), nullptr));
|
||||
EVPKeyCtxPointer ctx = m_pkey.newCtx();
|
||||
|
||||
if (!ctx || init(ctx.get()) <= 0)
|
||||
return WebCryptoCipherStatus::FAILED;
|
||||
@ -360,7 +360,7 @@ Maybe<void> ExportJWKRsaKey(Environment* env,
|
||||
Local<Object> target) {
|
||||
Mutex::ScopedLock lock(key.mutex());
|
||||
const auto& m_pkey = key.GetAsymmetricKey();
|
||||
int type = EVP_PKEY_id(m_pkey.get());
|
||||
int type = m_pkey.id();
|
||||
CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS);
|
||||
|
||||
// TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
|
||||
@ -493,7 +493,7 @@ KeyObjectData ImportJWKRsaKey(Environment* env,
|
||||
}
|
||||
}
|
||||
|
||||
EVPKeyPointer pkey(EVP_PKEY_new());
|
||||
auto pkey = EVPKeyPointer::New();
|
||||
CHECK_EQ(EVP_PKEY_set1_RSA(pkey.get(), rsa.get()), 1);
|
||||
|
||||
return KeyObjectData::CreateAsymmetric(type, std::move(pkey));
|
||||
@ -507,7 +507,7 @@ Maybe<void> GetRsaKeyDetail(Environment* env,
|
||||
|
||||
Mutex::ScopedLock lock(key.mutex());
|
||||
const auto& m_pkey = key.GetAsymmetricKey();
|
||||
int type = EVP_PKEY_id(m_pkey.get());
|
||||
int type = m_pkey.id();
|
||||
CHECK(type == EVP_PKEY_RSA || type == EVP_PKEY_RSA_PSS);
|
||||
|
||||
// TODO(tniessen): Remove the "else" branch once we drop support for OpenSSL
|
||||
|
@ -34,11 +34,11 @@ namespace crypto {
|
||||
namespace {
|
||||
bool ValidateDSAParameters(EVP_PKEY* key) {
|
||||
/* Validate DSA2 parameters from FIPS 186-4 */
|
||||
auto id = EVPKeyPointer::base_id(key);
|
||||
#if OPENSSL_VERSION_MAJOR >= 3
|
||||
if (EVP_default_properties_is_fips_enabled(nullptr) &&
|
||||
EVP_PKEY_DSA == EVP_PKEY_base_id(key)) {
|
||||
if (EVP_default_properties_is_fips_enabled(nullptr) && EVP_PKEY_DSA == id) {
|
||||
#else
|
||||
if (FIPS_mode() && EVP_PKEY_DSA == EVP_PKEY_base_id(key)) {
|
||||
if (FIPS_mode() && EVP_PKEY_DSA == id) {
|
||||
#endif
|
||||
const DSA* dsa = EVP_PKEY_get0_DSA(key);
|
||||
const BIGNUM* p;
|
||||
@ -60,9 +60,8 @@ bool ApplyRSAOptions(const EVPKeyPointer& pkey,
|
||||
EVP_PKEY_CTX* pkctx,
|
||||
int padding,
|
||||
const Maybe<int>& salt_len) {
|
||||
if (EVP_PKEY_id(pkey.get()) == EVP_PKEY_RSA ||
|
||||
EVP_PKEY_id(pkey.get()) == EVP_PKEY_RSA2 ||
|
||||
EVP_PKEY_id(pkey.get()) == EVP_PKEY_RSA_PSS) {
|
||||
int id = pkey.id();
|
||||
if (id == EVP_PKEY_RSA || id == EVP_PKEY_RSA2 || id == EVP_PKEY_RSA_PSS) {
|
||||
if (EVP_PKEY_CTX_set_rsa_padding(pkctx, padding) <= 0)
|
||||
return false;
|
||||
if (padding == RSA_PKCS1_PSS_PADDING && salt_len.IsJust()) {
|
||||
@ -85,15 +84,13 @@ std::unique_ptr<BackingStore> Node_SignFinal(Environment* env,
|
||||
if (!EVP_DigestFinal_ex(mdctx.get(), m, &m_len))
|
||||
return nullptr;
|
||||
|
||||
int signed_sig_len = EVP_PKEY_size(pkey.get());
|
||||
CHECK_GE(signed_sig_len, 0);
|
||||
size_t sig_len = static_cast<size_t>(signed_sig_len);
|
||||
size_t sig_len = pkey.size();
|
||||
std::unique_ptr<BackingStore> sig;
|
||||
{
|
||||
NoArrayBufferZeroFillScope no_zero_fill_scope(env->isolate_data());
|
||||
sig = ArrayBuffer::NewBackingStore(env->isolate(), sig_len);
|
||||
}
|
||||
EVPKeyCtxPointer pkctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
|
||||
EVPKeyCtxPointer pkctx = pkey.newCtx();
|
||||
if (pkctx && EVP_PKEY_sign_init(pkctx.get()) > 0 &&
|
||||
ApplyRSAOptions(pkey, pkctx.get(), padding, pss_salt_len) &&
|
||||
EVP_PKEY_CTX_set_signature_md(pkctx.get(), EVP_MD_CTX_md(mdctx.get())) >
|
||||
@ -120,12 +117,12 @@ std::unique_ptr<BackingStore> Node_SignFinal(Environment* env,
|
||||
}
|
||||
|
||||
int GetDefaultSignPadding(const EVPKeyPointer& m_pkey) {
|
||||
return EVP_PKEY_id(m_pkey.get()) == EVP_PKEY_RSA_PSS ? RSA_PKCS1_PSS_PADDING :
|
||||
RSA_PKCS1_PADDING;
|
||||
return m_pkey.id() == EVP_PKEY_RSA_PSS ? RSA_PKCS1_PSS_PADDING
|
||||
: RSA_PKCS1_PADDING;
|
||||
}
|
||||
|
||||
unsigned int GetBytesOfRS(const EVPKeyPointer& pkey) {
|
||||
int bits, base_id = EVP_PKEY_base_id(pkey.get());
|
||||
int bits, base_id = pkey.base_id();
|
||||
|
||||
if (base_id == EVP_PKEY_DSA) {
|
||||
const DSA* dsa_key = EVP_PKEY_get0_DSA(pkey.get());
|
||||
@ -274,23 +271,12 @@ void CheckThrow(Environment* env, SignBase::Error error) {
|
||||
}
|
||||
|
||||
bool IsOneShot(const EVPKeyPointer& key) {
|
||||
switch (EVP_PKEY_id(key.get())) {
|
||||
case EVP_PKEY_ED25519:
|
||||
case EVP_PKEY_ED448:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return key.id() == EVP_PKEY_ED25519 || key.id() == EVP_PKEY_ED448;
|
||||
}
|
||||
|
||||
bool UseP1363Encoding(const EVPKeyPointer& key, const DSASigEnc& dsa_encoding) {
|
||||
switch (EVP_PKEY_id(key.get())) {
|
||||
case EVP_PKEY_EC:
|
||||
case EVP_PKEY_DSA:
|
||||
return dsa_encoding == kSigEncP1363;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return (key.id() == EVP_PKEY_EC || key.id() == EVP_PKEY_DSA) &&
|
||||
dsa_encoding == kSigEncP1363;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@ -530,7 +516,7 @@ SignBase::Error Verify::VerifyFinal(const EVPKeyPointer& pkey,
|
||||
if (!EVP_DigestFinal_ex(mdctx.get(), m, &m_len))
|
||||
return kSignPublicKey;
|
||||
|
||||
EVPKeyCtxPointer pkctx(EVP_PKEY_CTX_new(pkey.get(), nullptr));
|
||||
EVPKeyCtxPointer pkctx = pkey.newCtx();
|
||||
if (pkctx) {
|
||||
const int init_ret = EVP_PKEY_verify_init(pkctx.get());
|
||||
if (init_ret == -2) {
|
||||
|
Loading…
Reference in New Issue
Block a user