diff --git a/Libraries/LibCrypto/PK/PK.h b/Libraries/LibCrypto/PK/PK.h index 63b668185ea..4e24f4a2af7 100644 --- a/Libraries/LibCrypto/PK/PK.h +++ b/Libraries/LibCrypto/PK/PK.h @@ -13,6 +13,29 @@ namespace Crypto::PK { +template +ErrorOr wrap_in_private_key_info(ByteBuffer key, Span algorithm_identifier) +{ + ASN1::Encoder encoder; + TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr { + TRY(encoder.write(0x00u)); // version + + // AlgorithmIdentifier + TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr { + TRY(encoder.write(algorithm_identifier)); // algorithm + + return {}; + })); + + // PrivateKey + TRY(encoder.write(key)); + + return {}; + })); + + return encoder.finish(); +} + template ErrorOr wrap_in_private_key_info(ByteBuffer key, Span algorithm_identifier, Params params) { @@ -38,6 +61,33 @@ ErrorOr wrap_in_private_key_info(ByteBuffer key, Span alg return encoder.finish(); } +template +ErrorOr wrap_in_private_key_info(ExportableKey key, Span algorithm_identifier) +requires requires(ExportableKey k) { + k.export_as_der(); +} +{ + ASN1::Encoder encoder; + TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr { + TRY(encoder.write(0x00u)); // version + + // AlgorithmIdentifier + TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr { + TRY(encoder.write(algorithm_identifier)); // algorithm + + return {}; + })); + + // PrivateKey + auto data = TRY(key.export_as_der()); + TRY(encoder.write(data)); + + return {}; + })); + + return encoder.finish(); +} + template ErrorOr wrap_in_private_key_info(ExportableKey key, Span algorithm_identifier, Params params) requires requires(ExportableKey k) { @@ -67,6 +117,28 @@ requires requires(ExportableKey k) { return encoder.finish(); } +template +ErrorOr wrap_in_subject_public_key_info(ByteBuffer key, Span algorithm_identifier) +{ + ASN1::Encoder encoder; + TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr { + // AlgorithmIdentifier + TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr { + TRY(encoder.write(algorithm_identifier)); // algorithm + + return {}; + })); + + // subjectPublicKey + auto bitstring = ::Crypto::ASN1::BitStringView(key, 0); + TRY(encoder.write(bitstring)); + + return {}; + })); + + return encoder.finish(); +} + template ErrorOr wrap_in_subject_public_key_info(ByteBuffer key, Span algorithm_identifier, ParamsType const& params) { @@ -91,6 +163,32 @@ ErrorOr wrap_in_subject_public_key_info(ByteBuffer key, Span +ErrorOr wrap_in_subject_public_key_info(ExportableKey key, Span algorithm_identifier) +requires requires(ExportableKey k) { + k.export_as_der(); +} +{ + ASN1::Encoder encoder; + TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr { + // AlgorithmIdentifier + TRY(encoder.write_constructed(ASN1::Class::Universal, ASN1::Kind::Sequence, [&]() -> ErrorOr { + TRY(encoder.write(algorithm_identifier)); // algorithm + + return {}; + })); + + // subjectPublicKey + auto data = TRY(key.export_as_der()); + auto bitstring = ::Crypto::ASN1::BitStringView(data, 0); + TRY(encoder.write(bitstring)); + + return {}; + })); + + return encoder.finish(); +} + template ErrorOr wrap_in_subject_public_key_info(ExportableKey key, Span algorithm_identifier, ParamsType const& params) requires requires(ExportableKey k) { diff --git a/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp b/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp index 578f7b60439..233a694bd20 100644 --- a/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp +++ b/Libraries/LibWeb/Crypto/CryptoAlgorithms.cpp @@ -4491,7 +4491,7 @@ WebIDL::ExceptionOr> ED25519::export_key(Bindings::KeyFormat // * Set the algorithm object identifier to the id-Ed25519 OID defined in [RFC8410]. // * Set the subjectPublicKey field to keyData. auto ed25519_oid = ::Crypto::ASN1::ed25519_oid; - auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_subject_public_key_info(key_data, ed25519_oid, nullptr)); + auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_subject_public_key_info(key_data, ed25519_oid)); // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data. return JS::ArrayBuffer::create(m_realm, move(data)); @@ -4514,7 +4514,7 @@ WebIDL::ExceptionOr> ED25519::export_key(Bindings::KeyFormat TRY_OR_THROW_OOM(vm, encoder.write(key_data.bytes())); auto ed25519_oid = ::Crypto::ASN1::ed25519_oid; - auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_private_key_info(encoder.finish(), ed25519_oid, nullptr)); + auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_private_key_info(encoder.finish(), ed25519_oid)); // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data. return JS::ArrayBuffer::create(m_realm, move(data)); @@ -5183,7 +5183,7 @@ WebIDL::ExceptionOr> X25519::export_key(Bindings::KeyFormat // Set the algorithm object identifier to the id-X25519 OID defined in [RFC8410]. // Set the subjectPublicKey field to keyData. auto public_key = handle.get(); - auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_subject_public_key_info(public_key, ::Crypto::ASN1::x25519_oid, nullptr)); + auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_subject_public_key_info(public_key, ::Crypto::ASN1::x25519_oid)); // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data. result = JS::ArrayBuffer::create(m_realm, data); @@ -5202,7 +5202,7 @@ WebIDL::ExceptionOr> X25519::export_key(Bindings::KeyFormat // Set the privateKey field to the result of DER-encoding a CurvePrivateKey ASN.1 type, as defined in Section 7 of [RFC8410], // that represents the X25519 private key represented by the [[handle]] internal slot of key auto private_key = handle.get(); - auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_private_key_info(private_key, ::Crypto::ASN1::x25519_oid, nullptr)); + auto data = TRY_OR_THROW_OOM(vm, ::Crypto::PK::wrap_in_private_key_info(private_key, ::Crypto::ASN1::x25519_oid)); // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data. result = JS::ArrayBuffer::create(m_realm, data); @@ -5427,7 +5427,7 @@ WebIDL::ExceptionOr> X448::export_key(Bindings::KeyFormat fo // * Set the algorithm object identifier to the id-X448 OID defined in [RFC8410]. // * Set the subjectPublicKey field to keyData. auto x448_oid = ::Crypto::ASN1::x448_oid; - auto data = TRY_OR_THROW_OOM(m_realm->vm(), ::Crypto::PK::wrap_in_subject_public_key_info(key_data, x448_oid, nullptr)); + auto data = TRY_OR_THROW_OOM(m_realm->vm(), ::Crypto::PK::wrap_in_subject_public_key_info(key_data, x448_oid)); // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data. return JS::ArrayBuffer::create(m_realm, data); @@ -5445,7 +5445,7 @@ WebIDL::ExceptionOr> X448::export_key(Bindings::KeyFormat fo // * Set the algorithm object identifier to the id-X448 OID defined in [RFC8410]. // * Set the privateKey field to the result of DER-encoding a CurvePrivateKey ASN.1 type, as defined in Section 7 of [RFC8410], that represents the X448 private key represented by the [[handle]] internal slot of key auto x448_oid = ::Crypto::ASN1::x448_oid; - auto data = TRY_OR_THROW_OOM(m_realm->vm(), ::Crypto::PK::wrap_in_private_key_info(key_data, x448_oid, nullptr)); + auto data = TRY_OR_THROW_OOM(m_realm->vm(), ::Crypto::PK::wrap_in_private_key_info(key_data, x448_oid)); // 3. Let result be a new ArrayBuffer associated with the relevant global object of this [HTML], and containing data. return JS::ArrayBuffer::create(m_realm, data); diff --git a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.txt b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.txt index f55036a7ff2..0bb7b8f2973 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_Ed25519.https.any.txt @@ -2,40 +2,39 @@ Harness status: OK Found 62 tests -52 Pass -10 Fail -Fail Good parameters: Ed25519 bits (spki, buffer(44), {name: Ed25519}, true, [verify]) -Fail Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify]) +62 Pass +Pass Good parameters: Ed25519 bits (spki, buffer(44), {name: Ed25519}, true, [verify]) +Pass Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify]) Pass Good parameters: Ed25519 bits (jwk, object(kty, crv, x), {name: Ed25519}, true, [verify]) Pass Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify]) Pass Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), {name: Ed25519}, true, [verify]) Pass Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify]) Pass Good parameters: Ed25519 bits (raw, buffer(32), {name: Ed25519}, true, [verify]) Pass Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify]) -Fail Good parameters: Ed25519 bits (spki, buffer(44), {name: Ed25519}, true, []) -Fail Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, []) +Pass Good parameters: Ed25519 bits (spki, buffer(44), {name: Ed25519}, true, []) +Pass Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, []) Pass Good parameters: Ed25519 bits (jwk, object(kty, crv, x), {name: Ed25519}, true, []) Pass Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, []) Pass Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), {name: Ed25519}, true, []) Pass Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, []) Pass Good parameters: Ed25519 bits (raw, buffer(32), {name: Ed25519}, true, []) Pass Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, []) -Fail Good parameters: Ed25519 bits (spki, buffer(44), {name: Ed25519}, true, [verify, verify]) -Fail Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify, verify]) +Pass Good parameters: Ed25519 bits (spki, buffer(44), {name: Ed25519}, true, [verify, verify]) +Pass Good parameters: Ed25519 bits (spki, buffer(44), Ed25519, true, [verify, verify]) Pass Good parameters: Ed25519 bits (jwk, object(kty, crv, x), {name: Ed25519}, true, [verify, verify]) Pass Good parameters: Ed25519 bits (jwk, object(kty, crv, x), Ed25519, true, [verify, verify]) Pass Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), {name: Ed25519}, true, [verify, verify]) Pass Good parameters with ignored JWK alg: Ed25519 (jwk, object(kty, crv, x), Ed25519, true, [verify, verify]) Pass Good parameters: Ed25519 bits (raw, buffer(32), {name: Ed25519}, true, [verify, verify]) Pass Good parameters: Ed25519 bits (raw, buffer(32), Ed25519, true, [verify, verify]) -Fail Good parameters: Ed25519 bits (pkcs8, buffer(48), {name: Ed25519}, true, [sign]) -Fail Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign]) +Pass Good parameters: Ed25519 bits (pkcs8, buffer(48), {name: Ed25519}, true, [sign]) +Pass Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign]) Pass Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), {name: Ed25519}, true, [sign]) Pass Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign]) Pass Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), {name: Ed25519}, true, [sign]) Pass Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), Ed25519, true, [sign]) -Fail Good parameters: Ed25519 bits (pkcs8, buffer(48), {name: Ed25519}, true, [sign, sign]) -Fail Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign, sign]) +Pass Good parameters: Ed25519 bits (pkcs8, buffer(48), {name: Ed25519}, true, [sign, sign]) +Pass Good parameters: Ed25519 bits (pkcs8, buffer(48), Ed25519, true, [sign, sign]) Pass Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), {name: Ed25519}, true, [sign, sign]) Pass Good parameters: Ed25519 bits (jwk, object(crv, d, x, kty), Ed25519, true, [sign, sign]) Pass Good parameters with ignored JWK alg: Ed25519 (jwk, object(crv, d, x, kty), {name: Ed25519}, true, [sign, sign]) diff --git a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.txt b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.txt index f0206395697..71448293d7a 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_X25519.https.any.txt @@ -2,10 +2,10 @@ Harness status: OK Found 54 tests -24 Pass -30 Fail -Fail Good parameters: X25519 bits (spki, buffer(44), {name: X25519}, true, []) -Fail Good parameters: X25519 bits (spki, buffer(44), X25519, true, []) +26 Pass +28 Fail +Pass Good parameters: X25519 bits (spki, buffer(44), {name: X25519}, true, []) +Pass Good parameters: X25519 bits (spki, buffer(44), X25519, true, []) Fail Good parameters: X25519 bits (jwk, object(kty, crv, x), {name: X25519}, true, []) Fail Good parameters: X25519 bits (jwk, object(kty, crv, x), X25519, true, []) Fail Good parameters with ignored JWK alg: X25519 (jwk, object(kty, crv, x), {name: X25519}, true, []) diff --git a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_X448.https.any.txt b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_X448.https.any.txt index 29405850640..1b533342cfe 100644 --- a/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_X448.https.any.txt +++ b/Tests/LibWeb/Text/expected/wpt-import/WebCryptoAPI/import_export/okp_importKey_X448.https.any.txt @@ -2,10 +2,10 @@ Harness status: OK Found 54 tests -24 Pass -30 Fail -Fail Good parameters: X448 bits (spki, buffer(68), {name: X448}, true, []) -Fail Good parameters: X448 bits (spki, buffer(68), X448, true, []) +26 Pass +28 Fail +Pass Good parameters: X448 bits (spki, buffer(68), {name: X448}, true, []) +Pass Good parameters: X448 bits (spki, buffer(68), X448, true, []) Fail Good parameters: X448 bits (jwk, object(kty, crv, x), {name: X448}, true, []) Fail Good parameters: X448 bits (jwk, object(kty, crv, x), X448, true, []) Fail Good parameters with ignored JWK alg: X448 (jwk, object(kty, crv, x), {name: X448}, true, [])