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

crypto: add API to retrieve key type OID #26709

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 10 additions & 0 deletions doc/api/crypto.md
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,16 @@ For asymmetric keys, this property represents the type of the embedded key
(`'rsa'`, `'dsa'`, `'ec'`, `'ed25519'`, or `'ed448'`).
This property is `undefined` for symmetric keys.

### keyObject.asymmetricKeyTypeOid
<!-- YAML
added: REPLACEME
-->
* {string}

For asymmetric keys, this property represents the numerical representation of
the OID of the type of the embedded key, e.g., `'1.3.101.113'` for `'ed448'`.
This property is `undefined` for symmetric keys.

### keyObject.export([options])
<!-- YAML
added: v11.6.0
Expand Down
6 changes: 6 additions & 0 deletions lib/internal/crypto/keys.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,18 @@ class SecretKeyObject extends KeyObject {
}

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

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

get asymmetricKeyTypeOid() {
return this[kAsymmetricKeyOid] ||
(this[kAsymmetricKeyOid] = this[kHandle].getAsymmetricKeyTypeOid());
}
}

class PublicKeyObject extends AsymmetricKeyObject {
Expand Down
20 changes: 20 additions & 0 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3333,6 +3333,8 @@ Local<Function> KeyObject::Initialize(Environment* env, Local<Object> target) {
GetSymmetricKeySize);
env->SetProtoMethodNoSideEffect(t, "getAsymmetricKeyType",
GetAsymmetricKeyType);
env->SetProtoMethodNoSideEffect(t, "getAsymmetricKeyTypeOid",
GetAsymmetricKeyTypeOid);
env->SetProtoMethod(t, "export", Export);

auto function = t->GetFunction(env->context()).ToLocalChecked();
Expand Down Expand Up @@ -3477,6 +3479,24 @@ void KeyObject::GetAsymmetricKeyType(const FunctionCallbackInfo<Value>& args) {
args.GetReturnValue().Set(key->GetAsymmetricKeyType());
}

void KeyObject::GetAsymmetricKeyTypeOid(
const v8::FunctionCallbackInfo<v8::Value>& args) {
KeyObject* key;
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder());
args.GetReturnValue().Set(key->GetAsymmetricKeyTypeOid());
}

v8::Local<v8::String> KeyObject::GetAsymmetricKeyTypeOid() const {
CHECK_NE(this->key_type_, kKeyTypeSecret);

int id = EVP_PKEY_id(asymmetric_key_.get());
ASN1_OBJECT* obj = OBJ_nid2obj(id);
char buf[1024];
CHECK(OBJ_obj2txt(buf, sizeof(buf), obj, true));
return String::NewFromUtf8(env()->isolate(), buf, NewStringType::kNormal)
.ToLocalChecked();
}

void KeyObject::GetSymmetricKeySize(const FunctionCallbackInfo<Value>& args) {
KeyObject* key;
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder());
Expand Down
4 changes: 4 additions & 0 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,10 @@ class KeyObject : public BaseObject {
const v8::FunctionCallbackInfo<v8::Value>& args);
v8::Local<v8::String> GetAsymmetricKeyType() const;

static void GetAsymmetricKeyTypeOid(
const v8::FunctionCallbackInfo<v8::Value>& args);
v8::Local<v8::String> GetAsymmetricKeyTypeOid() const;

static void GetSymmetricKeySize(
const v8::FunctionCallbackInfo<v8::Value>& args);

Expand Down
12 changes: 10 additions & 2 deletions test/parallel/test-crypto-key-objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const privatePem = fixtures.readSync('test_rsa_privkey.pem', 'ascii');
assert.strictEqual(key.type, 'secret');
assert.strictEqual(key.symmetricKeySize, 32);
assert.strictEqual(key.asymmetricKeyType, undefined);
assert.strictEqual(key.asymmetricKeyTypeOid, undefined);

const exportedKey = key.export();
assert(keybuf.equals(exportedKey));
Expand Down Expand Up @@ -91,17 +92,20 @@ const privatePem = fixtures.readSync('test_rsa_privkey.pem', 'ascii');
const publicKey = createPublicKey(publicPem);
assert.strictEqual(publicKey.type, 'public');
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa');
assert.strictEqual(publicKey.asymmetricKeyTypeOid, '1.2.840.113549.1.1.1');
assert.strictEqual(publicKey.symmetricKeySize, undefined);

const privateKey = createPrivateKey(privatePem);
assert.strictEqual(privateKey.type, 'private');
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa');
assert.strictEqual(publicKey.asymmetricKeyTypeOid, '1.2.840.113549.1.1.1');
assert.strictEqual(privateKey.symmetricKeySize, undefined);

// It should be possible to derive a public key from a private key.
const derivedPublicKey = createPublicKey(privateKey);
assert.strictEqual(derivedPublicKey.type, 'public');
assert.strictEqual(derivedPublicKey.asymmetricKeyType, 'rsa');
assert.strictEqual(publicKey.asymmetricKeyTypeOid, '1.2.840.113549.1.1.1');
assert.strictEqual(derivedPublicKey.symmetricKeySize, undefined);

