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
51impl 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
85impl 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}