mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-05-02 04:27:12 +02:00
LibWeb: Validate JWK key length for OKP importKey
After base64url-decoding the x and d fields during JWK import, verify the decoded byte length matches the expected key size for the curve (32 for Ed25519/X25519, 57 for Ed448, 56 for X448). A truncated value does not "contain the public/private key" as required by RFC 8037 Section 2.
This commit is contained in:
committed by
Jelle Raaijmakers
parent
00e9396cfe
commit
32af84b698
Notes:
github-actions[bot]
2026-04-19 11:36:39 +00:00
Author: https://github.com/tete17 Commit: https://github.com/LadybirdBrowser/ladybird/commit/32af84b698f Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8886 Reviewed-by: https://github.com/gmta ✅
@@ -6082,19 +6082,19 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> ED25519::import_key(
|
||||
// o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
|
||||
if (!jwk.x.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing x field"_utf16);
|
||||
auto public_key = TRY(base64_url_bytes_decode(m_realm, jwk.x.value()));
|
||||
if (public_key.size() != 32)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
|
||||
// This parameter MUST NOT be present for public keys.
|
||||
if (!jwk.d.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Present d field"_utf16);
|
||||
auto private_key = TRY(base64_url_bytes_decode(m_realm, jwk.d.value()));
|
||||
if (private_key.size() != 32)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// 2. Let key be a new CryptoKey object that represents the Ed25519 private key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
auto private_key_base_64 = jwk.d.value();
|
||||
auto private_key_or_error = decode_base64url(private_key_base_64);
|
||||
if (private_key_or_error.is_error()) {
|
||||
return WebIDL::DataError::create(m_realm, "Failed to decode base64"_utf16);
|
||||
}
|
||||
auto private_key = private_key_or_error.release_value();
|
||||
key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key });
|
||||
|
||||
// 3. Set the [[type]] internal slot of Key to "private".
|
||||
@@ -6115,6 +6115,9 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> ED25519::import_key(
|
||||
// o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
|
||||
if (!jwk.x.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing x field"_utf16);
|
||||
auto public_key = TRY(base64_url_bytes_decode(m_realm, jwk.x.value()));
|
||||
if (public_key.size() != 32)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
|
||||
// This parameter MUST NOT be present for public keys.
|
||||
@@ -6122,12 +6125,6 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> ED25519::import_key(
|
||||
return WebIDL::DataError::create(m_realm, "Present d field"_utf16);
|
||||
|
||||
// 2. Let key be a new CryptoKey object that represents the Ed25519 public key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
auto public_key_base_64 = jwk.x.value();
|
||||
auto public_key_or_error = decode_base64url(public_key_base_64);
|
||||
if (public_key_or_error.is_error()) {
|
||||
return WebIDL::DataError::create(m_realm, "Failed to decode base64"_utf16);
|
||||
}
|
||||
auto public_key = public_key_or_error.release_value();
|
||||
key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
|
||||
|
||||
// 3. Set the [[type]] internal slot of Key to "public".
|
||||
@@ -6590,19 +6587,19 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> ED448::import_key(
|
||||
// o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
|
||||
if (!jwk.x.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing x field"_utf16);
|
||||
auto public_key = TRY(base64_url_bytes_decode(m_realm, jwk.x.value()));
|
||||
if (public_key.size() != 57)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
|
||||
// This parameter MUST NOT be present for public keys.
|
||||
if (!jwk.d.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Present d field"_utf16);
|
||||
auto private_key = TRY(base64_url_bytes_decode(m_realm, jwk.d.value()));
|
||||
if (private_key.size() != 57)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// 2. Let key be a new CryptoKey object that represents the Ed448 private key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
auto private_key_base_64 = jwk.d.value();
|
||||
auto private_key_or_error = decode_base64url(private_key_base_64);
|
||||
if (private_key_or_error.is_error()) {
|
||||
return WebIDL::DataError::create(m_realm, "Failed to decode base64"_utf16);
|
||||
}
|
||||
auto private_key = private_key_or_error.release_value();
|
||||
key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key });
|
||||
|
||||
// 3. Set the [[type]] internal slot of Key to "private".
|
||||
@@ -6623,6 +6620,9 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> ED448::import_key(
|
||||
// o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
|
||||
if (!jwk.x.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing x field"_utf16);
|
||||
auto public_key = TRY(base64_url_bytes_decode(m_realm, jwk.x.value()));
|
||||
if (public_key.size() != 57)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
|
||||
// This parameter MUST NOT be present for public keys.
|
||||
@@ -6630,12 +6630,6 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> ED448::import_key(
|
||||
return WebIDL::DataError::create(m_realm, "Present d field"_utf16);
|
||||
|
||||
// 2. Let key be a new CryptoKey object that represents the Ed448 public key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
auto public_key_base_64 = jwk.x.value();
|
||||
auto public_key_or_error = decode_base64url(public_key_base_64);
|
||||
if (public_key_or_error.is_error()) {
|
||||
return WebIDL::DataError::create(m_realm, "Failed to decode base64"_utf16);
|
||||
}
|
||||
auto public_key = public_key_or_error.release_value();
|
||||
key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
|
||||
|
||||
// 3. Set the [[type]] internal slot of Key to "public".
|
||||
@@ -7321,19 +7315,19 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> X25519::import_key([[maybe_unused]] Web:
|
||||
// o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
|
||||
if (!jwk.x.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing x field"_utf16);
|
||||
auto public_key = TRY(base64_url_bytes_decode(m_realm, jwk.x.value()));
|
||||
if (public_key.size() != 32)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
|
||||
// This parameter MUST NOT be present for public keys.
|
||||
if (!jwk.d.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing d field"_utf16);
|
||||
auto private_key = TRY(base64_url_bytes_decode(m_realm, jwk.d.value()));
|
||||
if (private_key.size() != 32)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// 2. Let key be a new CryptoKey object that represents the X25519 private key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
auto private_key_base_64 = jwk.d.value();
|
||||
auto private_key_or_error = decode_base64url(private_key_base_64);
|
||||
if (private_key_or_error.is_error()) {
|
||||
return WebIDL::DataError::create(m_realm, "Failed to decode base64"_utf16);
|
||||
}
|
||||
auto private_key = private_key_or_error.release_value();
|
||||
key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key });
|
||||
|
||||
// 3. Set the [[type]] internal slot of Key to "private".
|
||||
@@ -7354,19 +7348,15 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> X25519::import_key([[maybe_unused]] Web:
|
||||
// o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
|
||||
if (!jwk.x.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing x field"_utf16);
|
||||
auto public_key = TRY(base64_url_bytes_decode(m_realm, jwk.x.value()));
|
||||
if (public_key.size() != 32)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
|
||||
// This parameter MUST NOT be present for public keys.
|
||||
if (jwk.d.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Present d field"_utf16);
|
||||
|
||||
// 2. Let key be a new CryptoKey object that represents the X25519 public key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
auto public_key_base_64 = jwk.x.value();
|
||||
auto public_key_or_error = decode_base64url(public_key_base_64);
|
||||
if (public_key_or_error.is_error()) {
|
||||
return WebIDL::DataError::create(m_realm, "Failed to decode base64"_utf16);
|
||||
}
|
||||
auto public_key = public_key_or_error.release_value();
|
||||
key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
|
||||
|
||||
// 3. Set the [[type]] internal slot of Key to "public".
|
||||
@@ -7938,19 +7928,19 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> X448::import_key(
|
||||
// o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
|
||||
if (!jwk.x.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing x field"_utf16);
|
||||
auto public_key = TRY(base64_url_bytes_decode(m_realm, jwk.x.value()));
|
||||
if (public_key.size() != 56)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
|
||||
// This parameter MUST NOT be present for public keys.
|
||||
if (!jwk.d.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing d field"_utf16);
|
||||
auto private_key = TRY(base64_url_bytes_decode(m_realm, jwk.d.value()));
|
||||
if (private_key.size() != 56)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// 2. Let key be a new CryptoKey object that represents the X25519 private key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
auto private_key_base_64 = jwk.d.value();
|
||||
auto private_key_or_error = decode_base64url(private_key_base_64);
|
||||
if (private_key_or_error.is_error()) {
|
||||
return WebIDL::DataError::create(m_realm, "Failed to decode base64"_utf16);
|
||||
}
|
||||
auto private_key = private_key_or_error.release_value();
|
||||
// 2. Let key be a new CryptoKey object that represents the X448 private key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { private_key });
|
||||
|
||||
// 3. Set the [[type]] internal slot of Key to "private".
|
||||
@@ -7971,19 +7961,16 @@ WebIDL::ExceptionOr<GC::Ref<CryptoKey>> X448::import_key(
|
||||
// o The parameter "x" MUST be present and contain the public key encoded using the base64url [RFC4648] encoding.
|
||||
if (!jwk.x.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Missing x field"_utf16);
|
||||
auto public_key = TRY(base64_url_bytes_decode(m_realm, jwk.x.value()));
|
||||
if (public_key.size() != 56)
|
||||
return WebIDL::DataError::create(m_realm, "Invalid key length"_utf16);
|
||||
|
||||
// o The parameter "d" MUST be present for private keys and contain the private key encoded using the base64url encoding.
|
||||
// This parameter MUST NOT be present for public keys.
|
||||
if (jwk.d.has_value())
|
||||
return WebIDL::DataError::create(m_realm, "Present d field"_utf16);
|
||||
|
||||
// 2. Let key be a new CryptoKey object that represents the Ed25519 public key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
auto public_key_base_64 = jwk.x.value();
|
||||
auto public_key_or_error = decode_base64url(public_key_base_64);
|
||||
if (public_key_or_error.is_error()) {
|
||||
return WebIDL::DataError::create(m_realm, "Failed to decode base64"_utf16);
|
||||
}
|
||||
auto public_key = public_key_or_error.release_value();
|
||||
// 2. Let key be a new CryptoKey object that represents the X448 public key identified by interpreting jwk according to Section 2 of [RFC8037].
|
||||
key = CryptoKey::create(m_realm, CryptoKey::InternalKeyData { public_key });
|
||||
|
||||
// 3. Set the [[type]] internal slot of Key to "public".
|
||||
|
||||
Reference in New Issue
Block a user