Skip to content

Commit

Permalink
src: add NativeKeyObject base class
Browse files Browse the repository at this point in the history
             +---------------------+
             |     BaseObject      |
             +---------------------+
                        |
                        |
                        |
             +---------------------+
             |   NativeKeyObject   |
             +---------------------+
                        |
                        |
                        |
             +---------------------+
             |      KeyObject      |
             +---------------------+
               /                 \
              /                   \
             /                     \
            /                       \
+---------------------+    +---------------------+
|   SecretKeyObject   |    | AsymmetricKeyObject |
+---------------------+    +---------------------+
                             /                 \
                            /                   \
                           /                     \
                          /                       \
              +---------------------+   +---------------------+
              |   PublicKeyObject   |   |   PrivateKeyObject  |
              +---------------------+   +---------------------+

PR-URL: #33360
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
tniessen authored and addaleax committed Sep 27, 2020
1 parent 21a0fe9 commit 4b98356
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 59 deletions.
135 changes: 76 additions & 59 deletions lib/internal/crypto/keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const {

const {
KeyObjectHandle,
createNativeKeyObjectClass,
kKeyTypeSecret,
kKeyTypePublic,
kKeyTypePrivate,
Expand Down Expand Up @@ -42,80 +43,96 @@ for (const m of [[kKeyEncodingPKCS1, 'pkcs1'], [kKeyEncodingPKCS8, 'pkcs8'],
[kKeyEncodingSPKI, 'spki'], [kKeyEncodingSEC1, 'sec1']])
encodingNames[m[0]] = m[1];

class KeyObject {
constructor(type, handle) {
if (type !== 'secret' && type !== 'public' && type !== 'private')
throw new ERR_INVALID_ARG_VALUE('type', type);
if (typeof handle !== 'object')
throw new ERR_INVALID_ARG_TYPE('handle', 'object', handle);

this[kKeyType] = type;

ObjectDefineProperty(this, kHandle, {
value: handle,
enumerable: false,
configurable: false,
writable: false
});
}
// Creating the KeyObject class is a little complicated due to inheritance
// and that fact that KeyObjects should be transferrable between threads,
// which requires the KeyObject base class to be implemented in C++.
// The creation requires a callback to make sure that the NativeKeyObject
// base class cannot exist without the other KeyObject implementations.
const [
KeyObject,
SecretKeyObject,
PublicKeyObject,
PrivateKeyObject
] = createNativeKeyObjectClass((NativeKeyObject) => {
// Publicly visible KeyObject class.
class KeyObject extends NativeKeyObject {
constructor(type, handle) {
super();
if (type !== 'secret' && type !== 'public' && type !== 'private')
throw new ERR_INVALID_ARG_VALUE('type', type);
if (typeof handle !== 'object')
throw new ERR_INVALID_ARG_TYPE('handle', 'object', handle);

this[kKeyType] = type;

ObjectDefineProperty(this, kHandle, {
value: handle,
enumerable: false,
configurable: false,
writable: false
});
}

get type() {
return this[kKeyType];
get type() {
return this[kKeyType];
}
}
}

class SecretKeyObject extends KeyObject {
constructor(handle) {
super('secret', handle);
}
class SecretKeyObject extends KeyObject {
constructor(handle) {
super('secret', handle);
}

get symmetricKeySize() {
return this[kHandle].getSymmetricKeySize();
}
get symmetricKeySize() {
return this[kHandle].getSymmetricKeySize();
}

export() {
return this[kHandle].export();
export() {
return this[kHandle].export();
}
}
}

const kAsymmetricKeyType = Symbol('kAsymmetricKeyType');
const kAsymmetricKeyType = Symbol('kAsymmetricKeyType');

class AsymmetricKeyObject extends KeyObject {
get asymmetricKeyType() {
return this[kAsymmetricKeyType] ||
(this[kAsymmetricKeyType] = this[kHandle].getAsymmetricKeyType());
class AsymmetricKeyObject extends KeyObject {
get asymmetricKeyType() {
return this[kAsymmetricKeyType] ||
(this[kAsymmetricKeyType] = this[kHandle].getAsymmetricKeyType());
}
}
}

class PublicKeyObject extends AsymmetricKeyObject {
constructor(handle) {
super('public', handle);
}
class PublicKeyObject extends AsymmetricKeyObject {
constructor(handle) {
super('public', handle);
}

export(encoding) {
const {
format,
type
} = parsePublicKeyEncoding(encoding, this.asymmetricKeyType);
return this[kHandle].export(format, type);
export(encoding) {
const {
format,
type
} = parsePublicKeyEncoding(encoding, this.asymmetricKeyType);
return this[kHandle].export(format, type);
}
}
}

class PrivateKeyObject extends AsymmetricKeyObject {
constructor(handle) {
super('private', handle);
}
class PrivateKeyObject extends AsymmetricKeyObject {
constructor(handle) {
super('private', handle);
}

export(encoding) {
const {
format,
type,
cipher,
passphrase
} = parsePrivateKeyEncoding(encoding, this.asymmetricKeyType);
return this[kHandle].export(format, type, cipher, passphrase);
export(encoding) {
const {
format,
type,
cipher,
passphrase
} = parsePrivateKeyEncoding(encoding, this.asymmetricKeyType);
return this[kHandle].export(format, type, cipher, passphrase);
}
}
}

return [KeyObject, SecretKeyObject, PublicKeyObject, PrivateKeyObject];
});

function parseKeyFormat(formatStr, defaultFormat, optionName) {
if (formatStr === undefined && defaultFormat !== undefined)
Expand Down
27 changes: 27 additions & 0 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3430,6 +3430,31 @@ MaybeLocal<Value> KeyObjectHandle::ExportPrivateKey(
return WritePrivateKey(env(), asymmetric_key_.get(), config);
}

void NativeKeyObject::New(const FunctionCallbackInfo<Value>& args) {
CHECK_EQ(args.Length(), 0);
}

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

CHECK_EQ(args.Length(), 1);
Local<Value> callback = args[0];
CHECK(callback->IsFunction());

Local<FunctionTemplate> t = env->NewFunctionTemplate(NativeKeyObject::New);
t->InstanceTemplate()->SetInternalFieldCount(
KeyObjectHandle::kInternalFieldCount);

Local<Value> ctor = t->GetFunction(env->context()).ToLocalChecked();

Local<Value> recv = Undefined(env->isolate());
Local<Value> ret =
callback.As<Function>()->Call(env->context(), recv, 1, &ctor)
.ToLocalChecked();
args.GetReturnValue().Set(ret);
}

CipherBase::CipherBase(Environment* env,
Local<Object> wrap,
CipherKind kind)
Expand Down Expand Up @@ -6901,6 +6926,8 @@ void Initialize(Local<Object> target,
SecureContext::Initialize(env, target);
env->set_crypto_key_object_handle_constructor(
KeyObjectHandle::Initialize(env, target));
env->SetMethod(target, "createNativeKeyObjectClass",
CreateNativeKeyObjectClass);
CipherBase::Initialize(env, target);
DiffieHellman::Initialize(env, target);
ECDH::Initialize(env, target);
Expand Down
9 changes: 9 additions & 0 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,15 @@ class KeyObjectHandle : public BaseObject {
ManagedEVPPKey asymmetric_key_;
};

class NativeKeyObject : public BaseObject {
public:
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);

SET_NO_MEMORY_INFO()
SET_MEMORY_INFO_NAME(NativeKeyObject)
SET_SELF_SIZE(NativeKeyObject)
};

class CipherBase : public BaseObject {
public:
static void Initialize(Environment* env, v8::Local<v8::Object> target);
Expand Down

0 comments on commit 4b98356

Please sign in to comment.