Skip to content

Commit a362c27

Browse files
panvatargos
authored andcommitted
crypto: ensure valid point on elliptic curve in SubtleCrypto.importKey
PR-URL: #50234 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent e375063 commit a362c27

4 files changed

Lines changed: 114 additions & 10 deletions

File tree

‎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].checkEcKeyData()){
268+
throwlazyDOMException('Invalid keyData','DataError');
269+
}
270+
267271
const{
268272
namedCurve: checkNamedCurve,
269273
}=keyObject[kHandle].keyDetail({});

‎src/crypto/crypto_keys.cc‎

Lines changed: 31 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, "checkEcKeyData", CheckEcKeyData);
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(CheckEcKeyData);
929932
registry->Register(Export);
930933
registry->Register(ExportJWK);
931934
registry->Register(InitECRaw);
@@ -1237,6 +1240,34 @@ void KeyObjectHandle::GetAsymmetricKeyType(
12371240
args.GetReturnValue().Set(key->GetAsymmetricKeyType());
12381241
}
12391242

1243+
boolKeyObjectHandle::CheckEcKeyData() const {
1244+
MarkPopErrorOnReturn mark_pop_error_on_return;
1245+
1246+
const ManagedEVPPKey& key = data_->GetAsymmetricKey();
1247+
KeyType type = data_->GetKeyType();
1248+
CHECK_NE(type, kKeyTypeSecret);
1249+
EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(key.get(), nullptr));
1250+
CHECK(ctx);
1251+
CHECK_EQ(EVP_PKEY_id(key.get()), EVP_PKEY_EC);
1252+
1253+
if (type == kKeyTypePrivate) {
1254+
returnEVP_PKEY_check(ctx.get()) == 1;
1255+
}
1256+
1257+
#if OPENSSL_VERSION_MAJOR >= 3
1258+
returnEVP_PKEY_public_check_quick(ctx.get()) == 1;
1259+
#else
1260+
returnEVP_PKEY_public_check(ctx.get()) == 1;
1261+
#endif
1262+
}
1263+
1264+
voidKeyObjectHandle::CheckEcKeyData(const FunctionCallbackInfo<Value>& args) {
1265+
KeyObjectHandle* key;
1266+
ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder());
1267+
1268+
args.GetReturnValue().Set(key->CheckEcKeyData());
1269+
}
1270+
12401271
voidKeyObjectHandle::GetSymmetricKeySize(
12411272
const FunctionCallbackInfo<Value>& args) {
12421273
KeyObjectHandle* key;

‎src/crypto/crypto_keys.h‎

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

196+
staticvoidCheckEcKeyData(const v8::FunctionCallbackInfo<v8::Value>& args);
197+
boolCheckEcKeyData() const;
198+
196199
staticvoidGetSymmetricKeySize(
197200
const v8::FunctionCallbackInfo<v8::Value>& args);
198201

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

Lines changed: 76 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -400,15 +400,81 @@ async function testImportRaw({ name, publicUsages }, namedCurve) {
400400
['ECDSA',['verify'],['sign']],
401401
['ECDH',[],['deriveBits','deriveBits']],
402402
]){
403-
assert.rejects(subtle.importKey(
404-
'spki',
405-
rsaPublic.export({format: 'der',type: 'spki'}),
406-
{ name,hash: 'SHA-256',namedCurve: 'P-256'},
407-
true,publicUsages),{message: /Invalidkeytype/});
408-
assert.rejects(subtle.importKey(
409-
'pkcs8',
410-
rsaPrivate.export({format: 'der',type: 'pkcs8'}),
411-
{ name,hash: 'SHA-256',namedCurve: 'P-256'},
412-
true,privateUsages),{message: /Invalidkeytype/});
403+
assert.rejects(
404+
subtle.importKey(
405+
'spki',
406+
rsaPublic.export({format: 'der',type: 'spki'}),
407+
{ name,hash: 'SHA-256',namedCurve: 'P-256'},
408+
true,publicUsages),{message: /Invalidkeytype/},
409+
).then(common.mustCall());
410+
assert.rejects(
411+
subtle.importKey(
412+
'pkcs8',
413+
rsaPrivate.export({format: 'der',type: 'pkcs8'}),
414+
{ name,hash: 'SHA-256',namedCurve: 'P-256'},
415+
true,privateUsages),{message: /Invalidkeytype/},
416+
).then(common.mustCall());
417+
}
418+
}
419+
420+
// Bad private keys
421+
{
422+
for(const{ namedCurve,key: pkcs8}of[
423+
// The private key is exactly equal to the order, and the public key is
424+
// private key * order.
425+
{
426+
namedCurve: 'P-256',
427+
key: Buffer.from(
428+
'3066020100301306072a8648ce3d020106082a8648ce3d030107044c304a0201'+
429+
'010420ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc'+
430+
'632551a12303210000ffffff00000000ffffffffffffffffbce6faada7179e84'+
431+
'f3b9cac2fc632551','hex'),
432+
},
433+
// The private key is exactly equal to the order, and the public key is
434+
// omitted.
435+
{
436+
namedCurve: 'P-256',
437+
key: Buffer.from(
438+
'3041020100301306072a8648ce3d020106082a8648ce3d030107042730250201'+
439+
'010420ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc'+
440+
'632551','hex'),
441+
},
442+
// The private key is exactly equal to the order + 11, and the public key is
443+
// private key * order.
444+
{
445+
namedCurve: 'P-521',
446+
key: Buffer.from(
447+
'3081ee020100301006072a8648ce3d020106052b810400230481d63081d30201'+
448+
'01044201ffffffffffffffffffffffffffffffffffffffffffffffffffffffff'+
449+
'fffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb7'+
450+
'1e91386414a181890381860004008a75841259fdedff546f1a39573b4315cfed'+
451+
'5dc7ed7c17849543ef2c54f2991652f3dbc5332663da1bd19b1aebe319108501'+
452+
'5c024fa4c9a902ecc0e02dda0cdb9a0096fb303fcbba2129849d0ca877054fb2'+
453+
'293add566210bd0493ed2e95d4e0b9b82b1bc8a90e8b42a4ab3892331914a953'+
454+
'36dcac80e3f4819b5d58874f92ce48c808','hex'),
455+
},
456+
// The private key is exactly equal to the order + 11, and the public key is
457+
// omitted.
458+
{
459+
namedCurve: 'P-521',
460+
key: Buffer.from(
461+
'3060020100301006072a8648ce3d020106052b81040023044930470201010442'+
462+
'01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'+
463+
'fffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e9138'+
464+
'6414','hex'),
465+
},
466+
]){
467+
for(const[name,privateUsages]of[
468+
['ECDSA',['sign']],
469+
['ECDH',['deriveBits','deriveBits']],
470+
]){
471+
assert.rejects(
472+
subtle.importKey(
473+
'pkcs8',
474+
pkcs8,
475+
{ name,hash: 'SHA-256', namedCurve },
476+
true,privateUsages),{name: 'DataError',message: /InvalidkeyData/},
477+
).then(common.mustCall());
478+
}
413479
}
414480
}

0 commit comments

Comments
 (0)