1- use std:: {
2- collections:: { BTreeMap , HashMap } ,
3- time:: Duration ,
4- } ;
1+ use std:: { collections:: HashMap , time:: Duration } ;
52
63use ctap_types:: ctap2:: credential_management:: CredentialProtectionPolicy as Ctap2CredentialProtectionPolicy ;
74use serde:: { Deserialize , Serialize } ;
8- use serde_cbor:: Value ;
95use sha2:: { Digest , Sha256 } ;
106use tracing:: { debug, error, instrument, trace} ;
117
@@ -16,8 +12,9 @@ use crate::{
1612 ctap1:: { Ctap1RegisteredKey , Ctap1Version } ,
1713 ctap2:: {
1814 Ctap2AttestationStatement , Ctap2COSEAlgorithmIdentifier , Ctap2CredentialType ,
19- Ctap2MakeCredentialsResponseExtensions , Ctap2PublicKeyCredentialDescriptor ,
20- Ctap2PublicKeyCredentialRpEntity , Ctap2PublicKeyCredentialUserEntity ,
15+ Ctap2GetAssertionResponseExtensions , Ctap2MakeCredentialsResponseExtensions ,
16+ Ctap2PublicKeyCredentialDescriptor , Ctap2PublicKeyCredentialRpEntity ,
17+ Ctap2PublicKeyCredentialUserEntity ,
2118 } ,
2219 } ,
2320 webauthn:: CtapError ,
@@ -97,7 +94,9 @@ pub struct MakeCredentialRequest {
9794
9895#[ derive( Debug , Default , Clone , Serialize ) ]
9996pub struct PRFValue {
97+ #[ serde( with = "serde_bytes" ) ]
10098 pub first : [ u8 ; 32 ] ,
99+ #[ serde( skip_serializing_if = "Option::is_none" , with = "serde_bytes" ) ]
101100 pub second : Option < [ u8 ; 32 ] > ,
102101}
103102
@@ -243,17 +242,10 @@ pub enum GetAssertionHmacOrPrfInput {
243242 } ,
244243}
245244
246- #[ derive( Debug , Default , Clone ) ]
247- pub enum GetAssertionHmacOrPrfOutput {
248- #[ default]
249- None ,
250- HmacGetSecret ( HMACGetSecretOutput ) ,
251- Prf {
252- enabled : bool ,
253- // The spec tells us this should be a Vec<PRFValue>, but doesn't
254- // explain how it could hold more than 1 value
255- result : PRFValue ,
256- } ,
245+ #[ derive( Debug , Default , Clone , Serialize ) ]
246+ pub struct GetAssertionPrfOutput {
247+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
248+ pub results : Option < PRFValue > ,
257249}
258250
259251#[ derive( Clone , Debug , Default , Eq , PartialEq ) ]
@@ -271,6 +263,15 @@ pub enum GetAssertionLargeBlobExtension {
271263 // Write(Vec<u8>),
272264}
273265
266+ #[ derive( Debug , Default , Clone , PartialEq , Eq , Serialize ) ]
267+ pub struct GetAssertionLargeBlobExtensionOutput {
268+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
269+ pub blob : Option < Vec < u8 > > ,
270+ // Not yet supported
271+ // #[serde(skip_serializing_if = "Option::is_none")]
272+ // pub written: Option<bool>,
273+ }
274+
274275#[ derive( Debug , Default , Clone ) ]
275276pub struct GetAssertionRequestExtensions {
276277 pub cred_blob : Option < bool > ,
@@ -286,7 +287,7 @@ pub struct HMACGetSecretOutput {
286287 pub output2 : Option < [ u8 ; 32 ] > ,
287288}
288289
289- #[ derive( Clone , Debug , Default , Deserialize ) ]
290+ #[ derive( Clone , Debug , Default , Serialize , Deserialize ) ]
290291#[ serde( transparent) ]
291292pub struct Ctap2HMACGetSecretOutput {
292293 // We get this from the device, but have to decrypt it, and
@@ -297,7 +298,7 @@ pub struct Ctap2HMACGetSecretOutput {
297298
298299impl Ctap2HMACGetSecretOutput {
299300 pub ( crate ) fn decrypt_output (
300- self ,
301+ & self ,
301302 shared_secret : & [ u8 ] ,
302303 uv_proto : & Box < dyn PinUvAuthProtocol > ,
303304 ) -> Option < HMACGetSecretOutput > {
@@ -313,7 +314,7 @@ impl Ctap2HMACGetSecretOutput {
313314 res. output1 . copy_from_slice ( & output) ;
314315 } else if output. len ( ) == 64 {
315316 let ( o1, o2) = output. split_at ( 32 ) ;
316- res. output1 . copy_from_slice ( & o1) ;
317+ res. output1 . copy_from_slice ( o1) ;
317318 res. output2 = Some ( o2. try_into ( ) . unwrap ( ) ) ;
318319 } else {
319320 error ! ( "Failed to split HMAC Secret outputs. Unexpected output length: {}. Skipping HMAC extension" , output. len( ) ) ;
@@ -324,11 +325,17 @@ impl Ctap2HMACGetSecretOutput {
324325 }
325326}
326327
327- #[ derive( Debug , Default , Clone ) ]
328- pub struct GetAssertionResponseExtensions {
329- // Stored credBlob
330- pub cred_blob : Option < Vec < u8 > > ,
331- pub hmac_or_prf : GetAssertionHmacOrPrfOutput ,
328+ pub type GetAssertionResponseExtensions = Ctap2GetAssertionResponseExtensions ;
329+
330+ #[ derive( Debug , Default , Clone , Serialize ) ]
331+ #[ serde( rename_all = "camelCase" ) ]
332+ pub struct GetAssertionResponseUnsignedExtensions {
333+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
334+ pub hmac_get_secret : Option < HMACGetSecretOutput > ,
335+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
336+ pub large_blob : Option < GetAssertionLargeBlobExtensionOutput > ,
337+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
338+ pub prf : Option < GetAssertionPrfOutput > ,
332339}
333340
334341#[ derive( Debug , Clone ) ]
@@ -345,7 +352,7 @@ pub struct Assertion {
345352 pub credentials_count : Option < u32 > ,
346353 pub user_selected : Option < bool > ,
347354 pub large_blob_key : Option < Vec < u8 > > ,
348- pub unsigned_extension_outputs : Option < BTreeMap < Value , Value > > ,
355+ pub unsigned_extensions_output : Option < GetAssertionResponseUnsignedExtensions > ,
349356 pub enterprise_attestation : Option < bool > ,
350357 pub attestation_statement : Option < Ctap2AttestationStatement > ,
351358}
0 commit comments