fido_authenticator/
ctap1.rs1use ctap_types::ctap1::{authenticate, register, Authenticator, ControlByte, Error, Result};
4use heapless_bytes::Bytes;
5use serde_bytes::ByteArray;
6
7use trussed_core::{
8 syscall,
9 types::{KeySerialization, Location, Mechanism, SignatureSerialization},
10};
11
12use crate::{
13 constants,
14 credential::{self, Credential, Key, StrippedCredential},
15 SigningAlgorithm, TrussedRequirements, UserPresence,
16};
17
18type Commitment = Bytes<324>;
19
20impl<UP: UserPresence, T: TrussedRequirements> Authenticator for crate::Authenticator<UP, T> {
27 fn register(&mut self, reg: ®ister::Request) -> Result<register::Response> {
36 self.up
37 .user_present(&mut self.trussed, constants::U2F_UP_TIMEOUT)
38 .map_err(|_| Error::ConditionsOfUseNotSatisfied)?;
39
40 let private_key = syscall!(self.trussed.generate_p256_private_key(Location::Volatile)).key;
42 let public_key = syscall!(self
43 .trussed
44 .derive_p256_public_key(private_key, Location::Volatile))
45 .key;
46
47 let serialized_cose_public_key = syscall!(self
48 .trussed
49 .serialize_p256_key(public_key, KeySerialization::EcdhEsHkdf256))
50 .serialized_key;
51 syscall!(self.trussed.delete(public_key));
52 let cose_key: cosey::EcdhEsHkdf256PublicKey =
53 cbor_smol::cbor_deserialize(&serialized_cose_public_key).unwrap();
54
55 let wrapping_key = self
56 .state
57 .persistent
58 .key_wrapping_key(&mut self.trussed)
59 .map_err(|_| Error::UnspecifiedCheckingError)?;
60 let wrapped_key =
63 syscall!(self
64 .trussed
65 .wrap_key_chacha8poly1305(wrapping_key, private_key, &[], None))
66 .wrapped_key;
67 syscall!(self.trussed.delete(private_key));
70
71 let key = Key::WrappedKey(
72 Bytes::try_from(&*wrapped_key).map_err(|_| Error::UnspecifiedCheckingError)?,
73 );
74 let nonce = ByteArray::new(self.nonce());
75
76 let credential = StrippedCredential {
77 ctap: credential::CtapVersion::U2fV2,
78 creation_time: self
79 .state
80 .persistent
81 .timestamp(&mut self.trussed)
82 .map_err(|_| Error::NotEnoughMemory)?,
83 use_counter: true,
84 algorithm: SigningAlgorithm::P256 as i32,
85 key,
86 nonce,
87 hmac_secret: None,
88 cred_protect: None,
89 large_blob_key: None,
90 third_party_payment: None,
91 };
92
93 let kek = self
97 .state
98 .persistent
99 .key_encryption_key(&mut self.trussed)
100 .map_err(|_| Error::NotEnoughMemory)?;
101 let credential_id = credential
102 .id(&mut self.trussed, kek, reg.app_id)
103 .map_err(|_| Error::NotEnoughMemory)?;
104
105 let mut commitment = Commitment::new();
106
107 commitment.push(0).unwrap(); commitment.extend_from_slice(reg.app_id).unwrap();
109 commitment.extend_from_slice(reg.challenge).unwrap();
110
111 commitment.extend_from_slice(&credential_id.0).unwrap();
112
113 commitment.push(0x04).unwrap(); commitment.extend_from_slice(&cose_key.x).unwrap();
115 commitment.extend_from_slice(&cose_key.y).unwrap();
116
117 let attestation = self.state.identity.attestation(&mut self.trussed);
118
119 let (signature, cert) = match attestation {
120 (Some((key, cert)), _aaguid) => {
121 info!("aaguid: {}", hex_str!(&_aaguid));
122 (
123 Bytes::try_from(
124 &*syscall!(self.trussed.sign(
125 Mechanism::P256,
126 key,
127 &commitment,
128 SignatureSerialization::Asn1Der
129 ))
130 .signature,
131 )
132 .unwrap(),
133 cert,
134 )
135 }
136 _ => {
137 info!("Not provisioned with attestation key!");
138 return Err(Error::KeyReferenceNotFound);
139 }
140 };
141
142 Ok(register::Response::new(
143 0x05,
144 &cose_key,
145 credential_id.0,
146 signature,
147 cert,
148 ))
149 }
150
151 fn authenticate(&mut self, auth: &authenticate::Request) -> Result<authenticate::Response> {
152 let cred = Credential::try_from_bytes(self, auth.app_id, auth.key_handle);
153
154 let user_presence_byte = match auth.control_byte {
155 ControlByte::CheckOnly => {
156 return if cred.is_ok() {
160 Err(Error::ConditionsOfUseNotSatisfied)
161 } else {
162 Err(Error::IncorrectDataParameter)
163 };
164 }
165 ControlByte::EnforceUserPresenceAndSign => {
166 if !self.skip_up_check() {
167 self.up
168 .user_present(&mut self.trussed, constants::U2F_UP_TIMEOUT)
169 .map_err(|_| Error::ConditionsOfUseNotSatisfied)?;
170 }
171 0x01
172 }
173 ControlByte::DontEnforceUserPresenceAndSign => 0x00,
174 };
175
176 let cred = cred.map_err(|_| Error::IncorrectDataParameter)?;
177
178 let key = match cred.key() {
179 Key::WrappedKey(bytes) => {
180 let wrapping_key = self
181 .state
182 .persistent
183 .key_wrapping_key(&mut self.trussed)
184 .map_err(|_| Error::IncorrectDataParameter)?;
185 let key_result = syscall!(self.trussed.unwrap_key_chacha8poly1305(
186 wrapping_key,
187 bytes,
188 &[],
189 Location::Volatile,
190 ))
191 .key;
192 match key_result {
193 Some(key) => {
194 info!("loaded u2f key!");
195 key
196 }
197 None => {
198 info!("issue with unwrapping credential id key");
199 return Err(Error::IncorrectDataParameter);
200 }
201 }
202 }
203 _ => return Err(Error::IncorrectDataParameter),
204 };
205
206 if cred.algorithm() != -7 {
207 info!("Unexpected mechanism for u2f");
208 return Err(Error::IncorrectDataParameter);
209 }
210
211 let sig_count = self
212 .state
213 .persistent
214 .timestamp(&mut self.trussed)
215 .map_err(|_| Error::UnspecifiedNonpersistentExecutionError)?;
216
217 let mut commitment = Commitment::new();
218
219 commitment.extend_from_slice(auth.app_id).unwrap();
220 commitment.push(user_presence_byte).unwrap();
221 commitment
222 .extend_from_slice(&sig_count.to_be_bytes())
223 .unwrap();
224 commitment.extend_from_slice(auth.challenge).unwrap();
225
226 let signature = Bytes::try_from(
227 &*syscall!(self.trussed.sign(
228 Mechanism::P256,
229 key,
230 &commitment,
231 SignatureSerialization::Asn1Der
232 ))
233 .signature,
234 )
235 .unwrap();
236
237 Ok(authenticate::Response {
238 user_presence: user_presence_byte,
239 count: sig_count,
240 signature,
241 })
242 }
243}