1use crate::crypto::COSEAlgorithm;
2use crate::{errors::AuthenticatorError, AuthenticatorTransports, KeyHandle};
3use serde::de::MapAccess;
4use serde::{
5 de::{Error as SerdeError, Visitor},
6 ser::SerializeMap,
7 Deserialize, Deserializer, Serialize, Serializer,
8};
9use serde_bytes::ByteBuf;
10use sha2::{Digest, Sha256};
11use std::convert::{Into, TryFrom};
12use std::fmt;
13
14#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)]
15pub struct RpIdHash(pub [u8; 32]);
16
17impl fmt::Debug for RpIdHash {
18 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
19 let value = base64::encode_config(&self.0, base64::URL_SAFE_NO_PAD);
20 write!(f, "RpIdHash({})", value)
21 }
22}
23
24impl AsRef<[u8]> for RpIdHash {
25 fn as_ref(&self) -> &[u8] {
26 self.0.as_ref()
27 }
28}
29
30impl RpIdHash {
31 pub fn from(src: &[u8]) -> Result<RpIdHash, AuthenticatorError> {
32 let mut payload = [0u8; 32];
33 if src.len() != payload.len() {
34 Err(AuthenticatorError::InvalidRelyingPartyInput)
35 } else {
36 payload.copy_from_slice(src);
37 Ok(RpIdHash(payload))
38 }
39 }
40}
41
42#[derive(Debug, Serialize, Clone, Default)]
43#[cfg_attr(test, derive(Deserialize))]
44pub struct RelyingParty {
45 pub id: String,
50 #[serde(skip_serializing_if = "Option::is_none")]
51 pub name: Option<String>,
52 #[serde(skip_serializing_if = "Option::is_none")]
53 pub icon: Option<String>,
54}
55
56#[derive(Debug, Clone)]
58pub enum RelyingPartyWrapper {
59 Data(RelyingParty),
60 Hash(RpIdHash),
63}
64
65impl RelyingPartyWrapper {
66 pub fn hash(&self) -> RpIdHash {
67 match *self {
68 RelyingPartyWrapper::Data(ref d) => {
69 let mut hasher = Sha256::new();
70 hasher.update(&d.id);
71
72 let mut output = [0u8; 32];
73 output.copy_from_slice(&hasher.finalize().as_slice());
74
75 RpIdHash(output)
76 }
77 RelyingPartyWrapper::Hash(ref d) => d.clone(),
78 }
79 }
80}
81
82#[derive(Debug, Serialize, Clone, Eq, PartialEq, Deserialize, Default)]
84pub struct User {
85 #[serde(with = "serde_bytes")]
86 pub id: Vec<u8>,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub icon: Option<String>, pub name: Option<String>,
90 #[serde(skip_serializing_if = "Option::is_none", rename = "displayName")]
91 pub display_name: Option<String>,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct PublicKeyCredentialParameters {
96 pub alg: COSEAlgorithm,
97}
98
99impl TryFrom<i32> for PublicKeyCredentialParameters {
100 type Error = AuthenticatorError;
101 fn try_from(arg: i32) -> Result<Self, Self::Error> {
102 let alg = COSEAlgorithm::try_from(arg as i64)?;
103 Ok(PublicKeyCredentialParameters { alg })
104 }
105}
106
107impl Serialize for PublicKeyCredentialParameters {
108 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
109 where
110 S: Serializer,
111 {
112 let mut map = serializer.serialize_map(Some(2))?;
113 map.serialize_entry("alg", &self.alg)?;
114 map.serialize_entry("type", "public-key")?;
115 map.end()
116 }
117}
118
119impl<'de> Deserialize<'de> for PublicKeyCredentialParameters {
120 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
121 where
122 D: Deserializer<'de>,
123 {
124 struct PublicKeyCredentialParametersVisitor;
125
126 impl<'de> Visitor<'de> for PublicKeyCredentialParametersVisitor {
127 type Value = PublicKeyCredentialParameters;
128
129 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
130 formatter.write_str("a map")
131 }
132
133 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
134 where
135 M: MapAccess<'de>,
136 {
137 let mut found_type = false;
138 let mut alg = None;
139 while let Some(key) = map.next_key()? {
140 match key {
141 "alg" => {
142 if alg.is_some() {
143 return Err(SerdeError::duplicate_field("alg"));
144 }
145 alg = Some(map.next_value()?);
146 }
147 "type" => {
148 if found_type {
149 return Err(SerdeError::duplicate_field("type"));
150 }
151
152 let v: &str = map.next_value()?;
153 if v != "public-key" {
154 return Err(SerdeError::custom(format!("invalid value: {}", v)));
155 }
156 found_type = true;
157 }
158 v => {
159 return Err(SerdeError::unknown_field(v, &[]));
160 }
161 }
162 }
163
164 if !found_type {
165 return Err(SerdeError::missing_field("type"));
166 }
167
168 let alg = alg.ok_or(SerdeError::missing_field("alg"))?;
169
170 Ok(PublicKeyCredentialParameters { alg })
171 }
172 }
173
174 deserializer.deserialize_bytes(PublicKeyCredentialParametersVisitor)
175 }
176}
177
178#[derive(Debug, PartialEq, Serialize, Deserialize, Eq, Clone)]
179#[serde(rename_all = "lowercase")]
180pub enum Transport {
181 USB,
182 NFC,
183 BLE,
184 Internal,
185}
186
187impl From<AuthenticatorTransports> for Vec<Transport> {
188 fn from(t: AuthenticatorTransports) -> Self {
189 let mut transports = Vec::new();
190 if t.contains(AuthenticatorTransports::USB) {
191 transports.push(Transport::USB);
192 }
193 if t.contains(AuthenticatorTransports::NFC) {
194 transports.push(Transport::NFC);
195 }
196 if t.contains(AuthenticatorTransports::BLE) {
197 transports.push(Transport::BLE);
198 }
199
200 transports
201 }
202}
203
204#[derive(Debug, Clone, PartialEq, Eq)]
205pub struct PublicKeyCredentialDescriptor {
206 pub id: Vec<u8>,
207 pub transports: Vec<Transport>,
208}
209
210impl Serialize for PublicKeyCredentialDescriptor {
211 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
212 where
213 S: Serializer,
214 {
215 let mut map = serializer.serialize_map(Some(2))?;
219 map.serialize_entry("type", "public-key")?;
221 map.serialize_entry("id", &ByteBuf::from(self.id.clone()))?;
222 map.end()
224 }
225}
226
227impl<'de> Deserialize<'de> for PublicKeyCredentialDescriptor {
228 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
229 where
230 D: Deserializer<'de>,
231 {
232 struct PublicKeyCredentialDescriptorVisitor;
233
234 impl<'de> Visitor<'de> for PublicKeyCredentialDescriptorVisitor {
235 type Value = PublicKeyCredentialDescriptor;
236
237 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
238 formatter.write_str("a map")
239 }
240
241 fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
242 where
243 M: MapAccess<'de>,
244 {
245 let mut found_type = false;
246 let mut id = None;
247 let mut transports = None;
248 while let Some(key) = map.next_key()? {
249 match key {
250 "id" => {
251 if id.is_some() {
252 return Err(SerdeError::duplicate_field("id"));
253 }
254 let id_bytes: ByteBuf = map.next_value()?;
255 id = Some(id_bytes.into_vec());
256 }
257 "transports" => {
258 if transports.is_some() {
259 return Err(SerdeError::duplicate_field("transports"));
260 }
261 transports = Some(map.next_value()?);
262 }
263 "type" => {
264 if found_type {
265 return Err(SerdeError::duplicate_field("type"));
266 }
267 let v: &str = map.next_value()?;
268 if v != "public-key" {
269 return Err(SerdeError::custom(format!("invalid value: {}", v)));
270 }
271 found_type = true;
272 }
273 v => {
274 return Err(SerdeError::unknown_field(v, &[]));
275 }
276 }
277 }
278
279 if !found_type {
280 return Err(SerdeError::missing_field("type"));
281 }
282
283 let id = id.ok_or(SerdeError::missing_field("id"))?;
284 let transports = transports.unwrap_or(Vec::new());
285
286 Ok(PublicKeyCredentialDescriptor { id, transports })
287 }
288 }
289
290 deserializer.deserialize_bytes(PublicKeyCredentialDescriptorVisitor)
291 }
292}
293
294impl From<&KeyHandle> for PublicKeyCredentialDescriptor {
295 fn from(kh: &KeyHandle) -> Self {
296 Self {
297 id: kh.credential.clone(),
298 transports: kh.transports.into(),
299 }
300 }
301}
302
303#[cfg(test)]
304mod test {
305 use super::{
306 COSEAlgorithm, PublicKeyCredentialDescriptor, PublicKeyCredentialParameters, RelyingParty,
307 Transport, User,
308 };
309
310 #[test]
311 fn serialize_rp() {
312 let rp = RelyingParty {
313 id: String::from("Acme"),
314 name: None,
315 icon: None,
316 };
317
318 let payload = ser::to_vec(&rp).unwrap();
319 assert_eq!(
320 &payload,
321 &[
322 0xa1, 0x62, 0x69, 0x64, 0x64, 0x41, 0x63, 0x6d, 0x65
327 ]
328 );
329 }
330
331 #[test]
332 fn serialize_user() {
333 let user = User {
334 id: vec![
335 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30,
336 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30, 0x82,
337 0x01, 0x93, 0x30, 0x82,
338 ],
339 icon: Some(String::from("https://pics.example.com/00/p/aBjjjpqPb.png")),
340 name: Some(String::from("johnpsmith@example.com")),
341 display_name: Some(String::from("John P. Smith")),
342 };
343
344 let payload = ser::to_vec(&user).unwrap();
345 println!("payload = {:?}", payload);
346 assert_eq!(
347 payload,
348 vec![
349 0xa4, 0x62, 0x69, 0x64, 0x58, 0x20, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x64, 0x69, 0x63, 0x6f, 0x6e, 0x78, 0x2b, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x70,
361 0x69, 0x63, 0x73, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x30, 0x2f, 0x70, 0x2f, 0x61, 0x42, 0x6a, 0x6a, 0x6a, 0x70, 0x71, 0x50, 0x62, 0x2e, 0x70, 0x6e, 0x67, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x76, 0x6a, 0x6f, 0x68, 0x6e, 0x70, 0x73, 0x6d, 0x69, 0x74,
370 0x68, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x6b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x6d, 0x4a, 0x6f, 0x68, 0x6e, 0x20, 0x50, 0x2e, 0x20, 0x53, 0x6d, 0x69, 0x74, 0x68, ]
380 );
381 }
382
383 #[test]
384 fn serialize_user_noicon_nodisplayname() {
385 let user = User {
386 id: vec![
387 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30,
388 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30, 0x82,
389 0x01, 0x93, 0x30, 0x82,
390 ],
391 icon: None,
392 name: Some(String::from("johnpsmith@example.com")),
393 display_name: None,
394 };
395
396 let payload = ser::to_vec(&user).unwrap();
397 println!("payload = {:?}", payload);
398 assert_eq!(
399 payload,
400 vec![
401 0xa2, 0x62, 0x69, 0x64, 0x58, 0x20, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x76, 0x6a, 0x6f, 0x68, 0x6e, 0x70, 0x73, 0x6d, 0x69, 0x74,
413 0x68, 0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, ]
417 );
418 }
419
420 use serde_cbor::ser;
421
422 #[test]
423 fn public_key() {
424 let keys = vec![
425 PublicKeyCredentialParameters {
426 alg: COSEAlgorithm::ES256,
427 },
428 PublicKeyCredentialParameters {
429 alg: COSEAlgorithm::RS256,
430 },
431 ];
432
433 let payload = ser::to_vec(&keys);
434 println!("payload = {:?}", payload);
435 let payload = payload.unwrap();
436 assert_eq!(
437 payload,
438 vec![
439 0x82, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x39, 0x01, 0x00, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79 ]
459 );
460 }
461
462 #[test]
463 fn public_key_desc() {
464 let key = PublicKeyCredentialDescriptor {
465 id: vec![
466 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
467 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
468 0x1c, 0x1d, 0x1e, 0x1f,
469 ],
470 transports: vec![Transport::BLE, Transport::USB],
471 };
472
473 let payload = ser::to_vec(&key);
474 println!("payload = {:?}", payload);
475 let payload = payload.unwrap();
476
477 assert_eq!(
478 payload,
479 vec![
480 0xa2, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, 0x2D, 0x6B, 0x65, 0x79, 0x62, 0x69, 0x64, 0x58, 0x20, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e,
496 0x1f, ]
508 );
509 }
510}