cratestack_cose/keys/
signers.rs1use std::fmt;
5
6use cratestack_core::CratestackError;
7use ed25519_dalek::Signer as _;
9use ed25519_dalek::ed25519::signature::MultipartSigner as _;
10use p256::ecdsa::signature::DigestSigner as _;
11use sha2::{Digest, Sha256};
12
13use super::traits::CoseSigner;
14use super::verify_key::CoseVerifyKey;
15use crate::alg::CoseAlg;
16use crate::thumbprint::KID_LEN;
17
18#[derive(Clone)]
34pub struct Ed25519Signer {
35 key: ed25519_dalek::SigningKey,
36 kid: [u8; KID_LEN],
37}
38
39impl Ed25519Signer {
40 pub fn from_seed(seed: &[u8; 32]) -> Self {
43 let key = ed25519_dalek::SigningKey::from_bytes(seed);
44 let kid = CoseVerifyKey::from_ed25519(key.verifying_key()).kid();
45 Self { key, kid }
46 }
47
48 pub fn verify_key(&self) -> CoseVerifyKey {
50 CoseVerifyKey::from_ed25519(self.key.verifying_key())
51 }
52}
53
54impl fmt::Debug for Ed25519Signer {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 f.debug_struct("Ed25519Signer")
57 .field("kid", &self.kid)
58 .finish_non_exhaustive()
59 }
60}
61
62#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
63#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
64impl CoseSigner for Ed25519Signer {
65 fn alg(&self) -> CoseAlg {
66 CoseAlg::Ed25519
67 }
68
69 fn kid(&self) -> &[u8] {
70 &self.kid
71 }
72
73 async fn sign(&self, to_be_signed: &[u8]) -> Result<Vec<u8>, CratestackError> {
74 Ok(self.key.sign(to_be_signed).to_bytes().to_vec())
75 }
76
77 fn sign_chunks(&self, to_be_signed: &[&[u8]]) -> Option<Result<Vec<u8>, CratestackError>> {
79 Some(
80 self.key
81 .try_multipart_sign(to_be_signed)
82 .map(|signature| signature.to_bytes().to_vec())
83 .map_err(|_| CratestackError::Internal("Ed25519 signing failed".to_owned())),
84 )
85 }
86}
87
88#[derive(Clone)]
98pub struct P256Signer {
99 key: p256::ecdsa::SigningKey,
100 kid: [u8; KID_LEN],
101}
102
103impl P256Signer {
104 pub fn from_scalar(scalar: &[u8; 32]) -> Result<Self, CratestackError> {
107 let key = p256::ecdsa::SigningKey::from_slice(scalar)
108 .map_err(|_| CratestackError::Validation("invalid P-256 private key".to_owned()))?;
109 let kid = CoseVerifyKey::from_p256(*key.verifying_key()).kid();
110 Ok(Self { key, kid })
111 }
112
113 pub fn verify_key(&self) -> CoseVerifyKey {
115 CoseVerifyKey::from_p256(*self.key.verifying_key())
116 }
117
118 fn sign_with(
119 &self,
120 feed: impl Fn(&mut Sha256),
121 ) -> Result<p256::ecdsa::Signature, CratestackError> {
122 self.key
123 .try_sign_digest(|digest: &mut Sha256| {
124 feed(digest);
125 Ok(())
126 })
127 .map_err(|_| CratestackError::Internal("P-256 signing failed".to_owned()))
128 }
129}
130
131impl fmt::Debug for P256Signer {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 f.debug_struct("P256Signer")
134 .field("kid", &self.kid)
135 .finish_non_exhaustive()
136 }
137}
138
139#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
140#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
141impl CoseSigner for P256Signer {
142 fn alg(&self) -> CoseAlg {
143 CoseAlg::Esp256
144 }
145
146 fn kid(&self) -> &[u8] {
147 &self.kid
148 }
149
150 async fn sign(&self, to_be_signed: &[u8]) -> Result<Vec<u8>, CratestackError> {
151 let signature = self.sign_with(|digest| Digest::update(digest, to_be_signed))?;
152 Ok(signature.to_bytes().to_vec())
153 }
154
155 fn sign_chunks(&self, to_be_signed: &[&[u8]]) -> Option<Result<Vec<u8>, CratestackError>> {
159 Some(
160 self.sign_with(|digest| {
161 for chunk in to_be_signed {
162 Digest::update(digest, chunk);
163 }
164 })
165 .map(|signature| signature.to_bytes().to_vec()),
166 )
167 }
168}