LibCrypto+LibWeb: Reorganize OID ASN1 constants

I have divided ANS1 constants by length so that they don't have
trailing zeros that need to be removed.

Also moved OIDs lists to the only place they are used for clarity.

Fixed a couple of WPT tests by adding SECP521r1 to the list of known
curves.
This commit is contained in:
devgianlu 2024-11-29 14:54:32 +01:00 committed by Andreas Kling
parent b39fdcfec2
commit ab2960e49f
Notes: github-actions[bot] 2024-11-30 10:19:21 +00:00
8 changed files with 75 additions and 103 deletions

View file

@ -109,15 +109,17 @@ ErrorOr<Vector<int>> parse_ec_parameters(Crypto::ASN1::Decoder& decoder, Vector<
// }
PUSH_SCOPE("ECParameters"sv);
READ_OBJECT(ObjectIdentifier, Vector<int>, named_curve);
// Note: namedCurve sometimes has 5 nodes, but we need 7 for the comparison below to work.
while (named_curve.size() < 7) {
named_curve.append(0);
}
POP_SCOPE();
constexpr static Array<Span<int const>, 3> known_curve_identifiers {
secp256r1_oid,
secp384r1_oid,
secp521r1_oid
};
bool is_known_curve = false;
for (auto const& curves : known_curve_identifiers) {
if (curves.span() == named_curve.span()) {
if (curves == named_curve.span()) {
is_known_curve = true;
break;
}
@ -139,15 +141,26 @@ static ErrorOr<AlgorithmIdentifier> parse_algorithm_identifier(Crypto::ASN1::Dec
ENTER_TYPED_SCOPE(Sequence, "AlgorithmIdentifier"sv);
PUSH_SCOPE("algorithm"sv);
READ_OBJECT(ObjectIdentifier, Vector<int>, algorithm);
// Note: ecPublicKey only has 6 nodes, but we need 7 for the comparison below to work.
while (algorithm.size() < 7) {
algorithm.append(0);
}
POP_SCOPE();
constexpr static Array<Span<int const>, 12> known_algorithm_identifiers {
rsa_encryption_oid,
rsa_md5_encryption_oid,
rsa_sha1_encryption_oid,
rsa_sha256_encryption_oid,
rsa_sha384_encryption_oid,
rsa_sha512_encryption_oid,
ecdsa_with_sha256_encryption_oid,
ecdsa_with_sha384_encryption_oid,
ec_public_key_encryption_oid,
x25519_oid,
ed25519_oid,
x448_oid,
};
bool is_known_algorithm = false;
for (auto const& inner : known_algorithm_identifiers) {
if (inner.span() == algorithm.span()) {
if (inner == algorithm.span()) {
is_known_algorithm = true;
break;
}
@ -166,7 +179,7 @@ static ErrorOr<AlgorithmIdentifier> parse_algorithm_identifier(Crypto::ASN1::Dec
// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
// sha224WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 14 }
Array<Array<int, 7>, 8> rsa_null_algorithms = {
constexpr static Array<Span<int const>, 8> rsa_null_algorithms = {
rsa_encryption_oid,
rsa_md5_encryption_oid,
rsa_sha1_encryption_oid,
@ -178,7 +191,7 @@ static ErrorOr<AlgorithmIdentifier> parse_algorithm_identifier(Crypto::ASN1::Dec
bool is_rsa_null_algorithm = false;
for (auto const& inner : rsa_null_algorithms) {
if (inner.span() == algorithm.span()) {
if (inner == algorithm.span()) {
is_rsa_null_algorithm = true;
break;
}
@ -202,7 +215,7 @@ static ErrorOr<AlgorithmIdentifier> parse_algorithm_identifier(Crypto::ASN1::Dec
// https://datatracker.ietf.org/doc/html/rfc8410#section-9
// For all of the OIDs, the parameters MUST be absent.
Array<Array<int, 7>, 8> no_parameter_algorithms = {
constexpr static Array<Span<int const>, 8> no_parameter_algorithms = {
ecdsa_with_sha224_encryption_oid,
ecdsa_with_sha256_encryption_oid,
ecdsa_with_sha384_encryption_oid,
@ -215,7 +228,7 @@ static ErrorOr<AlgorithmIdentifier> parse_algorithm_identifier(Crypto::ASN1::Dec
bool is_no_parameter_algorithm = false;
for (auto const& inner : no_parameter_algorithms) {
if (inner.span() == algorithm.span()) {
if (inner == algorithm.span()) {
is_no_parameter_algorithm = true;
}
}
@ -381,7 +394,7 @@ ErrorOr<SubjectPublicKey> parse_subject_public_key_info(Crypto::ASN1::Decoder& d
// https://datatracker.ietf.org/doc/html/rfc8410#section-9
// For all of the OIDs, the parameters MUST be absent.
Array<Array<int, 7>, 5> no_parameter_algorithms = {
constexpr static Array<Span<int const>, 5> no_parameter_algorithms = {
ec_public_key_encryption_oid,
x25519_oid,
x448_oid,
@ -390,7 +403,7 @@ ErrorOr<SubjectPublicKey> parse_subject_public_key_info(Crypto::ASN1::Decoder& d
};
for (auto const& inner : no_parameter_algorithms) {
if (public_key.algorithm.identifier.span() == inner.span()) {
if (public_key.algorithm.identifier.span() == inner) {
// Note: Raw key is already stored, so we can just exit out at this point.
EXIT_SCOPE();
return public_key;
@ -451,7 +464,7 @@ ErrorOr<PrivateKey> parse_private_key_info(Crypto::ASN1::Decoder& decoder, Vecto
// https://datatracker.ietf.org/doc/html/rfc8410#section-9
// For all of the OIDs, the parameters MUST be absent.
Array<Array<int, 7>, 5> no_parameter_algorithms = {
constexpr static Array<Span<int const>, 5> no_parameter_algorithms = {
ec_public_key_encryption_oid,
x25519_oid,
x448_oid,
@ -460,7 +473,7 @@ ErrorOr<PrivateKey> parse_private_key_info(Crypto::ASN1::Decoder& decoder, Vecto
};
for (auto const& inner : no_parameter_algorithms) {
if (private_key.algorithm.identifier.span() == inner.span()) {
if (private_key.algorithm.identifier.span() == inner) {
// Note: Raw key is already stored, so we can just exit out at this point.
EXIT_SCOPE();
return private_key;

View file

@ -31,40 +31,20 @@ constexpr static Array<int, 7>
ecdsa_with_sha256_encryption_oid { 1, 2, 840, 10045, 4, 3, 2 },
ecdsa_with_sha384_encryption_oid { 1, 2, 840, 10045, 4, 3, 3 },
ecdsa_with_sha512_encryption_oid { 1, 2, 840, 10045, 4, 3, 4 },
ec_public_key_encryption_oid { 1, 2, 840, 10045, 2, 1 },
secp256r1_oid { 1, 2, 840, 10045, 3, 1, 7 };
constexpr static Array<int, 6>
ec_public_key_encryption_oid { 1, 2, 840, 10045, 2, 1 };
constexpr static Array<int, 5>
secp384r1_oid { 1, 3, 132, 0, 34 },
secp521r1_oid { 1, 3, 132, 0, 35 };
constexpr static Array<int, 4>
x25519_oid { 1, 3, 101, 110 },
x448_oid { 1, 3, 101, 111 },
ed25519_oid { 1, 3, 101, 112 },
ed448_oid { 1, 3, 101, 113 },
secp256r1_oid { 1, 2, 840, 10045, 3, 1, 7 },
secp384r1_oid { 1, 3, 132, 0, 34 },
secp521r1_oid { 1, 3, 132, 0, 35 };
constexpr static Array<Array<int, 7>, 12> known_algorithm_identifiers {
rsa_encryption_oid,
rsa_md5_encryption_oid,
rsa_sha1_encryption_oid,
rsa_sha256_encryption_oid,
rsa_sha384_encryption_oid,
rsa_sha512_encryption_oid,
ecdsa_with_sha256_encryption_oid,
ecdsa_with_sha384_encryption_oid,
ec_public_key_encryption_oid,
x25519_oid,
ed25519_oid,
x448_oid,
};
constexpr static Array<int, 7>
curve_ansip384r1 { 1, 3, 132, 0, 34 },
curve_prime256 { 1, 2, 840, 10045, 3, 1, 7 };
constexpr static Array<Array<int, 7>, 9> known_curve_identifiers {
curve_ansip384r1,
curve_prime256
};
constexpr static Array<int, 4>
key_usage_oid { 2, 5, 29, 15 },
subject_alternative_name_oid { 2, 5, 29, 17 },
issuer_alternative_name_oid { 2, 5, 29, 18 },

View file

@ -597,9 +597,9 @@ ErrorOr<Vector<Certificate>> DefaultRootCACertificates::parse_pem_root_certifica
ErrorOr<SupportedGroup> oid_to_curve(Vector<int> curve)
{
if (curve == Crypto::Certificate::curve_ansip384r1)
if (curve == Crypto::Certificate::secp384r1_oid)
return SupportedGroup::SECP384R1;
if (curve == Crypto::Certificate::curve_prime256)
if (curve == Crypto::Certificate::secp256r1_oid)
return SupportedGroup::SECP256R1;
return AK::Error::from_string_literal("Unknown curve oid");

View file

@ -3144,7 +3144,7 @@ WebIDL::ExceptionOr<GC::Ref<JS::Object>> ECDH::export_key(Bindings::KeyFormat fo
[&](::Crypto::PK::ECPublicKey<> const& public_key) -> ErrorOr<ByteBuffer> {
auto public_key_bytes = TRY(public_key.to_uncompressed());
Array<int, 7> ec_params;
Span<int const> ec_params;
if (algorithm.named_curve() == "P-256"sv)
ec_params = ::Crypto::Certificate::secp256r1_oid;
else if (algorithm.named_curve() == "P-384"sv)
@ -3154,17 +3154,7 @@ WebIDL::ExceptionOr<GC::Ref<JS::Object>> ECDH::export_key(Bindings::KeyFormat fo
else
VERIFY_NOT_REACHED();
// NOTE: we store OIDs as 7 bytes, but they might be shorter
size_t trailing_zeros = 0;
for (size_t i = ec_params.size() - 1; i > 0; --i) {
if (ec_params[i] == 0)
++trailing_zeros;
else
break;
}
auto ec_public_key_oid = ::Crypto::Certificate::ec_public_key_encryption_oid.span().trim(6);
return TRY(::Crypto::PK::wrap_in_subject_public_key_info(public_key_bytes, ec_public_key_oid, ec_params.span().trim(ec_params.size() - trailing_zeros)));
return TRY(::Crypto::PK::wrap_in_subject_public_key_info(public_key_bytes, ::Crypto::Certificate::ec_public_key_encryption_oid, ec_params));
},
[](auto) -> ErrorOr<ByteBuffer> {
VERIFY_NOT_REACHED();
@ -3221,7 +3211,7 @@ WebIDL::ExceptionOr<GC::Ref<JS::Object>> ECDH::export_key(Bindings::KeyFormat fo
// NOTE: everything above happens in wrap_in_private_key_info
auto maybe_data = handle.visit(
[&](::Crypto::PK::ECPrivateKey<> const& private_key) -> ErrorOr<ByteBuffer> {
Array<int, 7> ec_params;
Span<int const> ec_params;
if (algorithm.named_curve() == "P-256"sv)
ec_params = ::Crypto::Certificate::secp256r1_oid;
else if (algorithm.named_curve() == "P-384"sv)
@ -3231,17 +3221,7 @@ WebIDL::ExceptionOr<GC::Ref<JS::Object>> ECDH::export_key(Bindings::KeyFormat fo
else
VERIFY_NOT_REACHED();
// NOTE: we store OIDs as 7 bytes, but they might be shorter
size_t trailing_zeros = 0;
for (size_t i = ec_params.size() - 1; i > 0; --i) {
if (ec_params[i] == 0)
++trailing_zeros;
else
break;
}
auto ec_public_key_oid = ::Crypto::Certificate::ec_public_key_encryption_oid.span().trim(6);
return TRY(::Crypto::PK::wrap_in_private_key_info(private_key, ec_public_key_oid, ec_params.span().trim(ec_params.size() - trailing_zeros)));
return TRY(::Crypto::PK::wrap_in_private_key_info(private_key, ::Crypto::Certificate::ec_public_key_encryption_oid, ec_params));
},
[](auto) -> ErrorOr<ByteBuffer> {
VERIFY_NOT_REACHED();

View file

@ -6,8 +6,8 @@ Rerun
Found 40 tests
25 Pass
15 Fail
30 Pass
10 Fail
Details
Result Test Name MessagePass setup - define tests
Fail P-521 good parameters
@ -16,12 +16,12 @@ Fail P-521 short result
Fail P-521 non-multiple of 8 bits
Pass P-521 missing public curve
Pass P-521 public property of algorithm is not a CryptoKey
Fail P-521 mismatched curves
Pass P-521 mismatched curves
Fail P-521 public property of algorithm is not an ECDSA public key Cannot access property "publicKey" on null object "ecdsaKeyPairs[namedCurve]"
Fail P-521 no deriveBits usage for base key
Fail P-521 base key is not a private key
Fail P-521 public property value is a private key
Fail P-521 public property value is a secret key
Pass P-521 no deriveBits usage for base key
Pass P-521 base key is not a private key
Pass P-521 public property value is a private key
Pass P-521 public property value is a secret key
Fail P-521 asking for too many bits
Pass P-256 good parameters
Pass P-256 mixed case parameters

View file

@ -6,20 +6,20 @@ Rerun
Found 31 tests
23 Pass
8 Fail
28 Pass
3 Fail
Details
Result Test Name MessagePass setup - define tests
Fail P-521 good parameters
Fail P-521 mixed case parameters
Pass P-521 missing public curve
Pass P-521 public property of algorithm is not a CryptoKey
Fail P-521 mismatched curves
Pass P-521 mismatched curves
Fail P-521 public property of algorithm is not an ECDSA public key Cannot access property "publicKey" on null object "ecdsaKeyPairs[namedCurve]"
Fail P-521 no deriveKey usage for base key
Fail P-521 base key is not a private key
Fail P-521 public property value is a private key
Fail P-521 public property value is a secret key
Pass P-521 no deriveKey usage for base key
Pass P-521 base key is not a private key
Pass P-521 public property value is a private key
Pass P-521 public property value is a secret key
Pass P-256 good parameters
Pass P-256 mixed case parameters
Pass P-256 missing public curve

View file

@ -6,8 +6,8 @@ Rerun
Found 246 tests
90 Pass
144 Fail
97 Pass
137 Fail
12 Optional Feature Unsupported
Details
Result Test Name MessageFail Good parameters: P-256 bits (spki, buffer(91), {name: ECDSA, namedCurve: P-256}, true, [verify])
@ -217,7 +217,7 @@ Pass Good parameters: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, n
Pass ECDH any JWK alg: P-384 bits (jwk, object(kty, crv, x, y, d, alg), {name: ECDH, namedCurve: P-384}, false, [deriveKey, deriveBits, deriveKey, deriveBits])
Pass Empty Usages: P-384 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-384}, false, [])
Fail Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, true, [])
Optional Feature Unsupported Good parameters: P-521 bits (spki, buffer(90, compressed), {name: ECDH, namedCurve: P-521}, true, []) Compressed point format not supported: DataError: Error parsing subjectPublicKeyInfo: [ "SubjectPublicKeyInfo"sv, "AlgorithmIdentifier"sv ]: Unknown named curve [ 1, 3, 132, 0, 35, 0, 0 ]
Optional Feature Unsupported Good parameters: P-521 bits (spki, buffer(90, compressed), {name: ECDH, namedCurve: P-521}, true, []) Compressed point format not supported: DataError: Unsupported key format
Fail Good parameters: P-521 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-521}, true, [])
Pass ECDH any JWK alg: P-521 bits (jwk, object(kty, crv, x, y, alg), {name: ECDH, namedCurve: P-521}, true, [])
Fail Good parameters: P-521 bits (raw, buffer(133), {name: ECDH, namedCurve: P-521}, true, [])
@ -226,7 +226,7 @@ Fail Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P
Fail Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey])
Fail Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveBits])
Fail Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits])
Fail Empty Usages: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [])
Pass Empty Usages: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, true, [])
Fail Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [deriveKey])
Pass ECDH any JWK alg: P-521 bits (jwk, object(kty, crv, x, y, d, alg), {name: ECDH, namedCurve: P-521}, true, [deriveKey])
Fail Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [deriveBits, deriveKey])
@ -236,17 +236,17 @@ Pass ECDH any JWK alg: P-521 bits (jwk, object(kty, crv, x, y, d, alg), {name: E
Fail Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits])
Pass ECDH any JWK alg: P-521 bits (jwk, object(kty, crv, x, y, d, alg), {name: ECDH, namedCurve: P-521}, true, [deriveKey, deriveBits, deriveKey, deriveBits])
Pass Empty Usages: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, true, [])
Fail Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, false, [])
Optional Feature Unsupported Good parameters: P-521 bits (spki, buffer(90, compressed), {name: ECDH, namedCurve: P-521}, false, []) Compressed point format not supported: DataError: Error parsing subjectPublicKeyInfo: [ "SubjectPublicKeyInfo"sv, "AlgorithmIdentifier"sv ]: Unknown named curve [ 1, 3, 132, 0, 35, 0, 0 ]
Pass Good parameters: P-521 bits (spki, buffer(158), {name: ECDH, namedCurve: P-521}, false, [])
Optional Feature Unsupported Good parameters: P-521 bits (spki, buffer(90, compressed), {name: ECDH, namedCurve: P-521}, false, []) Compressed point format not supported: DataError: Unsupported key format
Pass Good parameters: P-521 bits (jwk, object(kty, crv, x, y), {name: ECDH, namedCurve: P-521}, false, [])
Pass ECDH any JWK alg: P-521 bits (jwk, object(kty, crv, x, y, alg), {name: ECDH, namedCurve: P-521}, false, [])
Pass Good parameters: P-521 bits (raw, buffer(133), {name: ECDH, namedCurve: P-521}, false, [])
Optional Feature Unsupported Good parameters: P-521 bits (raw, buffer(67, compressed), {name: ECDH, namedCurve: P-521}, false, []) Compressed point format not supported: DataError: Invalid key size
Fail Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveKey])
Fail Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey])
Fail Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits])
Fail Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits])
Fail Empty Usages: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [])
Pass Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveKey])
Pass Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey])
Pass Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveBits])
Pass Good parameters: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [deriveKey, deriveBits, deriveKey, deriveBits])
Pass Empty Usages: P-521 bits (pkcs8, buffer(241), {name: ECDH, namedCurve: P-521}, false, [])
Pass Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, false, [deriveKey])
Pass ECDH any JWK alg: P-521 bits (jwk, object(kty, crv, x, y, d, alg), {name: ECDH, namedCurve: P-521}, false, [deriveKey])
Pass Good parameters: P-521 bits (jwk, object(kty, crv, x, y, d), {name: ECDH, namedCurve: P-521}, false, [deriveBits, deriveKey])

View file

@ -6,8 +6,7 @@ Rerun
Found 608 tests
606 Pass
2 Fail
608 Pass
Details
Result Test Name MessagePass Bad usages: importKey(spki, {name: ECDH, namedCurve: P-256}, true, [encrypt])
Pass Bad usages: importKey(spki, {name: ECDH, namedCurve: P-256}, false, [encrypt])
@ -473,8 +472,8 @@ Pass Empty usages: importKey(pkcs8, {name: ECDH, namedCurve: P-384}, true, [])
Pass Empty usages: importKey(pkcs8, {name: ECDH, namedCurve: P-384}, false, [])
Pass Empty usages: importKey(jwk(private), {name: ECDH, namedCurve: P-384}, true, [])
Pass Empty usages: importKey(jwk(private), {name: ECDH, namedCurve: P-384}, false, [])
Fail Empty usages: importKey(pkcs8, {name: ECDH, namedCurve: P-521}, true, [])
Fail Empty usages: importKey(pkcs8, {name: ECDH, namedCurve: P-521}, false, [])
Pass Empty usages: importKey(pkcs8, {name: ECDH, namedCurve: P-521}, true, [])
Pass Empty usages: importKey(pkcs8, {name: ECDH, namedCurve: P-521}, false, [])
Pass Empty usages: importKey(jwk(private), {name: ECDH, namedCurve: P-521}, true, [])
Pass Empty usages: importKey(jwk(private), {name: ECDH, namedCurve: P-521}, false, [])
Pass Bad key length: importKey(spki, {name: ECDH, namedCurve: P-256}, true, [])