| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -858,6 +858,9 @@ class EVPKeyPointer final { | |||
| 858 | 858 | DER, | |
| 859 | 859 | PEM, | |
| 860 | 860 | JWK, | |
| 861 | + RAW_PUBLIC, | ||
| 862 | + RAW_PRIVATE, | ||
| 863 | + RAW_SEED, | ||
| 861 | 864 | }; | |
| 862 | 865 | ||
| 863 | 866 | enum class PKParseError { NOT_RECOGNIZED, NEED_PASSPHRASE, FAILED }; | |
@@ -867,6 +870,7 @@ class EVPKeyPointer final { | |||
| 867 | 870 | bool output_key_object = false; | |
| 868 | 871 | PKFormatType format = PKFormatType::DER; | |
| 869 | 872 | PKEncodingType type = PKEncodingType::PKCS8; | |
| 873 | + int ec_point_form = POINT_CONVERSION_UNCOMPRESSED; | ||
| 870 | 874 | AsymmetricKeyEncodingConfig() = default; | |
| 871 | 875 | AsymmetricKeyEncodingConfig(bool output_key_object, | |
| 872 | 876 | PKFormatType format, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -21,6 +21,9 @@ const { | |||
| 21 | 21 | kKeyFormatPEM, | |
| 22 | 22 | kKeyFormatDER, | |
| 23 | 23 | kKeyFormatJWK, | |
| 24 | + kKeyFormatRawPublic, | ||
| 25 | + kKeyFormatRawPrivate, | ||
| 26 | + kKeyFormatRawSeed, | ||
| 24 | 27 | kKeyEncodingPKCS1, | |
| 25 | 28 | kKeyEncodingPKCS8, | |
| 26 | 29 | kKeyEncodingSPKI, | |
@@ -433,6 +436,12 @@ function parseKeyFormat(formatStr, defaultFormat, optionName) { | |||
| 433 | 436 | return kKeyFormatDER; | |
| 434 | 437 | else if (formatStr === 'jwk') | |
| 435 | 438 | return kKeyFormatJWK; | |
| 439 | + else if (formatStr === 'raw-public') | ||
| 440 | + return kKeyFormatRawPublic; | ||
| 441 | + else if (formatStr === 'raw-private') | ||
| 442 | + return kKeyFormatRawPrivate; | ||
| 443 | + else if (formatStr === 'raw-seed') | ||
| 444 | + return kKeyFormatRawSeed; | ||
| 436 | 445 | throw new ERR_INVALID_ARG_VALUE(optionName, formatStr); | |
| 437 | 446 | } | |
| 438 | 447 | ||
@@ -473,6 +482,33 @@ function parseKeyFormatAndType(enc, keyType, isPublic, objName) { | |||
| 473 | 482 | isInput ? kKeyFormatPEM : undefined, | |
| 474 | 483 | option('format', objName)); | |
| 475 | 484 | ||
| 485 | + if (format === kKeyFormatRawPublic) { | ||
| 486 | + if (isPublic === false) { | ||
| 487 | + throw new ERR_INVALID_ARG_VALUE(option('format', objName), 'raw-public'); | ||
| 488 | + } | ||
| 489 | + let type; | ||
| 490 | + if (typeStr === undefined || typeStr === 'uncompressed') { | ||
| 491 | + type = POINT_CONVERSION_UNCOMPRESSED; | ||
| 492 | + } else if (typeStr === 'compressed') { | ||
| 493 | + type = POINT_CONVERSION_COMPRESSED; | ||
| 494 | + } else { | ||
| 495 | + throw new ERR_INVALID_ARG_VALUE(option('type', objName), typeStr); | ||
| 496 | + } | ||
| 497 | + return { format, type }; | ||
| 498 | + } | ||
| 499 | + | ||
| 500 | + if (format === kKeyFormatRawPrivate || format === kKeyFormatRawSeed) { | ||
| 501 | + if (isPublic === true) { | ||
| 502 | + throw new ERR_INVALID_ARG_VALUE( | ||
| 503 | + option('format', objName), | ||
| 504 | + format === kKeyFormatRawPrivate ? 'raw-private' : 'raw-seed'); | ||
| 505 | + } | ||
| 506 | + if (typeStr !== undefined) { | ||
| 507 | + throw new ERR_INVALID_ARG_VALUE(option('type', objName), typeStr); | ||
| 508 | + } | ||
| 509 | + return { format }; | ||
| 510 | + } | ||
| 511 | + | ||
| 476 | 512 | const isRequired = (!isInput || | |
| 477 | 513 | format === kKeyFormatDER) && | |
| 478 | 514 | format !== kKeyFormatJWK; | |
@@ -504,6 +540,14 @@ function parseKeyEncoding(enc, keyType, isPublic, objName) { | |||
| 504 | 540 | if (isPublic !== true) { | |
| 505 | 541 | ({ cipher, passphrase, encoding } = enc); | |
| 506 | 542 | ||
| 543 | + if (format === kKeyFormatRawPrivate || format === kKeyFormatRawSeed) { | ||
| 544 | + if (cipher != null || passphrase !== undefined) { | ||
| 545 | + throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS( | ||
| 546 | + 'raw format', 'does not support encryption'); | ||
| 547 | + } | ||
| 548 | + return { format, type }; | ||
| 549 | + } | ||
| 550 | + | ||
| 507 | 551 | if (!isInput) { | |
| 508 | 552 | if (cipher != null) { | |
| 509 | 553 | if (typeof cipher !== 'string') | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -66,7 +66,16 @@ Maybe<EVPKeyPointer::AsymmetricKeyEncodingConfig> GetKeyFormatAndTypeFromJs( | |||
| 66 | 66 | config.format = static_cast<EVPKeyPointer::PKFormatType>( | |
| 67 | 67 | args[*offset].As<Int32>()->Value()); | |
| 68 | 68 | ||
| 69 | - if (args[*offset + 1]->IsInt32()) { | ||
| 69 | + if (config.format == EVPKeyPointer::PKFormatType::RAW_PUBLIC || | ||
| 70 | + config.format == EVPKeyPointer::PKFormatType::RAW_PRIVATE || | ||
| 71 | + config.format == EVPKeyPointer::PKFormatType::RAW_SEED) { | ||
| 72 | + // Raw formats use the type slot for ec_point_form (int) or null. | ||
| 73 | + if (args[*offset + 1]->IsInt32()) { | ||
| 74 | + config.ec_point_form = args[*offset + 1].As<Int32>()->Value(); | ||
| 75 | + } else { | ||
| 76 | + CHECK(args[*offset + 1]->IsNullOrUndefined()); | ||
| 77 | + } | ||
| 78 | + } else if (args[*offset + 1]->IsInt32()) { | ||
| 70 | 79 | config.type = static_cast<EVPKeyPointer::PKEncodingType>( | |
| 71 | 80 | args[*offset + 1].As<Int32>()->Value()); | |
| 72 | 81 | } else { | |
@@ -329,6 +338,54 @@ bool KeyObjectData::ToEncodedPublicKey( | |||
| 329 | 338 | *out = Object::New(env->isolate()); | |
| 330 | 339 | return ExportJWKInner( | |
| 331 | 340 | env, addRefWithType(KeyType::kKeyTypePublic), *out, false); | |
| 341 | + } else if (config.format == EVPKeyPointer::PKFormatType::RAW_PUBLIC) { | ||
| 342 | + Mutex::ScopedLock lock(mutex()); | ||
| 343 | + const auto& pkey = GetAsymmetricKey(); | ||
| 344 | + if (pkey.id() == EVP_PKEY_EC) { | ||
| 345 | + const EC_KEY* ec_key = pkey; | ||
| 346 | + CHECK_NOT_NULL(ec_key); | ||
| 347 | + auto form = static_cast<point_conversion_form_t>(config.ec_point_form); | ||
| 348 | + const auto group = ECKeyPointer::GetGroup(ec_key); | ||
| 349 | + const auto point = ECKeyPointer::GetPublicKey(ec_key); | ||
| 350 | + return ECPointToBuffer(env, group, point, form).ToLocal(out); | ||
| 351 | + } | ||
| 352 | + switch (pkey.id()) { | ||
| 353 | + case EVP_PKEY_ED25519: | ||
| 354 | + case EVP_PKEY_ED448: | ||
| 355 | + case EVP_PKEY_X25519: | ||
| 356 | + case EVP_PKEY_X448: | ||
| 357 | + #if OPENSSL_WITH_PQC | ||
| 358 | + case EVP_PKEY_ML_DSA_44: | ||
| 359 | + case EVP_PKEY_ML_DSA_65: | ||
| 360 | + case EVP_PKEY_ML_DSA_87: | ||
| 361 | + case EVP_PKEY_ML_KEM_512: | ||
| 362 | + case EVP_PKEY_ML_KEM_768: | ||
| 363 | + case EVP_PKEY_ML_KEM_1024: | ||
| 364 | + case EVP_PKEY_SLH_DSA_SHA2_128F: | ||
| 365 | + case EVP_PKEY_SLH_DSA_SHA2_128S: | ||
| 366 | + case EVP_PKEY_SLH_DSA_SHA2_192F: | ||
| 367 | + case EVP_PKEY_SLH_DSA_SHA2_192S: | ||
| 368 | + case EVP_PKEY_SLH_DSA_SHA2_256F: | ||
| 369 | + case EVP_PKEY_SLH_DSA_SHA2_256S: | ||
| 370 | + case EVP_PKEY_SLH_DSA_SHAKE_128F: | ||
| 371 | + case EVP_PKEY_SLH_DSA_SHAKE_128S: | ||
| 372 | + case EVP_PKEY_SLH_DSA_SHAKE_192F: | ||
| 373 | + case EVP_PKEY_SLH_DSA_SHAKE_192S: | ||
| 374 | + case EVP_PKEY_SLH_DSA_SHAKE_256F: | ||
| 375 | + case EVP_PKEY_SLH_DSA_SHAKE_256S: | ||
| 376 | + #endif | ||
| 377 | + break; | ||
| 378 | + default: | ||
| 379 | + THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env); | ||
| 380 | + return false; | ||
| 381 | + } | ||
| 382 | + auto raw_data = pkey.rawPublicKey(); | ||
| 383 | + if (!raw_data) { | ||
| 384 | + THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to get raw public key"); | ||
| 385 | + return false; | ||
| 386 | + } | ||
| 387 | + return Buffer::Copy(env, raw_data.get<const char>(), raw_data.size()) | ||
| 388 | + .ToLocal(out); | ||
| 332 | 389 | } | |
| 333 | 390 | ||
| 334 | 391 | return WritePublicKey(env, GetAsymmetricKey(), config).ToLocal(out); | |
@@ -347,6 +404,86 @@ bool KeyObjectData::ToEncodedPrivateKey( | |||
| 347 | 404 | *out = Object::New(env->isolate()); | |
| 348 | 405 | return ExportJWKInner( | |
| 349 | 406 | env, addRefWithType(KeyType::kKeyTypePrivate), *out, false); | |
| 407 | + } else if (config.format == EVPKeyPointer::PKFormatType::RAW_PRIVATE) { | ||
| 408 | + Mutex::ScopedLock lock(mutex()); | ||
| 409 | + const auto& pkey = GetAsymmetricKey(); | ||
| 410 | + if (pkey.id() == EVP_PKEY_EC) { | ||
| 411 | + const EC_KEY* ec_key = pkey; | ||
| 412 | + CHECK_NOT_NULL(ec_key); | ||
| 413 | + const BIGNUM* private_key = ECKeyPointer::GetPrivateKey(ec_key); | ||
| 414 | + CHECK_NOT_NULL(private_key); | ||
| 415 | + const auto group = ECKeyPointer::GetGroup(ec_key); | ||
| 416 | + auto order = BignumPointer::New(); | ||
| 417 | + CHECK(order); | ||
| 418 | + CHECK(EC_GROUP_get_order(group, order.get(), nullptr)); | ||
| 419 | + auto buf = BignumPointer::EncodePadded(private_key, order.byteLength()); | ||
| 420 | + if (!buf) { | ||
| 421 | + THROW_ERR_CRYPTO_OPERATION_FAILED(env, | ||
| 422 | + "Failed to export EC private key"); | ||
| 423 | + return false; | ||
| 424 | + } | ||
| 425 | + return Buffer::Copy(env, buf.get<const char>(), buf.size()).ToLocal(out); | ||
| 426 | + } | ||
| 427 | + switch (pkey.id()) { | ||
| 428 | + case EVP_PKEY_ED25519: | ||
| 429 | + case EVP_PKEY_ED448: | ||
| 430 | + case EVP_PKEY_X25519: | ||
| 431 | + case EVP_PKEY_X448: | ||
| 432 | + #if OPENSSL_WITH_PQC | ||
| 433 | + case EVP_PKEY_SLH_DSA_SHA2_128F: | ||
| 434 | + case EVP_PKEY_SLH_DSA_SHA2_128S: | ||
| 435 | + case EVP_PKEY_SLH_DSA_SHA2_192F: | ||
| 436 | + case EVP_PKEY_SLH_DSA_SHA2_192S: | ||
| 437 | + case EVP_PKEY_SLH_DSA_SHA2_256F: | ||
| 438 | + case EVP_PKEY_SLH_DSA_SHA2_256S: | ||
| 439 | + case EVP_PKEY_SLH_DSA_SHAKE_128F: | ||
| 440 | + case EVP_PKEY_SLH_DSA_SHAKE_128S: | ||
| 441 | + case EVP_PKEY_SLH_DSA_SHAKE_192F: | ||
| 442 | + case EVP_PKEY_SLH_DSA_SHAKE_192S: | ||
| 443 | + case EVP_PKEY_SLH_DSA_SHAKE_256F: | ||
| 444 | + case EVP_PKEY_SLH_DSA_SHAKE_256S: | ||
| 445 | + #endif | ||
| 446 | + break; | ||
| 447 | + default: | ||
| 448 | + THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env); | ||
| 449 | + return false; | ||
| 450 | + } | ||
| 451 | + auto raw_data = pkey.rawPrivateKey(); | ||
| 452 | + if (!raw_data) { | ||
| 453 | + THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to get raw private key"); | ||
| 454 | + return false; | ||
| 455 | + } | ||
| 456 | + return Buffer::Copy(env, raw_data.get<const char>(), raw_data.size()) | ||
| 457 | + .ToLocal(out); | ||
| 458 | + } else if (config.format == EVPKeyPointer::PKFormatType::RAW_SEED) { | ||
| 459 | + Mutex::ScopedLock lock(mutex()); | ||
| 460 | + const auto& pkey = GetAsymmetricKey(); | ||
| 461 | + switch (pkey.id()) { | ||
| 462 | + #if OPENSSL_WITH_PQC | ||
| 463 | + case EVP_PKEY_ML_DSA_44: | ||
| 464 | + case EVP_PKEY_ML_DSA_65: | ||
| 465 | + case EVP_PKEY_ML_DSA_87: | ||
| 466 | + case EVP_PKEY_ML_KEM_512: | ||
| 467 | + case EVP_PKEY_ML_KEM_768: | ||
| 468 | + case EVP_PKEY_ML_KEM_1024: | ||
| 469 | + break; | ||
| 470 | + #endif | ||
| 471 | + default: | ||
| 472 | + THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env); | ||
| 473 | + return false; | ||
| 474 | + } | ||
| 475 | + #if OPENSSL_WITH_PQC | ||
| 476 | + auto raw_data = pkey.rawSeed(); | ||
| 477 | + if (!raw_data) { | ||
| 478 | + THROW_ERR_CRYPTO_OPERATION_FAILED(env, "Failed to get raw seed"); | ||
| 479 | + return false; | ||
| 480 | + } | ||
| 481 | + return Buffer::Copy(env, raw_data.get<const char>(), raw_data.size()) | ||
| 482 | + .ToLocal(out); | ||
| 483 | + #else | ||
| 484 | + THROW_ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS(env); | ||
| 485 | + return false; | ||
| 486 | + #endif | ||
| 350 | 487 | } | |
| 351 | 488 | ||
| 352 | 489 | return WritePrivateKey(env, GetAsymmetricKey(), config).ToLocal(out); | |
@@ -367,6 +504,14 @@ KeyObjectData::GetPrivateKeyEncodingFromJs( | |||
| 367 | 504 | if (config.output_key_object) { | |
| 368 | 505 | if (context != kKeyContextInput) | |
| 369 | 506 | (*offset)++; | |
| 507 | + } else if (config.format == EVPKeyPointer::PKFormatType::RAW_PRIVATE || | ||
| 508 | + config.format == EVPKeyPointer::PKFormatType::RAW_SEED) { | ||
| 509 | + // Raw formats don't support encryption. Still consume the arg offsets. | ||
| 510 | + if (context != kKeyContextInput) { | ||
| 511 | + CHECK(args[*offset]->IsNullOrUndefined()); | ||
| 512 | + (*offset)++; | ||
| 513 | + } | ||
| 514 | + CHECK(args[*offset]->IsNullOrUndefined()); | ||
| 370 | 515 | } else { | |
| 371 | 516 | bool needs_passphrase = false; | |
| 372 | 517 | if (context != kKeyContextInput) { | |
@@ -1557,6 +1702,12 @@ void Initialize(Environment* env, Local<Object> target) { | |||
| 1557 | 1702 | static_cast<int>(EVPKeyPointer::PKFormatType::PEM); | |
| 1558 | 1703 | constexpr int kKeyFormatJWK = | |
| 1559 | 1704 | static_cast<int>(EVPKeyPointer::PKFormatType::JWK); | |
| 1705 | + constexpr int kKeyFormatRawPublic = | ||
| 1706 | + static_cast<int>(EVPKeyPointer::PKFormatType::RAW_PUBLIC); | ||
| 1707 | + constexpr int kKeyFormatRawPrivate = | ||
| 1708 | + static_cast<int>(EVPKeyPointer::PKFormatType::RAW_PRIVATE); | ||
| 1709 | + constexpr int kKeyFormatRawSeed = | ||
| 1710 | + static_cast<int>(EVPKeyPointer::PKFormatType::RAW_SEED); | ||
| 1560 | 1711 | ||
| 1561 | 1712 | constexpr auto kSigEncDER = DSASigEnc::DER; | |
| 1562 | 1713 | constexpr auto kSigEncP1363 = DSASigEnc::P1363; | |
@@ -1596,6 +1747,9 @@ void Initialize(Environment* env, Local<Object> target) { | |||
| 1596 | 1747 | NODE_DEFINE_CONSTANT(target, kKeyFormatDER); | |
| 1597 | 1748 | NODE_DEFINE_CONSTANT(target, kKeyFormatPEM); | |
| 1598 | 1749 | NODE_DEFINE_CONSTANT(target, kKeyFormatJWK); | |
| 1750 | + NODE_DEFINE_CONSTANT(target, kKeyFormatRawPublic); | ||
| 1751 | + NODE_DEFINE_CONSTANT(target, kKeyFormatRawPrivate); | ||
| 1752 | + NODE_DEFINE_CONSTANT(target, kKeyFormatRawSeed); | ||
| 1599 | 1753 | NODE_DEFINE_CONSTANT(target, kKeyTypeSecret); | |
| 1600 | 1754 | NODE_DEFINE_CONSTANT(target, kKeyTypePublic); | |
| 1601 | 1755 | NODE_DEFINE_CONSTANT(target, kKeyTypePrivate); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments