gose/cose/sign
COSE_Sign multi-signer signing and verification (RFC 9052).
Example
import gose/algorithm
import gose/cose/sign
import gose/key
import kryptos/ec
let payload = <<"hello":utf8>>
let k1 = key.generate_ec(ec.P256)
let k2 = key.generate_ec(ec.P384)
let assert Ok(body) =
sign.new(payload:)
|> sign.sign(algorithm.Ecdsa(algorithm.EcdsaP256), key: k1)
let assert Ok(body) =
sign.sign(body, algorithm.Ecdsa(algorithm.EcdsaP384), key: k2)
let signed = sign.assemble(body)
let data = sign.serialize(signed)
let assert Ok(parsed) = sign.parse(data)
let assert Ok(verifier) =
sign.verifier(algorithm.Ecdsa(algorithm.EcdsaP256), keys: [k1])
let assert Ok(Nil) = sign.verify(verifier, parsed)
Building, signing, assembling
Body(state) uses a phantom to enforce ordering:
new(payload:)returnsBody(Building).with_*builders only acceptBody(Building), so configuration happens before any signature is computed.sign(body, alg, key)computes a signature over the body and returnsBody(Signed). Callingsignfrom either state yieldsSigned, so subsequent signers just chain:|> sign(_, alg2, key2).assemble(body)finalizes aBody(Signed)intoSign(Signed).
Because builders require Body(Building), mutating the body after any
sign call is a compile error. The body each signer signed over matches
the body that gets serialized on the wire.
Algorithm Pinning
Each verifier is pinned to a single signature algorithm. The matched
signer’s protected header alg must match the verifier’s expected algorithm.
Types
Outer message body holding body-level protected and unprotected headers, the payload, and any accumulated signatures.
pub opaque type Body(state)
Values
pub fn assemble(body: Body(Signed)) -> Sign(Signed)
Finalize a signed body into a serializable COSE_Sign message.
pub fn content_type(
message: Sign(Signed),
) -> Result(cose.ContentType, gose.GoseError)
Extract the content type from the body-level headers.
pub fn critical(
message: Sign(Signed),
) -> Result(List(Int), gose.GoseError)
Extract the critical header labels from the body-level headers.
pub fn kid(
message: Sign(Signed),
) -> Result(BitArray, gose.GoseError)
Extract the key ID from the body-level headers.
pub fn new(payload payload: BitArray) -> Body(Building)
Create a new body pinned to the payload all signers will sign.
pub fn parse(
data: BitArray,
) -> Result(Sign(Signed), gose.GoseError)
Decode a CBOR-encoded COSE_Sign message, accepting both tagged and untagged forms.
pub fn payload(message: Sign(Signed)) -> Result(BitArray, Nil)
Return the payload from a signed message. Returns Error(Nil) if detached.
pub fn protected_headers(
message: Sign(Signed),
) -> List(cose.Header)
Return the raw body-level protected headers.
pub fn serialize(message: Sign(Signed)) -> BitArray
Encode a signed message as an untagged CBOR COSE_Sign array.
pub fn serialize_tagged(message: Sign(Signed)) -> BitArray
Encode a signed message as a CBOR-tagged (tag 98) COSE_Sign structure.
pub fn sign(
body: Body(state),
alg alg: algorithm.DigitalSignatureAlg,
key key: key.Key(BitArray),
) -> Result(Body(Signed), gose.GoseError)
Compute a per-signer signature over the body’s payload and append it to
the body. Transitions the body to Signed state, preventing further
with_* mutations at compile time.
pub fn unprotected_headers(
message: Sign(Signed),
) -> List(cose.Header)
Return the raw body-level unprotected headers.
pub fn verifier(
alg: algorithm.DigitalSignatureAlg,
keys keys: List(key.Key(BitArray)),
) -> Result(Verifier, gose.GoseError)
Build a verifier pinned to a single signature algorithm and one or more keys.
pub fn verify(
verifier: Verifier,
message: Sign(Signed),
) -> Result(Nil, gose.GoseError)
Verify the first matching signer’s signature.
pub fn verify_detached(
verifier: Verifier,
message message: Sign(Signed),
payload payload: BitArray,
) -> Result(Nil, gose.GoseError)
Verify a detached-payload message.
pub fn verify_detached_with_aad(
verifier: Verifier,
message message: Sign(Signed),
payload payload: BitArray,
aad aad: BitArray,
) -> Result(Nil, gose.GoseError)
Verify a detached-payload message with external AAD.
pub fn verify_with_aad(
verifier: Verifier,
message message: Sign(Signed),
aad aad: BitArray,
) -> Result(Nil, gose.GoseError)
Verify with externally-supplied AAD.
pub fn with_aad(
body: Body(Building),
aad aad: BitArray,
) -> Body(Building)
Set external additional authenticated data (AAD) for the signing operation.
pub fn with_content_type(
body: Body(Building),
ct ct: cose.ContentType,
) -> Body(Building)
Add a content type to the body’s unprotected headers.
RFC 9052 permits either bucket. Signed messages place it in unprotected,
consistent with with_kid.
pub fn with_critical(
body: Body(Building),
labels labels: List(Int),
) -> Body(Building)
Add critical header labels to the body’s protected headers.