use cbor2::Cbor;
use crate::{
header::{decode_protected, encode_protected},
iana, tag, util, Error, Header, Signer, Value, Verifier,
};
#[derive(Clone, Debug, PartialEq, Cbor)]
struct Sign1Wire(
#[serde(with = "serde_bytes")] Vec<u8>,
Header,
#[serde(with = "serde_bytes")] Option<Vec<u8>>,
#[serde(with = "serde_bytes")] Vec<u8>,
);
#[derive(Clone, Debug, Default, PartialEq)]
pub struct Sign1Message {
pub protected: Header,
pub unprotected: Header,
pub payload: Option<Vec<u8>>,
signature: Vec<u8>,
protected_raw: Vec<u8>,
signed: bool,
}
impl Sign1Message {
pub fn new(payload: Option<Vec<u8>>) -> Self {
Sign1Message {
payload,
..Default::default()
}
}
fn to_be_signed(
protected_raw: &[u8],
external_aad: &[u8],
payload: &Option<Vec<u8>>,
) -> Vec<u8> {
util::encode_structure(vec![
Value::from("Signature1"),
Value::Bytes(protected_raw.to_vec()),
Value::Bytes(external_aad.to_vec()),
util::payload_value(payload),
])
}
pub fn sign(&mut self, signer: &dyn Signer, external_aad: Option<&[u8]>) -> Result<(), Error> {
util::ensure_protected_alg(&mut self.protected, signer.alg())?;
util::ensure_unprotected_kid(&mut self.unprotected, signer.kid());
self.protected_raw = encode_protected(&self.protected);
let tbs = Self::to_be_signed(
&self.protected_raw,
external_aad.unwrap_or(&[]),
&self.payload,
);
self.signature = signer.sign(&tbs)?;
self.signed = true;
Ok(())
}
pub fn sign_and_encode(
&mut self,
signer: &dyn Signer,
external_aad: Option<&[u8]>,
) -> Result<Vec<u8>, Error> {
self.sign(signer, external_aad)?;
self.to_vec()
}
pub fn to_vec(&self) -> Result<Vec<u8>, Error> {
if !self.signed {
return Err(Error::Custom(
"Sign1Message must be signed before encoding".into(),
));
}
let wire = Sign1Wire(
self.protected_raw.clone(),
self.unprotected.clone(),
self.payload.clone(),
self.signature.clone(),
);
Ok(tag::with_tag(
tag::SIGN1_PREFIX,
&cbor2::to_canonical_vec(&wire)?,
))
}
pub fn from_slice(data: &[u8]) -> Result<Self, Error> {
let body = tag::untag(data, tag::SIGN1_PREFIX);
let wire: Sign1Wire = cbor2::from_slice(body)?;
let protected = decode_protected(&wire.0)?;
Ok(Sign1Message {
protected,
unprotected: wire.1,
payload: wire.2,
signature: wire.3,
protected_raw: wire.0,
signed: true,
})
}
pub fn verify(
&self,
verifier: &dyn Verifier,
external_aad: Option<&[u8]>,
) -> Result<(), Error> {
if !self.signed {
return Err(Error::Custom(
"Sign1Message must be decoded before verifying".into(),
));
}
util::check_protected_alg(&self.protected, verifier.alg())?;
let tbs = Self::to_be_signed(
&self.protected_raw,
external_aad.unwrap_or(&[]),
&self.payload,
);
verifier.verify(&tbs, &self.signature)
}
pub fn verify_and_decode(
verifier: &dyn Verifier,
data: &[u8],
external_aad: Option<&[u8]>,
) -> Result<Self, Error> {
let msg = Self::from_slice(data)?;
msg.verify(verifier, external_aad)?;
Ok(msg)
}
pub fn signature(&self) -> &[u8] {
&self.signature
}
pub const TAG: u64 = iana::CBORTagCOSESign1;
}