bitwarden_crypto/signing/
cose.rs1use coset::{
4 CoseKey, Label, ProtectedHeader, RegisteredLabel,
5 iana::{EllipticCurve, EnumI64, OkpKeyParameter},
6};
7
8use super::SigningNamespace;
9use crate::{
10 CryptoError, KEY_ID_SIZE,
11 cose::SIGNING_NAMESPACE,
12 error::{EncodingError, SignatureError},
13 keys::KeyId,
14};
15
16pub(super) fn namespace(
19 protected_header: &ProtectedHeader,
20) -> Result<SigningNamespace, CryptoError> {
21 let namespace = protected_header
22 .header
23 .rest
24 .iter()
25 .find_map(|(key, value)| {
26 if let Label::Int(key) = key {
27 if *key == SIGNING_NAMESPACE {
28 return value.as_integer();
29 }
30 }
31 None
32 })
33 .ok_or(SignatureError::InvalidNamespace)?;
34
35 SigningNamespace::try_from(i128::from(namespace))
36}
37
38pub(super) fn content_type(
42 protected_header: &ProtectedHeader,
43) -> Result<coset::iana::CoapContentFormat, CryptoError> {
44 protected_header
45 .header
46 .content_type
47 .as_ref()
48 .and_then(|ct| match ct {
49 RegisteredLabel::Assigned(content_format) => Some(*content_format),
50 _ => None,
51 })
52 .ok_or_else(|| SignatureError::InvalidSignature.into())
53}
54
55pub(super) fn key_id(cose_key: &CoseKey) -> Result<KeyId, EncodingError> {
58 let key_id: [u8; KEY_ID_SIZE] = cose_key
59 .key_id
60 .as_slice()
61 .try_into()
62 .map_err(|_| EncodingError::InvalidValue("key id length"))?;
63 let key_id: KeyId = key_id.into();
64 Ok(key_id)
65}
66
67pub(super) fn ed25519_signing_key(
69 cose_key: &CoseKey,
70) -> Result<ed25519_dalek::SigningKey, EncodingError> {
71 let d = okp_d(cose_key)?;
73 let crv = okp_curve(cose_key)?;
74 if crv == EllipticCurve::Ed25519.to_i64().into() {
75 Ok(ed25519_dalek::SigningKey::from_bytes(
76 d.try_into()
77 .map_err(|_| EncodingError::InvalidCoseEncoding)?,
78 ))
79 } else {
80 Err(EncodingError::UnsupportedValue("OKP curve"))
81 }
82}
83
84pub(super) fn ed25519_verifying_key(
86 cose_key: &CoseKey,
87) -> Result<ed25519_dalek::VerifyingKey, EncodingError> {
88 let x = okp_x(cose_key)?;
90 let crv = okp_curve(cose_key)?;
91 if crv == EllipticCurve::Ed25519.to_i64().into() {
92 ed25519_dalek::VerifyingKey::from_bytes(
93 x.try_into()
94 .map_err(|_| EncodingError::InvalidValue("ed25519 OKP verifying key"))?,
95 )
96 .map_err(|_| EncodingError::InvalidValue("ed25519 OKP verifying key"))
97 } else {
98 Err(EncodingError::UnsupportedValue("OKP curve"))
99 }
100}
101
102fn okp_d(cose_key: &CoseKey) -> Result<&[u8], EncodingError> {
104 cose_key
106 .params
107 .iter()
108 .find_map(|(key, value)| match key {
109 Label::Int(i) if OkpKeyParameter::from_i64(*i) == Some(OkpKeyParameter::D) => {
110 value.as_bytes().map(|v| v.as_slice())
111 }
112 _ => None,
113 })
114 .ok_or(EncodingError::MissingValue("OKP private key"))
115}
116
117fn okp_x(cose_key: &CoseKey) -> Result<&[u8], EncodingError> {
119 cose_key
121 .params
122 .iter()
123 .find_map(|(key, value)| match key {
124 Label::Int(i) if OkpKeyParameter::from_i64(*i) == Some(OkpKeyParameter::X) => {
125 value.as_bytes().map(|v| v.as_slice())
126 }
127 _ => None,
128 })
129 .ok_or(EncodingError::MissingValue("OKP public key"))
130}
131
132fn okp_curve(cose_key: &CoseKey) -> Result<i128, EncodingError> {
134 cose_key
136 .params
137 .iter()
138 .find_map(|(key, value)| match key {
139 Label::Int(i) if OkpKeyParameter::from_i64(*i) == Some(OkpKeyParameter::Crv) => {
140 value.as_integer().map(i128::from)
141 }
142 _ => None,
143 })
144 .ok_or(EncodingError::MissingValue("OKP curve"))
145}