Skip to content

Commit 692c8ff

Browse files
committed
crypto: ensure valid point on elliptic curve in SubtleCrypto.importKey
1 parent badba8c commit 692c8ff

File tree

4 files changed

+111
-0
lines changed

4 files changed

+111
-0
lines changed

lib/internal/crypto/ec.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@ async function ecImportKey(
264264
break;
265265
}
266266

267+
if (keyObject[kHandle].checkKeyData() === 0) {
268+
throw lazyDOMException('Invalid keyData', 'DataError');
269+
}
270+
267271
const {
268272
namedCurve: checkNamedCurve,
269273
} = keyObject[kHandle].keyDetail({});

src/crypto/crypto_keys.cc

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,6 +907,8 @@ v8::Local<v8::Function> KeyObjectHandle::Initialize(Environment* env) {
907907
isolate, templ, "getSymmetricKeySize", GetSymmetricKeySize);
908908
SetProtoMethodNoSideEffect(
909909
isolate, templ, "getAsymmetricKeyType", GetAsymmetricKeyType);
910+
SetProtoMethodNoSideEffect(
911+
isolate, templ, "checkKeyData", CheckKeyData);
910912
SetProtoMethod(isolate, templ, "export", Export);
911913
SetProtoMethod(isolate, templ, "exportJwk", ExportJWK);
912914
SetProtoMethod(isolate, templ, "initECRaw", InitECRaw);
@@ -926,6 +928,7 @@ void KeyObjectHandle::RegisterExternalReferences(
926928
registry->Register(Init);
927929
registry->Register(GetSymmetricKeySize);
928930
registry->Register(GetAsymmetricKeyType);
931+
registry->Register(CheckKeyData);
929932
registry->Register(Export);
930933
registry->Register(ExportJWK);
931934
registry->Register(InitECRaw);
@@ -1237,6 +1240,46 @@ void KeyObjectHandle::GetAsymmetricKeyType(
12371240
args.GetReturnValue().Set(key->GetAsymmetricKeyType());
12381241
}
12391242

1243+
int KeyObjectHandle::CheckKeyData() const {
1244+
MarkPopErrorOnReturn mark_pop_error_on_return;
1245+
1246+
const ManagedEVPPKey& key = data_->GetAsymmetricKey();
1247+
switch (EVP_PKEY_id(key.get())) {
1248+
case EVP_PKEY_EC: {
1249+
switch (data_->GetKeyType()) {
1250+
case kKeyTypePublic:
1251+
#if OPENSSL_VERSION_MAJOR >= 3
1252+
return EVP_PKEY_public_check_quick(
1253+
EVP_PKEY_CTX_new(key.get(), nullptr));
1254+
#else
1255+
return EVP_PKEY_public_check(
1256+
EVP_PKEY_CTX_new(key.get(), nullptr));
1257+
#endif
1258+
case kKeyTypePrivate:
1259+
#if OPENSSL_VERSION_MAJOR >= 3
1260+
return EVP_PKEY_pairwise_check(
1261+
EVP_PKEY_CTX_new(key.get(), nullptr));
1262+
#else
1263+
return EVP_PKEY_check(
1264+
EVP_PKEY_CTX_new(key.get(), nullptr));
1265+
#endif
1266+
default:
1267+
UNREACHABLE();
1268+
}
1269+
}
1270+
default:
1271+
UNREACHABLE();
1272+
}
1273+
}
1274+
1275+
void KeyObjectHandle::CheckKeyData(
1276+
const FunctionCallbackInfo<Value>& args) {
1277+
KeyObjectHandle* key;
1278+
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder());
1279+
1280+
args.GetReturnValue().Set(key->CheckKeyData());
1281+
}
1282+
12401283
void KeyObjectHandle::GetSymmetricKeySize(
12411284
const FunctionCallbackInfo<Value>& args) {
12421285
KeyObjectHandle* key;

src/crypto/crypto_keys.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,10 @@ class KeyObjectHandle : public BaseObject {
193193
const v8::FunctionCallbackInfo<v8::Value>& args);
194194
v8::Local<v8::Value> GetAsymmetricKeyType() const;
195195

196+
static void CheckKeyData(
197+
const v8::FunctionCallbackInfo<v8::Value>& args);
198+
int CheckKeyData() const;
199+
196200
static void GetSymmetricKeySize(
197201
const v8::FunctionCallbackInfo<v8::Value>& args);
198202

test/parallel/test-webcrypto-export-import-ec.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,3 +412,63 @@ async function testImportRaw({ name, publicUsages }, namedCurve) {
412412
true, privateUsages), { message: /Invalid key type/ });
413413
}
414414
}
415+
416+
// Bad private keys
417+
{
418+
for (const { namedCurve, key: pkcs8 } of [
419+
// The private key is exactly equal to the order, and the public key is
420+
// private key * order.
421+
{
422+
namedCurve: 'P-256',
423+
key: Buffer.from(
424+
'3066020100301306072a8648ce3d020106082a8648ce3d030107044c304a0201' +
425+
'010420ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc' +
426+
'632551a12303210000ffffff00000000ffffffffffffffffbce6faada7179e84' +
427+
'f3b9cac2fc632551', 'hex'),
428+
},
429+
// The private key is exactly equal to the order, and the public key is
430+
// omitted.
431+
{
432+
namedCurve: 'P-256',
433+
key: Buffer.from(
434+
'3041020100301306072a8648ce3d020106082a8648ce3d030107042730250201' +
435+
'010420ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc' +
436+
'632551', 'hex'),
437+
},
438+
// The private key is exactly equal to the order + 11, and the public key is
439+
// private key * order.
440+
{
441+
namedCurve: 'P-521',
442+
key: Buffer.from(
443+
'3081ee020100301006072a8648ce3d020106052b810400230481d63081d30201' +
444+
'01044201ffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
445+
'fffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb7' +
446+
'1e91386414a181890381860004008a75841259fdedff546f1a39573b4315cfed' +
447+
'5dc7ed7c17849543ef2c54f2991652f3dbc5332663da1bd19b1aebe319108501' +
448+
'5c024fa4c9a902ecc0e02dda0cdb9a0096fb303fcbba2129849d0ca877054fb2' +
449+
'293add566210bd0493ed2e95d4e0b9b82b1bc8a90e8b42a4ab3892331914a953' +
450+
'36dcac80e3f4819b5d58874f92ce48c808', 'hex'),
451+
},
452+
// The private key is exactly equal to the order + 11, and the public key is
453+
// omitted.
454+
{
455+
namedCurve: 'P-521',
456+
key: Buffer.from(
457+
'3060020100301006072a8648ce3d020106052b81040023044930470201010442' +
458+
'01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff' +
459+
'fffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e9138' +
460+
'6414', 'hex'),
461+
},
462+
]) {
463+
for (const [name, privateUsages] of [
464+
['ECDSA', ['sign']],
465+
['ECDH', ['deriveBits', 'deriveBits']],
466+
]) {
467+
assert.rejects(subtle.importKey(
468+
'pkcs8',
469+
pkcs8,
470+
{ name, hash: 'SHA-256', namedCurve },
471+
true, privateUsages), { name: 'DataError', message: /Invalid keyData/ });
472+
}
473+
}
474+
}

0 commit comments

Comments
 (0)