GeezerVison is showing github.com — crypto: ensure valid point on elliptic curve in SubtleCrypto.importKey · nodejs/node@76e4d41
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: lib/internal/crypto/ec.js +4Lines changed: 4 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -264,6 +264,10 @@ async function ecImportKey( | 264 | 264 | break; | 265 | 265 | } | 266 | 266 |
| | 267 | + if (!keyObject[kHandle].checkEcKeyData()) { | | 268 | + throw lazyDOMException('Invalid keyData', 'DataError'); | | 269 | + } | | 270 | + | 267 | 271 | const { | 268 | 272 | namedCurve: checkNamedCurve, | 269 | 273 | } = keyObject[kHandle].keyDetail({}); | |
Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_keys.cc +31Lines changed: 31 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -908,6 +908,8 @@ v8::Local<v8::Function> KeyObjectHandle::Initialize(Environment* env) { | 908 | 908 | isolate, templ, "getSymmetricKeySize", GetSymmetricKeySize); | 909 | 909 | SetProtoMethodNoSideEffect( | 910 | 910 | isolate, templ, "getAsymmetricKeyType", GetAsymmetricKeyType); | | 911 | + SetProtoMethodNoSideEffect( | | 912 | + isolate, templ, "checkEcKeyData", CheckEcKeyData); | 911 | 913 | SetProtoMethod(isolate, templ, "export", Export); | 912 | 914 | SetProtoMethod(isolate, templ, "exportJwk", ExportJWK); | 913 | 915 | SetProtoMethod(isolate, templ, "initECRaw", InitECRaw); | @@ -927,6 +929,7 @@ void KeyObjectHandle::RegisterExternalReferences( | 927 | 929 | registry->Register(Init); | 928 | 930 | registry->Register(GetSymmetricKeySize); | 929 | 931 | registry->Register(GetAsymmetricKeyType); | | 932 | + registry->Register(CheckEcKeyData); | 930 | 933 | registry->Register(Export); | 931 | 934 | registry->Register(ExportJWK); | 932 | 935 | registry->Register(InitECRaw); | @@ -1238,6 +1241,34 @@ void KeyObjectHandle::GetAsymmetricKeyType( | 1238 | 1241 | args.GetReturnValue().Set(key->GetAsymmetricKeyType()); | 1239 | 1242 | } | 1240 | 1243 |
| | 1244 | +bool KeyObjectHandle::CheckEcKeyData() const { | | 1245 | + MarkPopErrorOnReturn mark_pop_error_on_return; | | 1246 | + | | 1247 | + const ManagedEVPPKey& key = data_->GetAsymmetricKey(); | | 1248 | + KeyType type = data_->GetKeyType(); | | 1249 | + CHECK_NE(type, kKeyTypeSecret); | | 1250 | + EVPKeyCtxPointer ctx(EVP_PKEY_CTX_new(key.get(), nullptr)); | | 1251 | + CHECK(ctx); | | 1252 | + CHECK_EQ(EVP_PKEY_id(key.get()), EVP_PKEY_EC); | | 1253 | + | | 1254 | + if (type == kKeyTypePrivate) { | | 1255 | + return EVP_PKEY_check(ctx.get()) == 1; | | 1256 | + } | | 1257 | + | | 1258 | +#if OPENSSL_VERSION_MAJOR >= 3 | | 1259 | + return EVP_PKEY_public_check_quick(ctx.get()) == 1; | | 1260 | +#else | | 1261 | + return EVP_PKEY_public_check(ctx.get()) == 1; | | 1262 | +#endif | | 1263 | +} | | 1264 | + | | 1265 | +void KeyObjectHandle::CheckEcKeyData(const FunctionCallbackInfo<Value>& args) { | | 1266 | + KeyObjectHandle* key; | | 1267 | + ASSIGN_OR_RETURN_UNWRAP(&key, args.Holder()); | | 1268 | + | | 1269 | + args.GetReturnValue().Set(key->CheckEcKeyData()); | | 1270 | +} | | 1271 | + | 1241 | 1272 | void KeyObjectHandle::GetSymmetricKeySize( | 1242 | 1273 | const FunctionCallbackInfo<Value>& args) { | 1243 | 1274 | KeyObjectHandle* key; | |
Collapse file Copy file name to clipboardExpand all lines: src/crypto/crypto_keys.h +3Lines changed: 3 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -193,6 +193,9 @@ class KeyObjectHandle : public BaseObject { | 193 | 193 | const v8::FunctionCallbackInfo<v8::Value>& args); | 194 | 194 | v8::Local<v8::Value> GetAsymmetricKeyType() const; | 195 | 195 |
| | 196 | + static void CheckEcKeyData(const v8::FunctionCallbackInfo<v8::Value>& args); | | 197 | + bool CheckEcKeyData() const; | | 198 | + | 196 | 199 | static void GetSymmetricKeySize( | 197 | 200 | const v8::FunctionCallbackInfo<v8::Value>& args); | 198 | 201 |
| |
Collapse file Copy file name to clipboardExpand all lines: test/parallel/test-webcrypto-export-import-ec.js +76-10Lines changed: 76 additions & 10 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -400,15 +400,81 @@ async function testImportRaw({ name, publicUsages }, namedCurve) { | 400 | 400 | ['ECDSA', ['verify'], ['sign']], | 401 | 401 | ['ECDH', [], ['deriveBits', 'deriveBits']], | 402 | 402 | ]) { | 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: /Invalid key type/ }); | 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: /Invalid key type/ }); | | 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: /Invalid key type/ }, | | 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: /Invalid key type/ }, | | 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: /Invalid keyData/ }, | | 477 | + ).then(common.mustCall()); | | 478 | + } | 413 | 479 | } | 414 | 480 | } |
|