1use ciborium::{Value, value::Integer};
7use coset::{
8 CborSerializable, RegisteredLabel, RegisteredLabelWithPrivate,
9 iana::{Algorithm, EllipticCurve, EnumI64, KeyOperation, KeyType, OkpKeyParameter},
10};
11
12use super::{SignatureAlgorithm, ed25519_verifying_key, key_id};
13use crate::{
14 CoseKeyBytes, CryptoError,
15 content_format::CoseKeyContentFormat,
16 cose::CoseSerializable,
17 error::{EncodingError, SignatureError},
18 keys::KeyId,
19};
20
21pub(super) enum RawVerifyingKey {
24 Ed25519(ed25519_dalek::VerifyingKey),
25}
26
27pub struct VerifyingKey {
31 pub(super) id: KeyId,
32 pub(super) inner: RawVerifyingKey,
33}
34
35impl std::fmt::Debug for VerifyingKey {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 let key_suffix = match &self.inner {
38 RawVerifyingKey::Ed25519(_) => "Ed25519",
39 };
40 let mut debug_struct = f.debug_struct(format!("VerifyingKey::{}", key_suffix).as_str());
41 debug_struct.field("id", &self.id);
42 match self.inner {
43 RawVerifyingKey::Ed25519(key) => {
44 debug_struct.field("key", &hex::encode(key.to_bytes()));
45 }
46 }
47 debug_struct.finish()
48 }
49}
50
51impl VerifyingKey {
52 pub fn algorithm(&self) -> SignatureAlgorithm {
54 match &self.inner {
55 RawVerifyingKey::Ed25519(_) => SignatureAlgorithm::Ed25519,
56 }
57 }
58
59 pub(super) fn verify_raw(&self, signature: &[u8], data: &[u8]) -> Result<(), CryptoError> {
63 match &self.inner {
64 RawVerifyingKey::Ed25519(key) => {
65 let sig = ed25519_dalek::Signature::from_bytes(
66 signature
67 .try_into()
68 .map_err(|_| SignatureError::InvalidSignature)?,
69 );
70 key.verify_strict(data, &sig)
71 .map_err(|_| SignatureError::InvalidSignature.into())
72 }
73 }
74 }
75}
76
77impl CoseSerializable<CoseKeyContentFormat> for VerifyingKey {
78 fn to_cose(&self) -> CoseKeyBytes {
79 match &self.inner {
80 RawVerifyingKey::Ed25519(key) => coset::CoseKeyBuilder::new_okp_key()
81 .key_id((&self.id).into())
82 .algorithm(Algorithm::EdDSA)
83 .param(
84 OkpKeyParameter::Crv.to_i64(), Value::Integer(Integer::from(EllipticCurve::Ed25519.to_i64())),
86 )
87 .param(
92 OkpKeyParameter::X.to_i64(), Value::Bytes(key.to_bytes().to_vec()),
94 )
95 .add_key_op(KeyOperation::Verify)
96 .build()
97 .to_vec()
98 .expect("Verifying key is always serializable")
99 .into(),
100 }
101 }
102
103 fn from_cose(bytes: &CoseKeyBytes) -> Result<Self, EncodingError>
104 where
105 Self: Sized,
106 {
107 let cose_key = coset::CoseKey::from_slice(bytes.as_ref())
108 .map_err(|_| EncodingError::InvalidCoseEncoding)?;
109
110 let algorithm = cose_key
111 .alg
112 .as_ref()
113 .ok_or(EncodingError::MissingValue("COSE key algorithm"))?;
114 match (&cose_key.kty, algorithm) {
115 (
116 RegisteredLabel::Assigned(KeyType::OKP),
117 RegisteredLabelWithPrivate::Assigned(Algorithm::EdDSA),
118 ) => Ok(VerifyingKey {
119 id: key_id(&cose_key)?,
120 inner: RawVerifyingKey::Ed25519(ed25519_verifying_key(&cose_key)?),
121 }),
122 _ => Err(EncodingError::UnsupportedValue(
123 "COSE key type or algorithm",
124 )),
125 }
126 }
127}
128
129#[cfg(test)]
130mod tests {
131 use super::*;
132
133 const VERIFYING_KEY: &[u8] = &[
134 166, 1, 1, 2, 80, 55, 131, 40, 191, 230, 137, 76, 182, 184, 139, 94, 152, 45, 63, 13, 71,
135 3, 39, 4, 129, 2, 32, 6, 33, 88, 32, 93, 213, 35, 177, 81, 219, 226, 241, 147, 140, 238,
136 32, 34, 183, 213, 107, 227, 92, 75, 84, 208, 47, 198, 80, 18, 188, 172, 145, 184, 154, 26,
137 170,
138 ];
139 const SIGNED_DATA_RAW: &[u8] = &[
140 247, 239, 74, 181, 75, 54, 137, 225, 2, 158, 14, 0, 61, 210, 254, 208, 255, 16, 8, 81, 173,
141 33, 59, 67, 204, 31, 45, 38, 147, 118, 228, 84, 235, 252, 104, 38, 194, 173, 62, 52, 9,
142 184, 1, 22, 113, 134, 154, 108, 24, 83, 78, 2, 23, 235, 80, 22, 57, 110, 100, 24, 151, 33,
143 186, 12,
144 ];
145
146 #[test]
147 fn test_cose_roundtrip_encode_verifying() {
148 let verifying_key = VerifyingKey::from_cose(&CoseKeyBytes::from(VERIFYING_KEY)).unwrap();
149 let cose = verifying_key.to_cose();
150 let parsed_key = VerifyingKey::from_cose(&cose).unwrap();
151
152 assert_eq!(verifying_key.to_cose(), parsed_key.to_cose());
153 }
154
155 #[test]
156 fn test_testvector() {
157 let verifying_key = VerifyingKey::from_cose(&CoseKeyBytes::from(VERIFYING_KEY)).unwrap();
158 assert_eq!(verifying_key.algorithm(), SignatureAlgorithm::Ed25519);
159
160 verifying_key
161 .verify_raw(SIGNED_DATA_RAW, b"Test message")
162 .unwrap();
163 }
164
165 #[test]
166 fn test_invalid_testvector() {
167 let verifying_key = VerifyingKey::from_cose(&CoseKeyBytes::from(VERIFYING_KEY)).unwrap();
168 assert_eq!(verifying_key.algorithm(), SignatureAlgorithm::Ed25519);
169
170 assert!(
172 verifying_key
173 .verify_raw(SIGNED_DATA_RAW, b"Invalid message")
174 .is_err()
175 );
176 }
177}