// algorithm.mbt — Algorithm abstraction (RFC 9421 §6.1).
//
// Signature algorithms are pluggable. The built-in provider is HMAC-SHA256.
// Additional algorithms (rsa-pss-sha512, rsa-v1_5-sha256, ecdsa-p256-sha256,
// ecdsa-p384-sha384, ed25519) are recognized by name but deliberately NOT
// implemented: any attempt to use them returns `AlgorithmNotAllowed` rather
// than a fake success.
///|
/// Key material for a signature algorithm.
pub(all) enum KeyMaterial {
/// A symmetric shared secret (HMAC and MAC algorithms).
SharedSecret(Bytes)
/// An external key reference whose interpretation is provider-specific
/// (e.g. a JWK string for a future asymmetric provider).
ExternalKey(String)
}
///|
/// The interface every signature algorithm must implement.
pub(open) trait SignatureAlgorithm {
/// The canonical algorithm name from the HTTP Signature Algorithms registry
/// (e.g. `hmac-sha256`).
fn name(Self) -> String
/// Computes the signature over `message`.
fn sign(Self, Bytes, KeyMaterial) -> Result[Bytes, HsError]
/// Verifies `signature` over `message`.
fn verify(Self, Bytes, Bytes, KeyMaterial) -> Result[Bool, HsError]
}
///|
/// A provider that returns `AlgorithmNotAllowed` for every unimplemented
/// algorithm name. Using this provider is safer than returning success.
pub struct UnsupportedAlgorithm {
algorithm : String
}
///|
/// Constructs an `UnsupportedAlgorithm` marker for the given name.
pub fn UnsupportedAlgorithm::new(algorithm : String) -> UnsupportedAlgorithm {
{ algorithm, }
}
///|
/// The algorithm name the marker stands for.
pub fn UnsupportedAlgorithm::algorithm_name(
self : UnsupportedAlgorithm,
) -> String {
self.algorithm
}
///|
/// Returns `AlgorithmNotAllowed` for signing (unimplemented algorithm).
pub fn UnsupportedAlgorithm::sign(
self : UnsupportedAlgorithm,
_message : Bytes,
_key : KeyMaterial,
) -> Result[Bytes, HsError] {
Err(
hs_error(
CryptographicVerification,
AlgorithmNotAllowed,
"algorithm not implemented: " + self.algorithm,
),
)
}
///|
/// Returns `AlgorithmNotAllowed` for verification (unimplemented algorithm).
pub fn UnsupportedAlgorithm::verify(
self : UnsupportedAlgorithm,
_message : Bytes,
_signature : Bytes,
_key : KeyMaterial,
) -> Result[Bool, HsError] {
Err(
hs_error(
CryptographicVerification,
AlgorithmNotAllowed,
"algorithm not implemented: " + self.algorithm,
),
)
}
///|
/// Implements `SignatureAlgorithm` for `UnsupportedAlgorithm`.
pub impl SignatureAlgorithm for UnsupportedAlgorithm with fn name(self) {
self.algorithm
}
///|
/// Implements `sign` for `UnsupportedAlgorithm`.
pub impl SignatureAlgorithm for UnsupportedAlgorithm with fn sign(
self,
message,
key,
) {
self.sign(message, key)
}
///|
/// Implements `verify` for `UnsupportedAlgorithm`.
pub impl SignatureAlgorithm for UnsupportedAlgorithm with fn verify(
self,
message,
signature,
key,
) {
self.verify(message, signature, key)
}
///|
/// A concrete, owned algorithm provider (either a built-in or an
/// unsupported-algorithm marker). This is what the signer/verifier carry
/// around so the `SignatureAlgorithm` trait can be used without lifetimes.
pub(all) enum SignatureAlgorithmProvider {
Hmac(HmacSha256)
Unsupported(UnsupportedAlgorithm)
}
///|
/// Implements `SignatureAlgorithm` for `SignatureAlgorithmProvider`.
pub impl SignatureAlgorithm for SignatureAlgorithmProvider with fn name(self) {
match self {
Hmac(h) => h.name()
Unsupported(u) => u.name()
}
}
///|
/// Implements `sign` for `SignatureAlgorithmProvider`.
pub impl SignatureAlgorithm for SignatureAlgorithmProvider with fn sign(
self,
message,
key,
) {
match self {
Hmac(h) => h.sign(message, key)
Unsupported(u) => u.sign(message, key)
}
}
///|
/// Implements `verify` for `SignatureAlgorithmProvider`.
pub impl SignatureAlgorithm for SignatureAlgorithmProvider with fn verify(
self,
message,
signature,
key,
) {
match self {
Hmac(h) => h.verify(message, signature, key)
Unsupported(u) => u.verify(message, signature, key)
}
}