mirror of
https://github.com/quizhizhe/LiteLoaderBDS-1.16.40.git
synced 2025-06-07 20:28:10 +00:00
421 lines
12 KiB
C++
421 lines
12 KiB
C++
#ifndef SRC_CRYPTO_CRYPTO_KEYS_H_
|
|
#define SRC_CRYPTO_CRYPTO_KEYS_H_
|
|
|
|
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
|
|
|
#include "crypto/crypto_util.h"
|
|
#include "base_object.h"
|
|
#include "env.h"
|
|
#include "memory_tracker.h"
|
|
#include "node_buffer.h"
|
|
#include "node_worker.h"
|
|
#include "v8.h"
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
namespace node {
|
|
namespace crypto {
|
|
enum PKEncodingType {
|
|
// RSAPublicKey / RSAPrivateKey according to PKCS#1.
|
|
kKeyEncodingPKCS1,
|
|
// PrivateKeyInfo or EncryptedPrivateKeyInfo according to PKCS#8.
|
|
kKeyEncodingPKCS8,
|
|
// SubjectPublicKeyInfo according to X.509.
|
|
kKeyEncodingSPKI,
|
|
// ECPrivateKey according to SEC1.
|
|
kKeyEncodingSEC1
|
|
};
|
|
|
|
enum PKFormatType {
|
|
kKeyFormatDER,
|
|
kKeyFormatPEM,
|
|
kKeyFormatJWK
|
|
};
|
|
|
|
enum KeyType {
|
|
kKeyTypeSecret,
|
|
kKeyTypePublic,
|
|
kKeyTypePrivate
|
|
};
|
|
|
|
enum KeyEncodingContext {
|
|
kKeyContextInput,
|
|
kKeyContextExport,
|
|
kKeyContextGenerate
|
|
};
|
|
|
|
enum class ParseKeyResult {
|
|
kParseKeyOk,
|
|
kParseKeyNotRecognized,
|
|
kParseKeyNeedPassphrase,
|
|
kParseKeyFailed
|
|
};
|
|
|
|
struct AsymmetricKeyEncodingConfig {
|
|
bool output_key_object_ = false;
|
|
PKFormatType format_ = kKeyFormatDER;
|
|
v8::Maybe<PKEncodingType> type_ = v8::Nothing<PKEncodingType>();
|
|
};
|
|
|
|
using PublicKeyEncodingConfig = AsymmetricKeyEncodingConfig;
|
|
|
|
struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig {
|
|
const EVP_CIPHER* cipher_;
|
|
// The ByteSource alone is not enough to distinguish between "no passphrase"
|
|
// and a zero-length passphrase (which can be a null pointer), therefore, we
|
|
// use a NonCopyableMaybe.
|
|
NonCopyableMaybe<ByteSource> passphrase_;
|
|
};
|
|
|
|
// This uses the built-in reference counter of OpenSSL to manage an EVP_PKEY
|
|
// which is slightly more efficient than using a shared pointer and easier to
|
|
// use.
|
|
class ManagedEVPPKey : public MemoryRetainer {
|
|
public:
|
|
ManagedEVPPKey() : mutex_(std::make_shared<Mutex>()) {}
|
|
explicit ManagedEVPPKey(EVPKeyPointer&& pkey);
|
|
ManagedEVPPKey(const ManagedEVPPKey& that);
|
|
ManagedEVPPKey& operator=(const ManagedEVPPKey& that);
|
|
|
|
operator bool() const;
|
|
EVP_PKEY* get() const;
|
|
Mutex* mutex() const;
|
|
|
|
void MemoryInfo(MemoryTracker* tracker) const override;
|
|
SET_MEMORY_INFO_NAME(ManagedEVPPKey)
|
|
SET_SELF_SIZE(ManagedEVPPKey)
|
|
|
|
static PublicKeyEncodingConfig GetPublicKeyEncodingFromJs(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
unsigned int* offset,
|
|
KeyEncodingContext context);
|
|
|
|
static NonCopyableMaybe<PrivateKeyEncodingConfig> GetPrivateKeyEncodingFromJs(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
unsigned int* offset,
|
|
KeyEncodingContext context);
|
|
|
|
static ManagedEVPPKey GetParsedKey(Environment* env,
|
|
EVPKeyPointer&& pkey,
|
|
ParseKeyResult ret,
|
|
const char* default_msg);
|
|
|
|
static ManagedEVPPKey GetPublicOrPrivateKeyFromJs(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
unsigned int* offset);
|
|
|
|
static ManagedEVPPKey GetPrivateKeyFromJs(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
unsigned int* offset,
|
|
bool allow_key_object);
|
|
|
|
static v8::Maybe<bool> ToEncodedPublicKey(
|
|
Environment* env,
|
|
ManagedEVPPKey key,
|
|
const PublicKeyEncodingConfig& config,
|
|
v8::Local<v8::Value>* out);
|
|
|
|
static v8::Maybe<bool> ToEncodedPrivateKey(
|
|
Environment* env,
|
|
ManagedEVPPKey key,
|
|
const PrivateKeyEncodingConfig& config,
|
|
v8::Local<v8::Value>* out);
|
|
|
|
private:
|
|
size_t size_of_private_key() const;
|
|
size_t size_of_public_key() const;
|
|
|
|
EVPKeyPointer pkey_;
|
|
std::shared_ptr<Mutex> mutex_;
|
|
};
|
|
|
|
// Objects of this class can safely be shared among threads.
|
|
class KeyObjectData : public MemoryRetainer {
|
|
public:
|
|
static std::shared_ptr<KeyObjectData> CreateSecret(ByteSource key);
|
|
|
|
static std::shared_ptr<KeyObjectData> CreateAsymmetric(
|
|
KeyType type,
|
|
const ManagedEVPPKey& pkey);
|
|
|
|
KeyType GetKeyType() const;
|
|
|
|
// These functions allow unprotected access to the raw key material and should
|
|
// only be used to implement cryptographic operations requiring the key.
|
|
ManagedEVPPKey GetAsymmetricKey() const;
|
|
const char* GetSymmetricKey() const;
|
|
size_t GetSymmetricKeySize() const;
|
|
|
|
void MemoryInfo(MemoryTracker* tracker) const override;
|
|
SET_MEMORY_INFO_NAME(KeyObjectData)
|
|
SET_SELF_SIZE(KeyObjectData)
|
|
|
|
private:
|
|
explicit KeyObjectData(ByteSource symmetric_key);
|
|
|
|
KeyObjectData(
|
|
KeyType type,
|
|
const ManagedEVPPKey& pkey);
|
|
|
|
const KeyType key_type_;
|
|
const ByteSource symmetric_key_;
|
|
const unsigned int symmetric_key_len_;
|
|
const ManagedEVPPKey asymmetric_key_;
|
|
};
|
|
|
|
class KeyObjectHandle : public BaseObject {
|
|
public:
|
|
static v8::Local<v8::Function> Initialize(Environment* env);
|
|
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
|
|
|
static v8::MaybeLocal<v8::Object> Create(Environment* env,
|
|
std::shared_ptr<KeyObjectData> data);
|
|
|
|
// TODO(tniessen): track the memory used by OpenSSL types
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(KeyObjectHandle)
|
|
SET_SELF_SIZE(KeyObjectHandle)
|
|
|
|
const std::shared_ptr<KeyObjectData>& Data();
|
|
|
|
protected:
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void InitECRaw(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void InitEDRaw(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void InitJWK(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetKeyDetail(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void Equals(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static void ExportJWK(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static void GetAsymmetricKeyType(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
v8::Local<v8::Value> GetAsymmetricKeyType() const;
|
|
|
|
static void GetSymmetricKeySize(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static void Export(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
v8::MaybeLocal<v8::Value> ExportSecretKey() const;
|
|
v8::MaybeLocal<v8::Value> ExportPublicKey(
|
|
const PublicKeyEncodingConfig& config) const;
|
|
v8::MaybeLocal<v8::Value> ExportPrivateKey(
|
|
const PrivateKeyEncodingConfig& config) const;
|
|
|
|
KeyObjectHandle(Environment* env,
|
|
v8::Local<v8::Object> wrap);
|
|
|
|
private:
|
|
std::shared_ptr<KeyObjectData> data_;
|
|
};
|
|
|
|
class NativeKeyObject : public BaseObject {
|
|
public:
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
|
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void CreateNativeKeyObjectClass(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(NativeKeyObject)
|
|
SET_SELF_SIZE(NativeKeyObject)
|
|
|
|
class KeyObjectTransferData : public worker::TransferData {
|
|
public:
|
|
explicit KeyObjectTransferData(const std::shared_ptr<KeyObjectData>& data)
|
|
: data_(data) {}
|
|
|
|
BaseObjectPtr<BaseObject> Deserialize(
|
|
Environment* env,
|
|
v8::Local<v8::Context> context,
|
|
std::unique_ptr<worker::TransferData> self) override;
|
|
|
|
SET_MEMORY_INFO_NAME(KeyObjectTransferData)
|
|
SET_SELF_SIZE(KeyObjectTransferData)
|
|
SET_NO_MEMORY_INFO()
|
|
|
|
private:
|
|
std::shared_ptr<KeyObjectData> data_;
|
|
};
|
|
|
|
BaseObject::TransferMode GetTransferMode() const override;
|
|
std::unique_ptr<worker::TransferData> CloneForMessaging() const override;
|
|
|
|
private:
|
|
NativeKeyObject(Environment* env,
|
|
v8::Local<v8::Object> wrap,
|
|
const std::shared_ptr<KeyObjectData>& handle_data)
|
|
: BaseObject(env, wrap),
|
|
handle_data_(handle_data) {
|
|
MakeWeak();
|
|
}
|
|
|
|
std::shared_ptr<KeyObjectData> handle_data_;
|
|
};
|
|
|
|
enum WebCryptoKeyFormat {
|
|
kWebCryptoKeyFormatRaw,
|
|
kWebCryptoKeyFormatPKCS8,
|
|
kWebCryptoKeyFormatSPKI,
|
|
kWebCryptoKeyFormatJWK
|
|
};
|
|
|
|
enum class WebCryptoKeyExportStatus {
|
|
OK,
|
|
INVALID_KEY_TYPE,
|
|
FAILED
|
|
};
|
|
|
|
template <typename KeyExportTraits>
|
|
class KeyExportJob final : public CryptoJob<KeyExportTraits> {
|
|
public:
|
|
using AdditionalParams = typename KeyExportTraits::AdditionalParameters;
|
|
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|
Environment* env = Environment::GetCurrent(args);
|
|
CHECK(args.IsConstructCall());
|
|
|
|
CryptoJobMode mode = GetCryptoJobMode(args[0]);
|
|
|
|
CHECK(args[1]->IsUint32()); // Export Type
|
|
CHECK(args[2]->IsObject()); // KeyObject
|
|
|
|
WebCryptoKeyFormat format =
|
|
static_cast<WebCryptoKeyFormat>(args[1].As<v8::Uint32>()->Value());
|
|
|
|
KeyObjectHandle* key;
|
|
ASSIGN_OR_RETURN_UNWRAP(&key, args[2]);
|
|
|
|
CHECK_NOT_NULL(key);
|
|
|
|
AdditionalParams params;
|
|
if (KeyExportTraits::AdditionalConfig(args, 3, ¶ms).IsNothing()) {
|
|
// The KeyExportTraits::AdditionalConfig is responsible for
|
|
// calling an appropriate THROW_CRYPTO_* variant reporting
|
|
// whatever error caused initialization to fail.
|
|
return;
|
|
}
|
|
|
|
new KeyExportJob<KeyExportTraits>(
|
|
env,
|
|
args.This(),
|
|
mode,
|
|
key->Data(),
|
|
format,
|
|
std::move(params));
|
|
}
|
|
|
|
static void Initialize(
|
|
Environment* env,
|
|
v8::Local<v8::Object> target) {
|
|
CryptoJob<KeyExportTraits>::Initialize(New, env, target);
|
|
}
|
|
|
|
static void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
|
|
CryptoJob<KeyExportTraits>::RegisterExternalReferences(New, registry);
|
|
}
|
|
|
|
KeyExportJob(
|
|
Environment* env,
|
|
v8::Local<v8::Object> object,
|
|
CryptoJobMode mode,
|
|
std::shared_ptr<KeyObjectData> key,
|
|
WebCryptoKeyFormat format,
|
|
AdditionalParams&& params)
|
|
: CryptoJob<KeyExportTraits>(
|
|
env,
|
|
object,
|
|
AsyncWrap::PROVIDER_KEYEXPORTREQUEST,
|
|
mode,
|
|
std::move(params)),
|
|
key_(key),
|
|
format_(format) {}
|
|
|
|
WebCryptoKeyFormat format() const { return format_; }
|
|
|
|
void DoThreadPoolWork() override {
|
|
const WebCryptoKeyExportStatus status =
|
|
KeyExportTraits::DoExport(
|
|
key_,
|
|
format_,
|
|
*CryptoJob<KeyExportTraits>::params(),
|
|
&out_);
|
|
if (status == WebCryptoKeyExportStatus::OK) {
|
|
// Success!
|
|
return;
|
|
}
|
|
CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors();
|
|
errors->Capture();
|
|
if (errors->Empty()) {
|
|
switch (status) {
|
|
case WebCryptoKeyExportStatus::OK:
|
|
UNREACHABLE();
|
|
break;
|
|
case WebCryptoKeyExportStatus::INVALID_KEY_TYPE:
|
|
errors->Insert(NodeCryptoError::INVALID_KEY_TYPE);
|
|
break;
|
|
case WebCryptoKeyExportStatus::FAILED:
|
|
errors->Insert(NodeCryptoError::CIPHER_JOB_FAILED);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
v8::Maybe<bool> ToResult(
|
|
v8::Local<v8::Value>* err,
|
|
v8::Local<v8::Value>* result) override {
|
|
Environment* env = AsyncWrap::env();
|
|
CryptoErrorStore* errors = CryptoJob<KeyExportTraits>::errors();
|
|
if (out_.size() > 0) {
|
|
CHECK(errors->Empty());
|
|
*err = v8::Undefined(env->isolate());
|
|
*result = out_.ToArrayBuffer(env);
|
|
return v8::Just(!result->IsEmpty());
|
|
}
|
|
|
|
if (errors->Empty())
|
|
errors->Capture();
|
|
CHECK(!errors->Empty());
|
|
*result = v8::Undefined(env->isolate());
|
|
return v8::Just(errors->ToException(env).ToLocal(err));
|
|
}
|
|
|
|
SET_SELF_SIZE(KeyExportJob)
|
|
void MemoryInfo(MemoryTracker* tracker) const override {
|
|
tracker->TrackFieldWithSize("out", out_.size());
|
|
CryptoJob<KeyExportTraits>::MemoryInfo(tracker);
|
|
}
|
|
|
|
private:
|
|
std::shared_ptr<KeyObjectData> key_;
|
|
WebCryptoKeyFormat format_;
|
|
ByteSource out_;
|
|
};
|
|
|
|
WebCryptoKeyExportStatus PKEY_SPKI_Export(
|
|
KeyObjectData* key_data,
|
|
ByteSource* out);
|
|
|
|
WebCryptoKeyExportStatus PKEY_PKCS8_Export(
|
|
KeyObjectData* key_data,
|
|
ByteSource* out);
|
|
|
|
namespace Keys {
|
|
void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
void RegisterExternalReferences(ExternalReferenceRegistry* registry);
|
|
} // namespace Keys
|
|
|
|
} // namespace crypto
|
|
} // namespace node
|
|
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
|
#endif // SRC_CRYPTO_CRYPTO_KEYS_H_
|