Skip to content

Commit ac0476c

Browse files
committed
fix: Serialize WebAuthn authenticator data properly
1 parent a876d3b commit ac0476c

2 files changed

Lines changed: 56 additions & 4 deletions

File tree

libwebauthn/src/fido.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,7 @@ where
9696
// signCount | 4
9797
// attestedCredentialData | variable
9898
// extensions | variable
99-
let mut res = cbor::to_vec(&self.rp_id_hash).map_err(|e| {
100-
error!("Failed to create AuthenticatorData output vec at rp_id_hash: {e:?}");
101-
Error::Platform(e.into())
102-
})?;
99+
let mut res = self.rp_id_hash.to_vec();
103100
res.push(self.flags.bits());
104101
res.write_u32::<BigEndian>(self.signature_count)
105102
.map_err(|e| {
@@ -250,3 +247,56 @@ impl<'de, T: DeserializeOwned> Deserialize<'de> for AuthenticatorData<T> {
250247
deserializer.deserialize_bytes(AuthenticatorDataVisitor(PhantomData))
251248
}
252249
}
250+
251+
#[cfg(test)]
252+
mod tests {
253+
use cosey::{Bytes, Ed25519PublicKey};
254+
255+
use super::{AttestedCredentialData, AuthenticatorData, AuthenticatorDataFlags};
256+
257+
#[test]
258+
fn test_serialize_auth_data() {
259+
// SHA-256 'example.com'
260+
let rp_id_hash = [0xa3, 0x79, 0xa6, 0xf6, 0xee, 0xaf, 0xb9, 0xa5, 0x5e, 0x37, 0x8c, 0x11, 0x80, 0x34, 0xe2, 0x75, 0x1e, 0x68, 0x2f, 0xab, 0x9f, 0x2d, 0x30, 0xab, 0x13, 0xd2, 0x12, 0x55, 0x86, 0xce, 0x19, 0x47,];
261+
let flag_bits = 0b0100_0101;
262+
let flags = AuthenticatorDataFlags::from_bits(flag_bits).unwrap();
263+
let signature_count = 0;
264+
let aaguid = [0x24, 0x38, 0x65, 0x2a, 0xbe, 0x9f, 0xbd, 0x84, 0x81, 0x0a, 0x84, 0x0d, 0x6f, 0xc4, 0x42, 0xa8, ];
265+
let credential_id = vec![0x01, 0x01, 0x03, 0x03, 0x05, 0x05, 0x07, 0x07];
266+
let pub_key_bytes = b"]\"\xff\xc5\x932x(\xd6-:1\xbb}\x8c$7\xf1&\xd4\xb4&\x02\x02\xa3\xd9\xe2\xba1\x1f\xec\xba";
267+
let credential_public_key = cosey::PublicKey::Ed25519Key(Ed25519PublicKey { x: Bytes::from_slice(pub_key_bytes).unwrap() });
268+
/*
269+
* A4 # map(4)
270+
* 01 # unsigned(1) kty
271+
* 01 # unsigned(1) OKP
272+
* 03 # unsigned(3) alg
273+
* 27 # negative(7) EdDSA
274+
* 20 # negative(0) crv
275+
* 06 # unsigned(6) Ed25519
276+
* 21 # negative(1) x
277+
* 58 20 # bytes(32) [bytes, length 32]
278+
* 5D22FFC593327828D62D3A31BB7D8C2437F126D4B4260202A3D9E2BA311FECBA # "]\"\xFFœ2x(\xD6-:1\xBB}\x8C$7\xF1&Դ&\u0002\u0002\xA3\xD9\xE2\xBA1\u001F\xEC\xBA"
279+
*/
280+
let mut cose_bytes = vec![0xa4, 0x01, 0x01, 0x03, 0x27, 0x20, 0x06, 0x21, 0x58, 0x20];
281+
cose_bytes.extend(pub_key_bytes);
282+
let attested_credential = Some(AttestedCredentialData {
283+
aaguid,
284+
credential_id: credential_id.clone(),
285+
credential_public_key,
286+
});
287+
let auth_data: AuthenticatorData<()> = AuthenticatorData {
288+
rp_id_hash,
289+
flags,
290+
signature_count,
291+
attested_credential,
292+
extensions: None,
293+
};
294+
let webauthn_auth_data = auth_data.to_response_bytes().unwrap();
295+
assert_eq!(rp_id_hash, &webauthn_auth_data[..32]);
296+
assert_eq!(flag_bits, webauthn_auth_data[32]);
297+
assert_eq!(u32::to_be_bytes(signature_count), webauthn_auth_data[33..37]);
298+
assert_eq!(aaguid, &webauthn_auth_data[37..37 + 16]);
299+
assert_eq!(&credential_id, &webauthn_auth_data[55..55 + &credential_id.len()]);
300+
assert_eq!(cose_bytes, &webauthn_auth_data[55 + credential_id.len()..]);
301+
}
302+
}

libwebauthn/src/proto/ctap2/protocol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ where
110110
error => return Err(Error::Ctap(error)),
111111
};
112112
let data = unwrap_field!(cbor_response.data);
113+
trace!("MakeCredential: {:?}", data);
113114
let ctap_response = parse_cbor!(Ctap2MakeCredentialResponse, &data);
114115
debug!("CTAP2 MakeCredential successful");
115116
trace!(?ctap_response);
@@ -130,6 +131,7 @@ where
130131
error => return Err(Error::Ctap(error)),
131132
};
132133
let data = unwrap_field!(cbor_response.data);
134+
trace!("GetAssertion: {:?}", data);
133135
let ctap_response = parse_cbor!(Ctap2GetAssertionResponse, &data);
134136
debug!("CTAP2 GetAssertion successful");
135137
trace!(?ctap_response);

0 commit comments

Comments
 (0)