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