LibWeb: Implement skeleton of ECDSA sign for SubtleCrypto

This commit is contained in:
stelar7 2024-03-27 01:34:04 +01:00 committed by Andrew Kaster
parent 41449814db
commit bc2a5e24bc
Notes: sideshowbarker 2024-07-17 01:06:10 +09:00
5 changed files with 113 additions and 0 deletions

View file

@ -0,0 +1 @@
Signed OK ... [13 bytes total] (Hello friends)

View file

@ -0,0 +1,32 @@
<script src="../include.js"></script>
<script>
asyncTest(async done => {
const encoder = new TextEncoder();
const message = "Hello friends";
const encoded_message = encoder.encode(message);
const key_algorithm = {
name: "ECDSA",
namedCurve: "P-384",
};
const extractable = true;
const usages = ["sign", "verify"];
const key = await window.crypto.subtle.generateKey(key_algorithm, extractable, usages);
const signature_algorithm = {
name: "ECDSA",
hash: { name: "SHA-384" },
};
const signature = await window.crypto.subtle.sign(
signature_algorithm,
key.privateKey,
encoded_message
);
const data_view = String.fromCharCode.apply(null, new Uint8Array(signature));
println(`Signed OK ... [${signature.byteLength} bytes total] (${data_view})`);
done();
});
</script>

View file

@ -345,6 +345,29 @@ JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> RsaOaepParams::from_value(
return adopt_own<AlgorithmParams>(*new RsaOaepParams { name, move(label) });
}
EcdsaParams::~EcdsaParams() = default;
JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> EcdsaParams::from_value(JS::VM& vm, JS::Value value)
{
auto& object = value.as_object();
auto name_value = TRY(object.get("name"));
auto name = TRY(name_value.to_string(vm));
auto hash_value = TRY(object.get("hash"));
auto hash = Variant<Empty, HashAlgorithmIdentifier> { Empty {} };
if (hash_value.is_string()) {
auto hash_string = TRY(hash_value.to_string(vm));
hash = HashAlgorithmIdentifier { hash_string };
} else {
auto hash_object = TRY(hash_value.to_object(vm));
hash = HashAlgorithmIdentifier { hash_object };
}
return adopt_own<AlgorithmParams>(*new EcdsaParams { name, hash.get<HashAlgorithmIdentifier>() });
}
EcKeyGenParams::~EcKeyGenParams() = default;
JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> EcKeyGenParams::from_value(JS::VM& vm, JS::Value value)
@ -1043,4 +1066,42 @@ WebIDL::ExceptionOr<Variant<JS::NonnullGCPtr<CryptoKey>, JS::NonnullGCPtr<Crypto
return Variant<JS::NonnullGCPtr<CryptoKey>, JS::NonnullGCPtr<CryptoKeyPair>> { CryptoKeyPair::create(m_realm, public_key, private_key) };
}
// https://w3c.github.io/webcrypto/#ecdsa-operations
WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> ECDSA::sign(AlgorithmParams const& params, JS::NonnullGCPtr<CryptoKey> key, ByteBuffer const& message)
{
auto& realm = m_realm;
auto& vm = realm.vm();
auto const& normalized_algorithm = static_cast<EcdsaParams const&>(params);
(void)vm;
(void)message;
// 1. If the [[type]] internal slot of key is not "private", then throw an InvalidAccessError.
if (key->type() != Bindings::KeyType::Private)
return WebIDL::InvalidAccessError::create(realm, "Key is not a private key"_fly_string);
// 2. Let hashAlgorithm be the hash member of normalizedAlgorithm.
[[maybe_unused]] auto const& hash_algorithm = normalized_algorithm.hash;
// NOTE: We dont have sign() on the SECPxxxr1 curves, so we can't implement this yet
// FIXME: 3. Let M be the result of performing the digest operation specified by hashAlgorithm using message.
// FIXME: 4. Let d be the ECDSA private key associated with key.
// FIXME: 5. Let params be the EC domain parameters associated with key.
// FIXME: 6. If the namedCurve attribute of the [[algorithm]] internal slot of key is "P-256", "P-384" or "P-521":
// FIXME: 1. Perform the ECDSA signing process, as specified in [RFC6090], Section 5.4, with M as the message, using params as the EC domain parameters, and with d as the private key.
// FIXME: 2. Let r and s be the pair of integers resulting from performing the ECDSA signing process.
// FIXME: 3. Let result be an empty byte sequence.
// FIXME: 4. Let n be the smallest integer such that n * 8 is greater than the logarithm to base 2 of the order of the base point of the elliptic curve identified by params.
// FIXME: 5. Convert r to an octet string of length n and append this sequence of bytes to result.
// FIXME: 6. Convert s to an octet string of length n and append this sequence of bytes to result.
// FIXME: Otherwise, the namedCurve attribute of the [[algorithm]] internal slot of key is a value specified in an applicable specification:
// FIXME: Perform the ECDSA signature steps specified in that specification, passing in M, params and d and resulting in result.
// NOTE: The spec jumps to 9 here for some reason
// FIXME: 9. Return the result of creating an ArrayBuffer containing result.
return WebIDL::NotSupportedError::create(realm, "ECDSA signing is not supported yet"_fly_string);
}
}

View file

@ -117,6 +117,22 @@ struct RsaOaepParams : public AlgorithmParams {
static JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> from_value(JS::VM&, JS::Value);
};
// https://w3c.github.io/webcrypto/#dfn-EcdsaParams
struct EcdsaParams : public AlgorithmParams {
virtual ~EcdsaParams() override;
EcdsaParams(String name, HashAlgorithmIdentifier hash)
: AlgorithmParams(move(name))
, hash(move(hash))
{
}
HashAlgorithmIdentifier hash;
static JS::ThrowCompletionOr<NonnullOwnPtr<AlgorithmParams>> from_value(JS::VM&, JS::Value);
};
// https://w3c.github.io/webcrypto/#dfn-EcKeyGenParams
struct EcKeyGenParams : public AlgorithmParams {
virtual ~EcKeyGenParams() override;
@ -229,6 +245,8 @@ private:
class ECDSA : public AlgorithmMethods {
public:
virtual WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::ArrayBuffer>> sign(AlgorithmParams const&, JS::NonnullGCPtr<CryptoKey>, ByteBuffer const&) override;
virtual WebIDL::ExceptionOr<Variant<JS::NonnullGCPtr<CryptoKey>, JS::NonnullGCPtr<CryptoKeyPair>>> generate_key(AlgorithmParams const&, bool, Vector<Bindings::KeyUsage> const&) override;
static NonnullOwnPtr<AlgorithmMethods> create(JS::Realm& realm) { return adopt_own(*new ECDSA(realm)); }

View file

@ -576,6 +576,7 @@ SupportedAlgorithmsMap supported_algorithms()
define_an_algorithm<RSAOAEP, RsaOaepParams>("decrypt"_string, "RSA-OAEP"_string);
// https://w3c.github.io/webcrypto/#ecdsa
define_an_algorithm<ECDSA, EcdsaParams>("sign"_string, "ECDSA"_string);
define_an_algorithm<ECDSA, EcKeyGenParams>("generateKey"_string, "ECDSA"_string);
return internal_object;