Skip to main content

cose_key/
lib.rs

1#[cfg(feature = "bls")]
2mod bls;
3mod codec;
4#[cfg(feature = "p256")]
5mod ecdsa_p256;
6#[cfg(feature = "p384")]
7mod ecdsa_p384;
8#[cfg(feature = "ed25519")]
9mod eddsa_ed25519;
10mod error;
11#[cfg(feature = "pem")]
12mod pem;
13
14use ciborium::Value;
15use coset::{Algorithm, KeyOperation, KeyType, Label, iana, iana::EnumI64};
16pub use error::CoseKeyError;
17
18#[derive(Clone, Debug, Default, PartialEq)]
19pub struct CoseKey(coset::CoseKey);
20
21impl std::hash::Hash for CoseKey {
22    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
23        match &self.kty {
24            KeyType::Assigned(i) => i.to_i64().hash(state),
25            KeyType::Text(s) => s.hash(state),
26        };
27        self.key_id.hash(state);
28        match &self.alg {
29            Some(Algorithm::PrivateUse(i)) => i.hash(state),
30            Some(Algorithm::Assigned(i)) => i.to_i64().hash(state),
31            Some(Algorithm::Text(s)) => s.hash(state),
32            None => {}
33        }
34        for ops in &self.key_ops {
35            match ops {
36                KeyOperation::Assigned(i) => i.to_i64().hash(state),
37                KeyOperation::Text(s) => s.hash(state),
38            }
39        }
40        self.base_iv.hash(state);
41        for (label, value) in &self.params {
42            match label {
43                Label::Int(i) => i.hash(state),
44                Label::Text(s) => s.hash(state),
45            }
46            hash_value(value, state);
47        }
48    }
49}
50
51// SAFETY: so far no float has been IANA registered (could be for private use though). So it's kinda fine to do this.
52impl Eq for CoseKey {}
53
54fn hash_value<H: std::hash::Hasher>(value: &Value, state: &mut H) {
55    use std::hash::Hash as _;
56    match value {
57        Value::Integer(i) => {
58            let _ = i64::try_from(*i).inspect(|i| i.hash(state));
59        }
60        Value::Bytes(b) => {
61            b.hash(state);
62        }
63        Value::Float(f) => f.to_be_bytes().hash(state),
64        Value::Text(s) => s.hash(state),
65        Value::Bool(b) => b.hash(state),
66        Value::Tag(tag, v) => {
67            tag.hash(state);
68            hash_value(v, state);
69        }
70        Value::Array(array) => {
71            for e in array {
72                hash_value(e, state);
73            }
74        }
75        Value::Map(map) => {
76            for (k, v) in map {
77                hash_value(k, state);
78                hash_value(v, state);
79            }
80        }
81        _ => {}
82    };
83}
84
85/// Accessors
86impl CoseKey {
87    pub fn into_inner(self) -> coset::CoseKey {
88        self.0
89    }
90
91    pub fn alg(&self) -> Option<iana::Algorithm> {
92        self.alg.as_ref().and_then(|a| match a {
93            Algorithm::Assigned(i) => iana::Algorithm::from_i64(i.to_i64()),
94            _ => None,
95        })
96    }
97
98    pub fn crv(&self) -> Option<iana::EllipticCurve> {
99        self.params
100            .iter()
101            .find_map(|(k, v)| {
102                matches!(k, Label::Int(i) if *i == iana::OkpKeyParameter::Crv.to_i64()).then_some(v)
103            })
104            .and_then(Value::as_integer)
105            .and_then(|i| i64::try_from(i).ok())
106            .and_then(iana::EllipticCurve::from_i64)
107    }
108}
109
110impl std::ops::Deref for CoseKey {
111    type Target = coset::CoseKey;
112
113    fn deref(&self) -> &Self::Target {
114        &self.0
115    }
116}
117
118impl From<coset::CoseKey> for CoseKey {
119    fn from(k: coset::CoseKey) -> Self {
120        Self(k)
121    }
122}
123
124impl From<CoseKey> for coset::CoseKey {
125    fn from(k: CoseKey) -> Self {
126        k.0
127    }
128}
129
130pub trait CoseKeyExt {
131    fn alg() -> iana::Algorithm;
132}
133
134pub trait EcdsaCoseKeyExt: CoseKeyExt {
135    fn crv() -> iana::EllipticCurve;
136}