// Test exporting with an invalid options object, this should throw.
Expand Down Expand Up @@ -171,10 +175,12 @@ const privatePem = fixtures.readSync('test_rsa_privkey.pem', 'ascii');
[
{ private: fixtures.readSync('test_ed25519_privkey.pem', 'ascii'),
public: fixtures.readSync('test_ed25519_pubkey.pem', 'ascii'),
keyType: 'ed25519' },
keyType: 'ed25519',
oid: '1.3.101.112' },
{ private: fixtures.readSync('test_ed448_privkey.pem', 'ascii'),
public: fixtures.readSync('test_ed448_pubkey.pem', 'ascii'),
keyType: 'ed448' }
keyType: 'ed448',
oid: '1.3.101.113' }
].forEach((info) => {
const keyType = info.keyType;

Expand All @@ -183,6 +189,7 @@ const privatePem = fixtures.readSync('test_rsa_privkey.pem', 'ascii');
const key = createPrivateKey(info.private);
assert.strictEqual(key.type, 'private');
assert.strictEqual(key.asymmetricKeyType, keyType);
assert.strictEqual(key.asymmetricKeyTypeOid, info.oid);
assert.strictEqual(key.symmetricKeySize, undefined);
assert.strictEqual(key.export(exportOptions), info.private);
}
Expand All @@ -193,6 +200,7 @@ const privatePem = fixtures.readSync('test_rsa_privkey.pem', 'ascii');
const key = createPublicKey(pem);
assert.strictEqual(key.type, 'public');
assert.strictEqual(key.asymmetricKeyType, keyType);
assert.strictEqual(key.asymmetricKeyTypeOid, info.oid);
assert.strictEqual(key.symmetricKeySize, undefined);
assert.strictEqual(key.export(exportOptions), info.public);
});
Expand Down
20 changes: 20 additions & 0 deletions test/parallel/test-crypto-keygen.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ if (!common.hasCrypto)

const assert = require('assert');
const {
createPrivateKey,
createPublicKey,
createSign,
createVerify,
generateKeyPair,
Expand Down Expand Up @@ -108,10 +110,12 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
assert.strictEqual(typeof publicKey, 'object');
assert.strictEqual(publicKey.type, 'public');
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa');
assert.strictEqual(publicKey.asymmetricKeyTypeOid, '1.2.840.113549.1.1.1');

assert.strictEqual(typeof privateKey, 'object');
assert.strictEqual(privateKey.type, 'private');
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa');
assert.strictEqual(publicKey.asymmetricKeyTypeOid, '1.2.840.113549.1.1.1');
}

{
Expand Down Expand Up @@ -273,6 +277,15 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
assertApproximateSize(publicKey, 440);
assertApproximateSize(privateKeyDER, 336);

assert.strictEqual(createPublicKey(publicKey).asymmetricKeyTypeOid,
'1.2.840.10040.4.1');
assert.strictEqual(createPrivateKey({
key: privateKeyDER,
...privateKeyEncoding,
passphrase: 'secret'
}).asymmetricKeyTypeOid,
'1.2.840.10040.4.1');

// Since the private key is encrypted, signing shouldn't work anymore.
assert.throws(() => {
testSignVerify(publicKey, {
Expand Down Expand Up @@ -312,6 +325,11 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
assert.strictEqual(typeof privateKey, 'string');
assert(sec1Exp.test(privateKey));

assert.strictEqual(createPublicKey(publicKey).asymmetricKeyTypeOid,
'1.2.840.10045.2.1');
assert.strictEqual(createPrivateKey(privateKey).asymmetricKeyTypeOid,
'1.2.840.10045.2.1');

testSignVerify(publicKey, privateKey);
}));

Expand Down Expand Up @@ -453,6 +471,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
assert.strictEqual(typeof publicKey, 'object');
assert.strictEqual(publicKey.type, 'public');
assert.strictEqual(publicKey.asymmetricKeyType, 'rsa');
assert.strictEqual(publicKey.asymmetricKeyTypeOid, '1.2.840.113549.1.1.1');

// The private key should still be a string.
assert.strictEqual(typeof privateKey, 'string');
Expand All @@ -477,6 +496,7 @@ const sec1EncExp = (cipher) => getRegExpForPEM('EC PRIVATE KEY', cipher);
assert.strictEqual(typeof privateKey, 'object');
assert.strictEqual(privateKey.type, 'private');
assert.strictEqual(privateKey.asymmetricKeyType, 'rsa');
assert.strictEqual(privateKey.asymmetricKeyTypeOid, '1.2.840.113549.1.1.1');

testEncryptDecrypt(publicKey, privateKey);
testSignVerify(publicKey, privateKey);
Expand Down