authenticator_ctap2_2021/crypto/
mod.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5use crate::errors::AuthenticatorError;
6use crate::{ctap2::commands::CommandError, transport::errors::HIDError};
7use serde::{
8    de::{Error as SerdeError, MapAccess, Unexpected, Visitor},
9    ser::SerializeMap,
10    Deserialize, Deserializer, Serialize, Serializer,
11};
12use serde_bytes::ByteBuf;
13use serde_cbor::Value;
14use std::convert::TryFrom;
15use std::fmt;
16
17cfg_if::cfg_if! {
18    if #[cfg(feature = "crypto_ring")] {
19        #[path = "ring.rs"]
20        pub mod imp;
21    } else if #[cfg(feature = "crypto_openssl")] {
22        #[path = "openssl.rs"]
23        pub mod imp;
24    } else if #[cfg(feature = "crypto_dummy")] {
25        #[path = "dummy.rs"]
26        pub mod imp;
27    } else {
28        #[path = "nss.rs"]
29        pub mod imp;
30    }
31}
32
33pub(crate) use imp::{authenticate, decrypt, encapsulate, encrypt, serialize_key, BackendError};
34
35/// An ECDSACurve identifier. You probably will never need to alter
36/// or use this value, as it is set inside the Credential for you.
37#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
38pub enum ECDSACurve {
39    // +---------+-------+----------+------------------------------------+
40    // | Name    | Value | Key Type | Description                        |
41    // +---------+-------+----------+------------------------------------+
42    // | P-256   | 1     | EC2      | NIST P-256 also known as secp256r1 |
43    // | P-384   | 2     | EC2      | NIST P-384 also known as secp384r1 |
44    // | P-521   | 3     | EC2      | NIST P-521 also known as secp521r1 |
45    // | X25519  | 4     | OKP      | X25519 for use w/ ECDH only        |
46    // | X448    | 5     | OKP      | X448 for use w/ ECDH only          |
47    // | Ed25519 | 6     | OKP      | Ed25519 for use w/ EdDSA only      |
48    // | Ed448   | 7     | OKP      | Ed448 for use w/ EdDSA only        |
49    // +---------+-------+----------+------------------------------------+
50    /// Identifies this curve as SECP256R1 (X9_62_PRIME256V1 in OpenSSL)
51    SECP256R1 = 1,
52    /// Identifies this curve as SECP384R1
53    SECP384R1 = 2,
54    /// Identifies this curve as SECP521R1
55    SECP521R1 = 3,
56    /// Identifieds this as OKP X25519 for use w/ ECDH only
57    X25519 = 4,
58    /// Identifieds this as OKP X448 for use w/ ECDH only
59    X448 = 5,
60    /// Identifieds this as OKP Ed25519 for use w/ EdDSA only
61    Ed25519 = 6,
62    /// Identifieds this as OKP Ed448 for use w/ EdDSA only
63    Ed448 = 7,
64}
65
66impl TryFrom<u64> for ECDSACurve {
67    type Error = CryptoError;
68    fn try_from(i: u64) -> Result<Self, Self::Error> {
69        match i {
70            1 => Ok(ECDSACurve::SECP256R1),
71            2 => Ok(ECDSACurve::SECP384R1),
72            3 => Ok(ECDSACurve::SECP521R1),
73            4 => Ok(ECDSACurve::X25519),
74            5 => Ok(ECDSACurve::X448),
75            6 => Ok(ECDSACurve::Ed25519),
76            7 => Ok(ECDSACurve::Ed448),
77            _ => Err(CryptoError::UnknownKeyType),
78        }
79    }
80}
81/// A COSE signature algorithm, indicating the type of key and hash type
82/// that should be used.
83/// see: https://www.iana.org/assignments/cose/cose.xhtml#table-algorithms
84#[allow(non_camel_case_types)]
85#[derive(Copy, Clone, Debug, PartialEq, Eq)]
86pub enum COSEAlgorithm {
87    // /// Identifies this key as ECDSA (recommended SECP256R1) with SHA256 hashing
88    // //#[serde(alias = "ECDSA_SHA256")]
89    // ES256 = -7, // recommends curve SECP256R1
90    // /// Identifies this key as ECDSA (recommended SECP384R1) with SHA384 hashing
91    // //#[serde(alias = "ECDSA_SHA384")]
92    // ES384 = -35, // recommends curve SECP384R1
93    // /// Identifies this key as ECDSA (recommended SECP521R1) with SHA512 hashing
94    // //#[serde(alias = "ECDSA_SHA512")]
95    // ES512 = -36, // recommends curve SECP521R1
96    // /// Identifies this key as RS256 aka RSASSA-PKCS1-v1_5 w/ SHA-256
97    // RS256 = -257,
98    // /// Identifies this key as RS384 aka RSASSA-PKCS1-v1_5 w/ SHA-384
99    // RS384 = -258,
100    // /// Identifies this key as RS512 aka RSASSA-PKCS1-v1_5 w/ SHA-512
101    // RS512 = -259,
102    // /// Identifies this key as PS256 aka RSASSA-PSS w/ SHA-256
103    // PS256 = -37,
104    // /// Identifies this key as PS384 aka RSASSA-PSS w/ SHA-384
105    // PS384 = -38,
106    // /// Identifies this key as PS512 aka RSASSA-PSS w/ SHA-512
107    // PS512 = -39,
108    // /// Identifies this key as EdDSA (likely curve ed25519)
109    // EDDSA = -8,
110    // /// Identifies this as an INSECURE RS1 aka RSASSA-PKCS1-v1_5 using SHA-1. This is not
111    // /// used by validators, but can exist in some windows hello tpm's
112    // INSECURE_RS1 = -65535,
113    INSECURE_RS1 = -65535,             //  RSASSA-PKCS1-v1_5 using SHA-1
114    RS512 = -259,                      //    RSASSA-PKCS1-v1_5 using SHA-512
115    RS384 = -258,                      //    RSASSA-PKCS1-v1_5 using SHA-384
116    RS256 = -257,                      //    RSASSA-PKCS1-v1_5 using SHA-256
117    ES256K = -47,                      //     ECDSA using secp256k1 curve and SHA-256
118    HSS_LMS = -46,                     //     HSS/LMS hash-based digital signature
119    SHAKE256 = -45,                    //     SHAKE-256 512-bit Hash Value
120    SHA512 = -44,                      //     SHA-2 512-bit Hash
121    SHA384 = -43,                      //     SHA-2 384-bit Hash
122    RSAES_OAEP_SHA_512 = -42,          //     RSAES-OAEP w/ SHA-512
123    RSAES_OAEP_SHA_256 = -41,          //     RSAES-OAEP w/ SHA-256
124    RSAES_OAEP_RFC_8017_default = -40, //     RSAES-OAEP w/ SHA-1
125    PS512 = -39,                       //     RSASSA-PSS w/ SHA-512
126    PS384 = -38,                       //     RSASSA-PSS w/ SHA-384
127    PS256 = -37,                       //     RSASSA-PSS w/ SHA-256
128    ES512 = -36,                       //     ECDSA w/ SHA-512
129    ES384 = -35,                       //     ECDSA w/ SHA-384
130    ECDH_SS_A256KW = -34,              //     ECDH SS w/ Concat KDF and AES Key Wrap w/ 256-bit key
131    ECDH_SS_A192KW = -33,              //     ECDH SS w/ Concat KDF and AES Key Wrap w/ 192-bit key
132    ECDH_SS_A128KW = -32,              //     ECDH SS w/ Concat KDF and AES Key Wrap w/ 128-bit key
133    ECDH_ES_A256KW = -31,              //     ECDH ES w/ Concat KDF and AES Key Wrap w/ 256-bit key
134    ECDH_ES_A192KW = -30,              //     ECDH ES w/ Concat KDF and AES Key Wrap w/ 192-bit key
135    ECDH_ES_A128KW = -29,              //     ECDH ES w/ Concat KDF and AES Key Wrap w/ 128-bit key
136    ECDH_SS_HKDF512 = -28,             //     ECDH SS w/ HKDF - generate key directly
137    ECDH_SS_HKDF256 = -27,             //     ECDH SS w/ HKDF - generate key directly
138    ECDH_ES_HKDF512 = -26,             //     ECDH ES w/ HKDF - generate key directly
139    ECDH_ES_HKDF256 = -25,             //     ECDH ES w/ HKDF - generate key directly
140    SHAKE128 = -18,                    //     SHAKE-128 256-bit Hash Value
141    SHA512_256 = -17,                  //     SHA-2 512-bit Hash truncated to 256-bits
142    SHA256 = -16,                      //     SHA-2 256-bit Hash
143    SHA256_64 = -15,                   //     SHA-2 256-bit Hash truncated to 64-bits
144    SHA1 = -14,                        //     SHA-1 Hash
145    Direct_HKDF_AES256 = -13,          //     Shared secret w/ AES-MAC 256-bit key
146    Direct_HKDF_AES128 = -12,          //     Shared secret w/ AES-MAC 128-bit key
147    Direct_HKDF_SHA512 = -11,          //     Shared secret w/ HKDF and SHA-512
148    Direct_HKDF_SHA256 = -10,          //     Shared secret w/ HKDF and SHA-256
149    EDDSA = -8,                        //  EdDSA
150    ES256 = -7,                        //  ECDSA w/ SHA-256
151    Direct = -6,                       //  Direct use of CEK
152    A256KW = -5,                       //  AES Key Wrap w/ 256-bit key
153    A192KW = -4,                       //  AES Key Wrap w/ 192-bit key
154    A128KW = -3,                       //  AES Key Wrap w/ 128-bit key
155    A128GCM = 1,                       //   AES-GCM mode w/ 128-bit key, 128-bit tag
156    A192GCM = 2,                       //   AES-GCM mode w/ 192-bit key, 128-bit tag
157    A256GCM = 3,                       //   AES-GCM mode w/ 256-bit key, 128-bit tag
158    HMAC256_64 = 4,                    //   HMAC w/ SHA-256 truncated to 64 bits
159    HMAC256_256 = 5,                   //   HMAC w/ SHA-256
160    HMAC384_384 = 6,                   //   HMAC w/ SHA-384
161    HMAC512_512 = 7,                   //   HMAC w/ SHA-512
162    AES_CCM_16_64_128 = 10,            //  AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce
163    AES_CCM_16_64_256 = 11,            //  AES-CCM mode 256-bit key, 64-bit tag, 13-byte nonce
164    AES_CCM_64_64_128 = 12,            //  AES-CCM mode 128-bit key, 64-bit tag, 7-byte nonce
165    AES_CCM_64_64_256 = 13,            //  AES-CCM mode 256-bit key, 64-bit tag, 7-byte nonce
166    AES_MAC_128_64 = 14,               //  AES-MAC 128-bit key, 64-bit tag
167    AES_MAC_256_64 = 15,               //  AES-MAC 256-bit key, 64-bit tag
168    ChaCha20_Poly1305 = 24,            //  ChaCha20/Poly1305 w/ 256-bit key, 128-bit tag
169    AES_MAC_128_128 = 25,              //  AES-MAC 128-bit key, 128-bit tag
170    AES_MAC_256_128 = 26,              //  AES-MAC 256-bit key, 128-bit tag
171    AES_CCM_16_128_128 = 30,           //  AES-CCM mode 128-bit key, 128-bit tag, 13-byte nonce
172    AES_CCM_16_128_256 = 31,           //  AES-CCM mode 256-bit key, 128-bit tag, 13-byte nonce
173    AES_CCM_64_128_128 = 32,           //  AES-CCM mode 128-bit key, 128-bit tag, 7-byte nonce
174    AES_CCM_64_128_256 = 33,           //  AES-CCM mode 256-bit key, 128-bit tag, 7-byte nonce
175    IV_GENERATION = 34,                //  For doing IV generation for symmetric algorithms.
176}
177
178impl Serialize for COSEAlgorithm {
179    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
180    where
181        S: Serializer,
182    {
183        match *self {
184            COSEAlgorithm::RS512 => serializer.serialize_i16(-259),
185            COSEAlgorithm::RS384 => serializer.serialize_i16(-258),
186            COSEAlgorithm::RS256 => serializer.serialize_i16(-257),
187            COSEAlgorithm::ES256K => serializer.serialize_i8(-47),
188            COSEAlgorithm::HSS_LMS => serializer.serialize_i8(-46),
189            COSEAlgorithm::SHAKE256 => serializer.serialize_i8(-45),
190            COSEAlgorithm::SHA512 => serializer.serialize_i8(-44),
191            COSEAlgorithm::SHA384 => serializer.serialize_i8(-43),
192            COSEAlgorithm::RSAES_OAEP_SHA_512 => serializer.serialize_i8(-42),
193            COSEAlgorithm::RSAES_OAEP_SHA_256 => serializer.serialize_i8(-41),
194            COSEAlgorithm::RSAES_OAEP_RFC_8017_default => serializer.serialize_i8(-40),
195            COSEAlgorithm::PS512 => serializer.serialize_i8(-39),
196            COSEAlgorithm::PS384 => serializer.serialize_i8(-38),
197            COSEAlgorithm::PS256 => serializer.serialize_i8(-37),
198            COSEAlgorithm::ES512 => serializer.serialize_i8(-36),
199            COSEAlgorithm::ES384 => serializer.serialize_i8(-35),
200            COSEAlgorithm::ECDH_SS_A256KW => serializer.serialize_i8(-34),
201            COSEAlgorithm::ECDH_SS_A192KW => serializer.serialize_i8(-33),
202            COSEAlgorithm::ECDH_SS_A128KW => serializer.serialize_i8(-32),
203            COSEAlgorithm::ECDH_ES_A256KW => serializer.serialize_i8(-31),
204            COSEAlgorithm::ECDH_ES_A192KW => serializer.serialize_i8(-30),
205            COSEAlgorithm::ECDH_ES_A128KW => serializer.serialize_i8(-29),
206            COSEAlgorithm::ECDH_SS_HKDF512 => serializer.serialize_i8(-28),
207            COSEAlgorithm::ECDH_SS_HKDF256 => serializer.serialize_i8(-27),
208            COSEAlgorithm::ECDH_ES_HKDF512 => serializer.serialize_i8(-26),
209            COSEAlgorithm::ECDH_ES_HKDF256 => serializer.serialize_i8(-25),
210            COSEAlgorithm::SHAKE128 => serializer.serialize_i8(-18),
211            COSEAlgorithm::SHA512_256 => serializer.serialize_i8(-17),
212            COSEAlgorithm::SHA256 => serializer.serialize_i8(-16),
213            COSEAlgorithm::SHA256_64 => serializer.serialize_i8(-15),
214            COSEAlgorithm::SHA1 => serializer.serialize_i8(-14),
215            COSEAlgorithm::Direct_HKDF_AES256 => serializer.serialize_i8(-13),
216            COSEAlgorithm::Direct_HKDF_AES128 => serializer.serialize_i8(-12),
217            COSEAlgorithm::Direct_HKDF_SHA512 => serializer.serialize_i8(-11),
218            COSEAlgorithm::Direct_HKDF_SHA256 => serializer.serialize_i8(-10),
219            COSEAlgorithm::EDDSA => serializer.serialize_i8(-8),
220            COSEAlgorithm::ES256 => serializer.serialize_i8(-7),
221            COSEAlgorithm::Direct => serializer.serialize_i8(-6),
222            COSEAlgorithm::A256KW => serializer.serialize_i8(-5),
223            COSEAlgorithm::A192KW => serializer.serialize_i8(-4),
224            COSEAlgorithm::A128KW => serializer.serialize_i8(-3),
225            COSEAlgorithm::A128GCM => serializer.serialize_i8(1),
226            COSEAlgorithm::A192GCM => serializer.serialize_i8(2),
227            COSEAlgorithm::A256GCM => serializer.serialize_i8(3),
228            COSEAlgorithm::HMAC256_64 => serializer.serialize_i8(4),
229            COSEAlgorithm::HMAC256_256 => serializer.serialize_i8(5),
230            COSEAlgorithm::HMAC384_384 => serializer.serialize_i8(6),
231            COSEAlgorithm::HMAC512_512 => serializer.serialize_i8(7),
232            COSEAlgorithm::AES_CCM_16_64_128 => serializer.serialize_i8(10),
233            COSEAlgorithm::AES_CCM_16_64_256 => serializer.serialize_i8(11),
234            COSEAlgorithm::AES_CCM_64_64_128 => serializer.serialize_i8(12),
235            COSEAlgorithm::AES_CCM_64_64_256 => serializer.serialize_i8(13),
236            COSEAlgorithm::AES_MAC_128_64 => serializer.serialize_i8(14),
237            COSEAlgorithm::AES_MAC_256_64 => serializer.serialize_i8(15),
238            COSEAlgorithm::ChaCha20_Poly1305 => serializer.serialize_i8(24),
239            COSEAlgorithm::AES_MAC_128_128 => serializer.serialize_i8(25),
240            COSEAlgorithm::AES_MAC_256_128 => serializer.serialize_i8(26),
241            COSEAlgorithm::AES_CCM_16_128_128 => serializer.serialize_i8(30),
242            COSEAlgorithm::AES_CCM_16_128_256 => serializer.serialize_i8(31),
243            COSEAlgorithm::AES_CCM_64_128_128 => serializer.serialize_i8(32),
244            COSEAlgorithm::AES_CCM_64_128_256 => serializer.serialize_i8(33),
245            COSEAlgorithm::IV_GENERATION => serializer.serialize_i8(34),
246            COSEAlgorithm::INSECURE_RS1 => serializer.serialize_i32(-65535),
247        }
248    }
249}
250
251impl<'de> Deserialize<'de> for COSEAlgorithm {
252    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
253    where
254        D: Deserializer<'de>,
255    {
256        struct COSEAlgorithmVisitor;
257
258        impl<'de> Visitor<'de> for COSEAlgorithmVisitor {
259            type Value = COSEAlgorithm;
260
261            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
262                formatter.write_str("a signed integer")
263            }
264
265            fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
266            where
267                E: SerdeError,
268            {
269                COSEAlgorithm::try_from(v).map_err(|_| {
270                    SerdeError::invalid_value(Unexpected::Signed(v), &"valid COSEAlgorithm")
271                })
272            }
273        }
274
275        deserializer.deserialize_any(COSEAlgorithmVisitor)
276    }
277}
278
279impl TryFrom<i64> for COSEAlgorithm {
280    type Error = CryptoError;
281    fn try_from(i: i64) -> Result<Self, Self::Error> {
282        match i {
283            -259 => Ok(COSEAlgorithm::RS512),
284            -258 => Ok(COSEAlgorithm::RS384),
285            -257 => Ok(COSEAlgorithm::RS256),
286            -47 => Ok(COSEAlgorithm::ES256K),
287            -46 => Ok(COSEAlgorithm::HSS_LMS),
288            -45 => Ok(COSEAlgorithm::SHAKE256),
289            -44 => Ok(COSEAlgorithm::SHA512),
290            -43 => Ok(COSEAlgorithm::SHA384),
291            -42 => Ok(COSEAlgorithm::RSAES_OAEP_SHA_512),
292            -41 => Ok(COSEAlgorithm::RSAES_OAEP_SHA_256),
293            -40 => Ok(COSEAlgorithm::RSAES_OAEP_RFC_8017_default),
294            -39 => Ok(COSEAlgorithm::PS512),
295            -38 => Ok(COSEAlgorithm::PS384),
296            -37 => Ok(COSEAlgorithm::PS256),
297            -36 => Ok(COSEAlgorithm::ES512),
298            -35 => Ok(COSEAlgorithm::ES384),
299            -34 => Ok(COSEAlgorithm::ECDH_SS_A256KW),
300            -33 => Ok(COSEAlgorithm::ECDH_SS_A192KW),
301            -32 => Ok(COSEAlgorithm::ECDH_SS_A128KW),
302            -31 => Ok(COSEAlgorithm::ECDH_ES_A256KW),
303            -30 => Ok(COSEAlgorithm::ECDH_ES_A192KW),
304            -29 => Ok(COSEAlgorithm::ECDH_ES_A128KW),
305            -28 => Ok(COSEAlgorithm::ECDH_SS_HKDF512),
306            -27 => Ok(COSEAlgorithm::ECDH_SS_HKDF256),
307            -26 => Ok(COSEAlgorithm::ECDH_ES_HKDF512),
308            -25 => Ok(COSEAlgorithm::ECDH_ES_HKDF256),
309            -18 => Ok(COSEAlgorithm::SHAKE128),
310            -17 => Ok(COSEAlgorithm::SHA512_256),
311            -16 => Ok(COSEAlgorithm::SHA256),
312            -15 => Ok(COSEAlgorithm::SHA256_64),
313            -14 => Ok(COSEAlgorithm::SHA1),
314            -13 => Ok(COSEAlgorithm::Direct_HKDF_AES256),
315            -12 => Ok(COSEAlgorithm::Direct_HKDF_AES128),
316            -11 => Ok(COSEAlgorithm::Direct_HKDF_SHA512),
317            -10 => Ok(COSEAlgorithm::Direct_HKDF_SHA256),
318            -8 => Ok(COSEAlgorithm::EDDSA),
319            -7 => Ok(COSEAlgorithm::ES256),
320            -6 => Ok(COSEAlgorithm::Direct),
321            -5 => Ok(COSEAlgorithm::A256KW),
322            -4 => Ok(COSEAlgorithm::A192KW),
323            -3 => Ok(COSEAlgorithm::A128KW),
324            1 => Ok(COSEAlgorithm::A128GCM),
325            2 => Ok(COSEAlgorithm::A192GCM),
326            3 => Ok(COSEAlgorithm::A256GCM),
327            4 => Ok(COSEAlgorithm::HMAC256_64),
328            5 => Ok(COSEAlgorithm::HMAC256_256),
329            6 => Ok(COSEAlgorithm::HMAC384_384),
330            7 => Ok(COSEAlgorithm::HMAC512_512),
331            10 => Ok(COSEAlgorithm::AES_CCM_16_64_128),
332            11 => Ok(COSEAlgorithm::AES_CCM_16_64_256),
333            12 => Ok(COSEAlgorithm::AES_CCM_64_64_128),
334            13 => Ok(COSEAlgorithm::AES_CCM_64_64_256),
335            14 => Ok(COSEAlgorithm::AES_MAC_128_64),
336            15 => Ok(COSEAlgorithm::AES_MAC_256_64),
337            24 => Ok(COSEAlgorithm::ChaCha20_Poly1305),
338            25 => Ok(COSEAlgorithm::AES_MAC_128_128),
339            26 => Ok(COSEAlgorithm::AES_MAC_256_128),
340            30 => Ok(COSEAlgorithm::AES_CCM_16_128_128),
341            31 => Ok(COSEAlgorithm::AES_CCM_16_128_256),
342            32 => Ok(COSEAlgorithm::AES_CCM_64_128_128),
343            33 => Ok(COSEAlgorithm::AES_CCM_64_128_256),
344            34 => Ok(COSEAlgorithm::IV_GENERATION),
345            -65535 => Ok(COSEAlgorithm::INSECURE_RS1),
346            _ => Err(CryptoError::UnknownAlgorithm),
347        }
348    }
349}
350/// A COSE Elliptic Curve Public Key. This is generally the provided credential
351/// that an authenticator registers, and is used to authenticate the user.
352#[derive(Clone, Debug, PartialEq, Eq)]
353pub struct COSEEC2Key {
354    /// The curve that this key references.
355    pub curve: ECDSACurve,
356    /// The key's public X coordinate.
357    pub x: Vec<u8>,
358    /// The key's public Y coordinate.
359    pub y: Vec<u8>,
360}
361
362/// A Octet Key Pair (OKP).
363/// The other version uses only the x-coordinate as the y-coordinate is
364/// either to be recomputed or not needed for the key agreement operation ('OKP').
365#[derive(Clone, Debug, PartialEq, Eq)]
366pub struct COSEOKPKey {
367    /// The curve that this key references.
368    pub curve: ECDSACurve,
369    /// The key's public X coordinate.
370    pub x: Vec<u8>,
371}
372
373/// A COSE RSA PublicKey. This is a provided credential from a registered
374/// authenticator.
375/// You will likely never need to interact with this value, as it is part of the Credential
376/// API.
377#[derive(Clone, Debug, PartialEq, Eq)]
378pub struct COSERSAKey {
379    /// An RSA modulus
380    pub n: Vec<u8>,
381    /// An RSA exponent
382    pub e: Vec<u8>,
383}
384
385/// A Octet Key Pair (OKP).
386/// The other version uses only the x-coordinate as the y-coordinate is
387/// either to be recomputed or not needed for the key agreement operation ('OKP').
388#[derive(Clone, Debug, PartialEq, Eq)]
389pub struct COSESymmetricKey {
390    /// The key
391    pub key: Vec<u8>,
392}
393
394// https://tools.ietf.org/html/rfc8152#section-13
395#[allow(non_camel_case_types)]
396#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
397#[repr(i64)]
398pub enum COSEKeyTypeId {
399    // Reserved is invalid
400    // Reserved = 0,
401    /// Octet Key Pair
402    OKP = 1,
403    /// Elliptic Curve Keys w/ x- and y-coordinate
404    EC2 = 2,
405    /// RSA
406    RSA = 3,
407    /// Symmetric
408    Symmetric = 4,
409}
410
411impl TryFrom<u64> for COSEKeyTypeId {
412    type Error = CryptoError;
413    fn try_from(i: u64) -> Result<Self, Self::Error> {
414        match i {
415            1 => Ok(COSEKeyTypeId::OKP),
416            2 => Ok(COSEKeyTypeId::EC2),
417            3 => Ok(COSEKeyTypeId::RSA),
418            4 => Ok(COSEKeyTypeId::Symmetric),
419            _ => Err(CryptoError::UnknownKeyType),
420        }
421    }
422}
423
424/// The type of Key contained within a COSE value. You should never need
425/// to alter or change this type.
426#[allow(non_camel_case_types)]
427#[derive(Clone, Debug, PartialEq, Eq)]
428pub enum COSEKeyType {
429    //    +-----------+-------+-----------------------------------------------+
430    //    | Name      | Value | Description                                   |
431    //    +-----------+-------+-----------------------------------------------+
432    //    | OKP       | 1     | Octet Key Pair                                |
433    //    | EC2       | 2     | Elliptic Curve Keys w/ x- and y-coordinate    |
434    //    |           |       | pair                                          |
435    //    | Symmetric | 4     | Symmetric Keys                                |
436    //    | Reserved  | 0     | This value is reserved                        |
437    //    +-----------+-------+-----------------------------------------------+
438    // Reserved, // should always be invalid.
439    /// Identifies this as an Elliptic Curve octet key pair
440    OKP(COSEOKPKey), // Not used here
441    /// Identifies this as an Elliptic Curve EC2 key
442    EC2(COSEEC2Key),
443    /// Identifies this as an RSA key
444    RSA(COSERSAKey), // Not used here
445    /// Identifies this as a Symmetric key
446    Symmetric(COSESymmetricKey), // Not used here
447}
448
449/// A COSE Key as provided by the Authenticator. You should never need
450/// to alter or change these values.
451#[derive(Clone, Debug, PartialEq, Eq)]
452pub struct COSEKey {
453    /// COSE signature algorithm, indicating the type of key and hash type
454    /// that should be used.
455    pub alg: COSEAlgorithm,
456    /// The public key
457    pub key: COSEKeyType,
458}
459
460impl<'de> Deserialize<'de> for COSEKey {
461    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
462    where
463        D: Deserializer<'de>,
464    {
465        struct COSEKeyVisitor;
466
467        impl<'de> Visitor<'de> for COSEKeyVisitor {
468            type Value = COSEKey;
469
470            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
471                formatter.write_str("a map")
472            }
473
474            fn visit_map<M>(self, mut map: M) -> std::result::Result<Self::Value, M::Error>
475            where
476                M: MapAccess<'de>,
477            {
478                let mut curve: Option<ECDSACurve> = None;
479                let mut key_type: Option<COSEKeyTypeId> = None;
480                let mut alg: Option<COSEAlgorithm> = None;
481                let mut x: Option<Vec<u8>> = None;
482                let mut y: Option<Vec<u8>> = None;
483
484                while let Some(key) = map.next_key()? {
485                    trace!("cose key {:?}", key);
486                    match key {
487                        1 => {
488                            if key_type.is_some() {
489                                return Err(SerdeError::duplicate_field("key_type"));
490                            }
491                            let value: u64 = map.next_value()?;
492                            let val = COSEKeyTypeId::try_from(value).map_err(|_| {
493                                SerdeError::custom(format!("unsupported key_type {}", value))
494                            })?;
495                            key_type = Some(val);
496                            // key_type = Some(map.next_value()?);
497                        }
498                        -1 => {
499                            let key_type = key_type.ok_or(SerdeError::missing_field("key_type"))?;
500                            if key_type == COSEKeyTypeId::RSA {
501                                if y.is_some() {
502                                    return Err(SerdeError::duplicate_field("y"));
503                                }
504                                let value: ByteBuf = map.next_value()?;
505                                y = Some(value.to_vec());
506                            } else {
507                                if curve.is_some() {
508                                    return Err(SerdeError::duplicate_field("curve"));
509                                }
510                                let value: u64 = map.next_value()?;
511                                let val = ECDSACurve::try_from(value).map_err(|_| {
512                                    SerdeError::custom(format!("unsupported curve {}", value))
513                                })?;
514                                curve = Some(val);
515                                // curve = Some(map.next_value()?);
516                            }
517                        }
518                        -2 => {
519                            if x.is_some() {
520                                return Err(SerdeError::duplicate_field("x"));
521                            }
522                            let value: ByteBuf = map.next_value()?;
523                            x = Some(value.to_vec());
524                        }
525                        -3 => {
526                            if y.is_some() {
527                                return Err(SerdeError::duplicate_field("y"));
528                            }
529                            let value: ByteBuf = map.next_value()?;
530                            y = Some(value.to_vec());
531                        }
532                        3 => {
533                            if alg.is_some() {
534                                return Err(SerdeError::duplicate_field("alg"));
535                            }
536                            let value: i64 = map.next_value()?;
537                            let val = COSEAlgorithm::try_from(value).map_err(|_| {
538                                SerdeError::custom(format!("unsupported algorithm {}", value))
539                            })?;
540                            alg = Some(val);
541                            // alg = map.next_value()?;
542                        }
543                        _ => {
544                            // This unknown field should raise an error, but
545                            // there is a couple of field I(baloo) do not understand
546                            // yet. I(baloo) chose to ignore silently the
547                            // error instead because of that
548                            let value: Value = map.next_value()?;
549                            trace!("cose unknown value {:?}:{:?}", key, value);
550                        }
551                    };
552                }
553
554                let key_type = key_type.ok_or(SerdeError::missing_field("key_type"))?;
555                let x = x.ok_or(SerdeError::missing_field("x"))?;
556                let alg = alg.ok_or(SerdeError::missing_field("alg"))?;
557
558                let res = match key_type {
559                    COSEKeyTypeId::OKP => {
560                        let curve = curve.ok_or(SerdeError::missing_field("curve"))?;
561                        COSEKeyType::OKP(COSEOKPKey { curve, x })
562                    }
563                    COSEKeyTypeId::EC2 => {
564                        let curve = curve.ok_or(SerdeError::missing_field("curve"))?;
565                        let y = y.ok_or(SerdeError::missing_field("y"))?;
566                        COSEKeyType::EC2(COSEEC2Key { curve, x, y })
567                    }
568                    COSEKeyTypeId::RSA => {
569                        let e = y.ok_or(SerdeError::missing_field("y"))?;
570                        COSEKeyType::RSA(COSERSAKey { e, n: x })
571                    }
572                    COSEKeyTypeId::Symmetric => COSEKeyType::Symmetric(COSESymmetricKey { key: x }),
573                };
574                Ok(COSEKey { alg, key: res })
575            }
576        }
577
578        deserializer.deserialize_bytes(COSEKeyVisitor)
579    }
580}
581
582impl Serialize for COSEKey {
583    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
584    where
585        S: Serializer,
586    {
587        let map_len = match &self.key {
588            COSEKeyType::OKP(_) => 3,
589            COSEKeyType::EC2(_) => 5,
590            COSEKeyType::RSA(_) => 4,
591            COSEKeyType::Symmetric(_) => 3,
592        };
593        let mut map = serializer.serialize_map(Some(map_len))?;
594        match &self.key {
595            COSEKeyType::OKP(key) => {
596                map.serialize_entry(&1, &COSEKeyTypeId::OKP)?;
597                map.serialize_entry(&3, &self.alg)?;
598                map.serialize_entry(&-1, &key.curve)?;
599                map.serialize_entry(&-2, &key.x)?;
600            }
601            COSEKeyType::EC2(key) => {
602                map.serialize_entry(&1, &(COSEKeyTypeId::EC2 as u8))?;
603                map.serialize_entry(&3, &self.alg)?;
604                map.serialize_entry(&-1, &(key.curve as u8))?;
605                map.serialize_entry(&-2, &serde_bytes::Bytes::new(&key.x))?;
606                map.serialize_entry(&-3, &serde_bytes::Bytes::new(&key.y))?;
607            }
608            COSEKeyType::RSA(key) => {
609                map.serialize_entry(&1, &COSEKeyTypeId::RSA)?;
610                map.serialize_entry(&3, &self.alg)?;
611                map.serialize_entry(&-1, &key.n)?;
612                map.serialize_entry(&-2, &key.e)?;
613            }
614            COSEKeyType::Symmetric(key) => {
615                map.serialize_entry(&1, &COSEKeyTypeId::Symmetric)?;
616                map.serialize_entry(&3, &self.alg)?;
617                map.serialize_entry(&-1, &key.key)?;
618            }
619        }
620
621        map.end()
622    }
623}
624
625/// Errors that can be returned from COSE functions.
626#[derive(Debug)]
627pub enum CryptoError {
628    // DecodingFailure,
629    // LibraryFailure,
630    // MalformedInput,
631    // MissingHeader,
632    // UnexpectedHeaderValue,
633    // UnexpectedTag,
634    // UnexpectedType,
635    // Unimplemented,
636    // VerificationFailed,
637    // SigningFailed,
638    // InvalidArgument,
639    UnknownKeyType,
640    UnknownSignatureScheme,
641    UnknownAlgorithm,
642    WrongSaltLength,
643    Backend(BackendError),
644}
645
646impl From<BackendError> for CryptoError {
647    fn from(e: BackendError) -> Self {
648        CryptoError::Backend(e)
649    }
650}
651
652impl From<CryptoError> for CommandError {
653    fn from(e: CryptoError) -> Self {
654        CommandError::Crypto(e)
655    }
656}
657
658impl From<CryptoError> for AuthenticatorError {
659    fn from(e: CryptoError) -> Self {
660        AuthenticatorError::HIDError(HIDError::Command(CommandError::Crypto(e)))
661    }
662}
663
664#[derive(Clone)]
665pub struct ECDHSecret {
666    remote: COSEKey,
667    my: COSEKey,
668    shared_secret: Vec<u8>,
669}
670
671impl ECDHSecret {
672    pub fn my_public_key(&self) -> &COSEKey {
673        &self.my
674    }
675
676    pub fn shared_secret(&self) -> &[u8] {
677        &self.shared_secret
678    }
679}
680
681impl fmt::Debug for ECDHSecret {
682    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
683        write!(
684            f,
685            "ECDHSecret(remote: {:?}, my: {:?})",
686            self.remote,
687            self.my_public_key()
688        )
689    }
690}
691
692#[cfg(all(test, not(feature = "crypto_dummy")))]
693mod test {
694    use super::{
695        authenticate, decrypt, encrypt, imp::parse_key, imp::test_encapsulate, serialize_key,
696        COSEAlgorithm, COSEKey, ECDSACurve,
697    };
698    use crate::crypto::{COSEEC2Key, COSEKeyType};
699    use crate::ctap2::commands::client_pin::Pin;
700    use crate::util::decode_hex;
701    use serde_cbor::de::from_slice;
702
703    #[test]
704    fn test_serialize_key() {
705        let x = [
706            0xfc, 0x9e, 0xd3, 0x6f, 0x7c, 0x1a, 0xa9, 0x15, 0xce, 0x3e, 0xa1, 0x77, 0xf0, 0x75,
707            0x67, 0xf0, 0x7f, 0x16, 0xf9, 0x47, 0x9d, 0x95, 0xad, 0x8e, 0xd4, 0x97, 0x1d, 0x33,
708            0x05, 0xe3, 0x1a, 0x80,
709        ];
710        let y = [
711            0x50, 0xb7, 0x33, 0xaf, 0x8c, 0x0b, 0x0e, 0xe1, 0xda, 0x8d, 0xe0, 0xac, 0xf9, 0xd8,
712            0xe1, 0x32, 0x82, 0xf0, 0x63, 0xb7, 0xb3, 0x0d, 0x73, 0xd4, 0xd3, 0x2c, 0x9a, 0xad,
713            0x6d, 0xfa, 0x8b, 0x27,
714        ];
715        let serialized_key = [
716            0x04, 0xfc, 0x9e, 0xd3, 0x6f, 0x7c, 0x1a, 0xa9, 0x15, 0xce, 0x3e, 0xa1, 0x77, 0xf0,
717            0x75, 0x67, 0xf0, 0x7f, 0x16, 0xf9, 0x47, 0x9d, 0x95, 0xad, 0x8e, 0xd4, 0x97, 0x1d,
718            0x33, 0x05, 0xe3, 0x1a, 0x80, 0x50, 0xb7, 0x33, 0xaf, 0x8c, 0x0b, 0x0e, 0xe1, 0xda,
719            0x8d, 0xe0, 0xac, 0xf9, 0xd8, 0xe1, 0x32, 0x82, 0xf0, 0x63, 0xb7, 0xb3, 0x0d, 0x73,
720            0xd4, 0xd3, 0x2c, 0x9a, 0xad, 0x6d, 0xfa, 0x8b, 0x27,
721        ];
722
723        let (res_x, res_y) =
724            serialize_key(ECDSACurve::SECP256R1, &serialized_key).expect("Failed to serialize key");
725        assert_eq!(res_x, x);
726        assert_eq!(res_y, y);
727
728        let res_key = parse_key(ECDSACurve::SECP256R1, &x, &y).expect("Failed to parse key");
729
730        assert_eq!(res_key, serialized_key)
731    }
732
733    #[test]
734    fn test_parse_es256_serialize_key() {
735        // Test values taken from https://github.com/Yubico/python-fido2/blob/master/test/test_cose.py
736        let key_data = decode_hex("A5010203262001215820A5FD5CE1B1C458C530A54FA61B31BF6B04BE8B97AFDE54DD8CBB69275A8A1BE1225820FA3A3231DD9DEED9D1897BE5A6228C59501E4BCD12975D3DFF730F01278EA61C");
737        let key: COSEKey = from_slice(&key_data).unwrap();
738        assert_eq!(key.alg, COSEAlgorithm::ES256);
739        if let COSEKeyType::EC2(ec2key) = &key.key {
740            assert_eq!(ec2key.curve, ECDSACurve::SECP256R1);
741            assert_eq!(
742                ec2key.x,
743                decode_hex("A5FD5CE1B1C458C530A54FA61B31BF6B04BE8B97AFDE54DD8CBB69275A8A1BE1")
744            );
745            assert_eq!(
746                ec2key.y,
747                decode_hex("FA3A3231DD9DEED9D1897BE5A6228C59501E4BCD12975D3DFF730F01278EA61C")
748            );
749        } else {
750            panic!("Wrong key type!");
751        }
752
753        let serialized = serde_cbor::to_vec(&key).expect("Failed to serialize key");
754        assert_eq!(key_data, serialized);
755    }
756
757    #[test]
758    #[allow(non_snake_case)]
759    fn test_shared_secret() {
760        // Test values taken from https://github.com/Yubico/python-fido2/blob/master/test/test_ctap2.py
761        let EC_PRIV =
762            decode_hex("7452E599FEE739D8A653F6A507343D12D382249108A651402520B72F24FE7684");
763        let EC_PUB_X =
764            decode_hex("44D78D7989B97E62EA993496C9EF6E8FD58B8B00715F9A89153DDD9C4657E47F");
765        let EC_PUB_Y =
766            decode_hex("EC802EE7D22BD4E100F12E48537EB4E7E96ED3A47A0A3BD5F5EEAB65001664F9");
767        let DEV_PUB_X =
768            decode_hex("0501D5BC78DA9252560A26CB08FCC60CBE0B6D3B8E1D1FCEE514FAC0AF675168");
769        let DEV_PUB_Y =
770            decode_hex("D551B3ED46F665731F95B4532939C25D91DB7EB844BD96D4ABD4083785F8DF47");
771        let SHARED = decode_hex("c42a039d548100dfba521e487debcbbb8b66bb7496f8b1862a7a395ed83e1a1c");
772        let TOKEN_ENC = decode_hex("7A9F98E31B77BE90F9C64D12E9635040");
773        let TOKEN = decode_hex("aff12c6dcfbf9df52f7a09211e8865cd");
774        let PIN_HASH_ENC = decode_hex("afe8327ce416da8ee3d057589c2ce1a9");
775
776        // let peer_key = parse_key(ECDSACurve::SECP256R1, &DEV_PUB_X, &DEV_PUB_Y).unwrap();
777        let my_pub_key_data = parse_key(ECDSACurve::SECP256R1, &EC_PUB_X, &EC_PUB_Y).unwrap();
778
779        let peer_key = COSEEC2Key {
780            curve: ECDSACurve::SECP256R1,
781            x: DEV_PUB_X,
782            y: DEV_PUB_Y,
783        };
784
785        // let my_pub_key = COSEKey {
786        //     alg: COSEAlgorithm::ES256,
787        //     key: COSEKeyType::EC2(COSEEC2Key {
788        //         curve: ECDSACurve::SECP256R1,
789        //         x: EC_PUB_X,
790        //         y: EC_PUB_Y,
791        //     }),
792        // };
793        // We are using `test_encapsulate()` here, because we need a way to hand in the private key
794        // which would be generated on the fly otherwise (ephemeral keys), to predict the outputs
795        let shared_secret =
796            test_encapsulate(&peer_key, COSEAlgorithm::ES256, &my_pub_key_data, &EC_PRIV).unwrap();
797        assert_eq!(shared_secret.shared_secret, SHARED);
798
799        let token_enc = encrypt(&shared_secret.shared_secret(), &TOKEN).unwrap();
800        assert_eq!(token_enc, TOKEN_ENC);
801
802        let token = decrypt(&shared_secret.shared_secret(), &TOKEN_ENC).unwrap();
803        assert_eq!(token, TOKEN);
804
805        let pin = Pin::new("1234");
806        let pin_hash_enc =
807            encrypt(&shared_secret.shared_secret(), pin.for_pin_token().as_ref()).unwrap();
808        assert_eq!(pin_hash_enc, PIN_HASH_ENC);
809    }
810
811    #[test]
812    fn test_authenticate() {
813        let key = "key";
814        let message = "The quick brown fox jumps over the lazy dog";
815        let expected =
816            decode_hex("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8");
817
818        let result =
819            authenticate(key.as_bytes(), message.as_bytes()).expect("Failed to authenticate");
820        assert_eq!(result, expected);
821
822        let key = "The quick brown fox jumps over the lazy dogThe quick brown fox jumps over the lazy dog";
823        let message = "message";
824        let expected =
825            decode_hex("5597b93a2843078cbb0c920ae41dfe20f1685e10c67e423c11ab91adfc319d12");
826
827        let result =
828            authenticate(key.as_bytes(), message.as_bytes()).expect("Failed to authenticate");
829        assert_eq!(result, expected);
830    }
831
832    #[test]
833    fn test_pin_encryption_and_hashing() {
834        let pin = "1234";
835
836        let shared_secret = vec![
837            0x82, 0xE3, 0xD8, 0x41, 0xE2, 0x5C, 0x5C, 0x13, 0x46, 0x2C, 0x12, 0x3C, 0xC3, 0xD3,
838            0x98, 0x78, 0x65, 0xBA, 0x3D, 0x20, 0x46, 0x74, 0xFB, 0xED, 0xD4, 0x7E, 0xF5, 0xAB,
839            0xAB, 0x8D, 0x13, 0x72,
840        ];
841        let expected_new_pin_enc = vec![
842            0x70, 0x66, 0x4B, 0xB5, 0x81, 0xE2, 0x57, 0x45, 0x1A, 0x3A, 0xB9, 0x1B, 0xF1, 0xAA,
843            0xD8, 0xE4, 0x5F, 0x6C, 0xE9, 0xB5, 0xC3, 0xB0, 0xF3, 0x2B, 0x5E, 0xCD, 0x62, 0xD0,
844            0xBA, 0x3B, 0x60, 0x5F, 0xD9, 0x18, 0x31, 0x66, 0xF6, 0xC5, 0xFA, 0xF3, 0xE4, 0xDA,
845            0x24, 0x81, 0x50, 0x2C, 0xD0, 0xCE, 0xE0, 0x15, 0x8B, 0x35, 0x1F, 0xC3, 0x92, 0x08,
846            0xA7, 0x7C, 0xB2, 0x74, 0x4B, 0xD4, 0x3C, 0xF9,
847        ];
848        let expected_pin_auth = vec![
849            0x8E, 0x7F, 0x01, 0x69, 0x97, 0xF3, 0xB0, 0xA2, 0x7B, 0xA4, 0x34, 0x7A, 0x0E, 0x49,
850            0xFD, 0xF5,
851        ];
852
853        // Padding to 64 bytes
854        let input: Vec<u8> = pin
855            .as_bytes()
856            .iter()
857            .chain(std::iter::repeat(&0x00))
858            .take(64)
859            .cloned()
860            .collect();
861
862        let new_pin_enc = encrypt(&shared_secret, &input).expect("Failed to encrypt pin");
863        assert_eq!(new_pin_enc, expected_new_pin_enc);
864
865        let pin_auth = authenticate(&shared_secret, &new_pin_enc).expect("Failed to authenticate");
866        assert_eq!(pin_auth[0..16], expected_pin_auth);
867    }
868}