authenticator_ctap2_2021/ctap2/
server.rs

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    // TODO(baloo): spec is wrong !!!!111
46    //              https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html#commands
47    //              in the example "A PublicKeyCredentialRpEntity DOM object defined as follows:"
48    //              inconsistent with https://w3c.github.io/webauthn/#sctn-rp-credential-params
49    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// Note: This enum is provided to make old CTAP1/U2F API work. This should be deprecated at some point
57#[derive(Debug, Clone)]
58pub enum RelyingPartyWrapper {
59    Data(RelyingParty),
60    // CTAP1 hash can be derived from full object, see RelyingParty::hash below,
61    // but very old backends might still provide application IDs.
62    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// TODO(baloo): should we rename this PublicKeyCredentialUserEntity ?
83#[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>, // This has been removed from Webauthn-2
89    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        // TODO(MS): Transports is OPTIONAL, but some older tokens don't understand it
216        //           and return a CBOR-Parsing error. It is only a hint for the token,
217        //           so we'll leave it out for the moment
218        let mut map = serializer.serialize_map(Some(2))?;
219        // let mut map = serializer.serialize_map(Some(3))?;
220        map.serialize_entry("type", "public-key")?;
221        map.serialize_entry("id", &ByteBuf::from(self.id.clone()))?;
222        // map.serialize_entry("transports", &self.transports)?;
223        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, // map(1)
323                0x62, // text(2)
324                0x69, 0x64, // "id"
325                0x64, // text(4)
326                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, // map(4)
350                0x62, // text(2)
351                0x69, 0x64, // "id"
352                0x58, 0x20, // bytes(32)
353                0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, // userid
354                0x02, 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, // ...
355                0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, // ...
356                0x30, 0x82, // ...
357                0x64, // text(4)
358                0x69, 0x63, 0x6f, 0x6e, // "icon"
359                0x78, 0x2b, // text(43)
360                0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x70,
361                0x69, // "https://pics.example.com/00/p/aBjjjpqPb.png"
362                0x63, 0x73, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, // ...
363                0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x30, 0x2f, 0x70, 0x2f, // ...
364                0x61, 0x42, 0x6a, 0x6a, 0x6a, 0x70, 0x71, 0x50, 0x62, 0x2e, // ...
365                0x70, 0x6e, 0x67, // ...
366                0x64, // text(4)
367                0x6e, 0x61, 0x6d, 0x65, // "name"
368                0x76, // text(22)
369                0x6a, 0x6f, 0x68, 0x6e, 0x70, 0x73, 0x6d, 0x69, 0x74,
370                0x68, // "johnpsmith@example.com"
371                0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, // ...
372                0x6f, 0x6d, // ...
373                0x6b, // text(11)
374                0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, // "displayName"
375                0x65, // ...
376                0x6d, // text(13)
377                0x4a, 0x6f, 0x68, 0x6e, 0x20, 0x50, 0x2e, 0x20, 0x53, 0x6d, // "John P. Smith"
378                0x69, 0x74, 0x68, // ...
379            ]
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, // map(2)
402                0x62, // text(2)
403                0x69, 0x64, // "id"
404                0x58, 0x20, // bytes(32)
405                0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, 0x38, 0xa0, 0x03, // userid
406                0x02, 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, 0x30, 0x82, 0x01, // ...
407                0x38, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x30, 0x82, 0x01, 0x93, // ...
408                0x30, 0x82, // ...
409                0x64, // text(4)
410                0x6e, 0x61, 0x6d, 0x65, // "name"
411                0x76, // text(22)
412                0x6a, 0x6f, 0x68, 0x6e, 0x70, 0x73, 0x6d, 0x69, 0x74,
413                0x68, // "johnpsmith@example.com"
414                0x40, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, // ...
415                0x6f, 0x6d, // ...
416            ]
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, // array(2)
440                0xa2, // map(2)
441                0x63, // text(3)
442                0x61, 0x6c, 0x67, // "alg"
443                0x26, // -7 (ES256)
444                0x64, // text(4)
445                0x74, 0x79, 0x70, 0x65, // "type"
446                0x6a, // text(10)
447                0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, // "public-key"
448                0x2D, 0x6B, 0x65, 0x79, // ...
449                0xa2, // map(2)
450                0x63, // text(3)
451                0x61, 0x6c, 0x67, // "alg"
452                0x39, 0x01, 0x00, // -257 (RS256)
453                0x64, // text(4)
454                0x74, 0x79, 0x70, 0x65, // "type"
455                0x6a, // text(10)
456                0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, // "public-key"
457                0x2D, 0x6B, 0x65, 0x79 // ...
458            ]
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                // 0xa3, // map(3)
481                0xa2, // map(2)
482                0x64, // text(4)
483                0x74, 0x79, 0x70, 0x65, // "type"
484                0x6a, // text(10)
485                0x70, 0x75, 0x62, 0x6C, 0x69, 0x63, // "public-key"
486                0x2D, 0x6B, 0x65, 0x79, // ...
487                0x62, // text(2)
488                0x69, 0x64, // "id"
489                0x58, 0x20, // bytes(32)
490                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, // key id
491                0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, // ...
492                0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, // ...
493                0x12, 0x13, 0x14, 0x15, 0x16, 0x17, // ...
494                0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, // ...
495                0x1e,
496                0x1f, // ...
497
498                      // Deactivated for now
499                      //0x6a, // text(10)
500                      //0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, // "transports"
501                      //0x6f, 0x72, 0x74, 0x73, // ...
502                      //0x82, // array(2)
503                      //0x63, // text(3)
504                      //0x62, 0x6c, 0x65, // "ble"
505                      //0x63, // text(3)
506                      //0x75, 0x73, 0x62 // "usb"
507            ]
508        );
509    }
510}