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