From 681a059aa8eef5f5d79ed7f280eaf69287298cc2 Mon Sep 17 00:00:00 2001 From: Adam Velebil Date: Mon, 25 Nov 2024 08:53:46 +0100 Subject: [PATCH] replace WithExtensionResults<> with Pair<> --- .../fido/client/BasicWebAuthnClient.java | 62 +++++++------------ .../client/MultipleAssertionsAvailable.java | 25 +++++--- 2 files changed, 38 insertions(+), 49 deletions(-) diff --git a/fido/src/main/java/com/yubico/yubikit/fido/client/BasicWebAuthnClient.java b/fido/src/main/java/com/yubico/yubikit/fido/client/BasicWebAuthnClient.java index bbeb3536..313047d5 100644 --- a/fido/src/main/java/com/yubico/yubikit/fido/client/BasicWebAuthnClient.java +++ b/fido/src/main/java/com/yubico/yubikit/fido/client/BasicWebAuthnClient.java @@ -21,6 +21,7 @@ import com.yubico.yubikit.core.application.CommandException; import com.yubico.yubikit.core.application.CommandState; import com.yubico.yubikit.core.fido.CtapException; +import com.yubico.yubikit.core.util.Pair; import com.yubico.yubikit.fido.client.extensions.CredBlobExtension; import com.yubico.yubikit.fido.client.extensions.CredPropsExtension; import com.yubico.yubikit.fido.client.extensions.CredProtectExtension; @@ -226,7 +227,7 @@ public PublicKeyCredential makeCredential( byte[] clientDataHash = Utils.hash(clientDataJson); try { - WithExtensionResults result = ctapMakeCredential( + Pair result = ctapMakeCredential( clientDataHash, options, effectiveDomain, @@ -234,8 +235,10 @@ public PublicKeyCredential makeCredential( enterpriseAttestation, state ); + final Ctap2Session.CredentialData credential = result.first; + final ClientExtensionResults clientExtensionResults = result.second; - final AttestationObject attestationObject = AttestationObject.fromCredential(result.data); + final AttestationObject attestationObject = AttestationObject.fromCredential(credential); AuthenticatorAttestationResponse response = new AuthenticatorAttestationResponse( clientDataJson, @@ -247,7 +250,7 @@ public PublicKeyCredential makeCredential( Objects.requireNonNull(attestationObject.getAuthenticatorData() .getAttestedCredentialData()).getCredentialId(), response, - result.clientExtensionResults); + clientExtensionResults); } catch (CtapException e) { if (e.getCtapError() == CtapException.ERR_PIN_INVALID) { throw new PinInvalidClientError(e, clientPin.getPinRetries().getCount()); @@ -282,7 +285,7 @@ public PublicKeyCredential getAssertion( ) throws MultipleAssertionsAvailable, IOException, CommandException, ClientError { byte[] clientDataHash = Utils.hash(clientDataJson); try { - final List> assertions = ctapGetAssertions( + final List> results = ctapGetAssertions( clientDataHash, options, effectiveDomain, @@ -294,18 +297,17 @@ public PublicKeyCredential getAssertion( options.getAllowCredentials() ); - if (assertions.size() == 1) { - final WithExtensionResults first = assertions.get(0); - final Ctap2Session.AssertionData assertionData = first.data; - final ClientExtensionResults clientExtensionResults = first.clientExtensionResults; + if (results.size() == 1) { + final Ctap2Session.AssertionData assertion = results.get(0).first; + final ClientExtensionResults clientExtensionResults = results.get(0).second; return PublicKeyCredential.fromAssertion( - assertionData, + assertion, clientDataJson, allowCredentials, clientExtensionResults); } else { - throw new MultipleAssertionsAvailable(clientDataJson, assertions); + throw new MultipleAssertionsAvailable(clientDataJson, results); } } catch (CtapException e) { @@ -418,24 +420,6 @@ public CredentialManager getCredentialManager(char[] pin) } } - protected static class WithExtensionResults { - final T data; - final ClientExtensionResults clientExtensionResults; - - WithExtensionResults(T data, ClientExtensionResults clientExtensionResults) { - this.data = data; - this.clientExtensionResults = clientExtensionResults; - } - - T getData() { - return data; - } - - ClientExtensionResults getClientExtensionResults() { - return clientExtensionResults; - } - } - /** * Create a new WebAuthn credential. *

@@ -449,13 +433,13 @@ ClientExtensionResults getClientExtensionResults() { * @param effectiveDomain The effective domain for the request, which is used to validate the RP ID against. * @param pin If needed, the PIN to authorize the credential creation. * @param state If needed, the state to provide control over the ongoing operation - * @return A WebAuthn public key credential. + * @return A pair of credential data and client extension results. * @throws IOException A communication error in the transport layer * @throws CommandException A communication in the protocol layer * @throws ClientError A higher level error */ @SuppressWarnings("unchecked") - protected WithExtensionResults ctapMakeCredential( + protected Pair ctapMakeCredential( byte[] clientDataHash, PublicKeyCredentialCreationOptions options, String effectiveDomain, @@ -555,12 +539,12 @@ protected WithExtensionResults ctapMakeCredential( state ); - ClientExtensionResults results = new ClientExtensionResults(); + ClientExtensionResults clientExtensionResults = new ClientExtensionResults(); for (Extension.RegistrationProcessor processor : registrationProcessors) { AttestationObject attestationObject = AttestationObject.fromCredential(credentialData); - results.add(processor.getOutput(attestationObject, authParams.pinToken)); + clientExtensionResults.add(processor.getOutput(attestationObject, authParams.pinToken)); } - return new WithExtensionResults<>(credentialData, results); + return new Pair<>(credentialData, clientExtensionResults); } /** @@ -578,12 +562,12 @@ protected WithExtensionResults ctapMakeCredential( * @param effectiveDomain The effective domain for the request, which is used to validate the RP ID against. * @param pin If needed, the PIN to authorize the credential creation. * @param state If needed, the state to provide control over the ongoing operation - * @return Webauthn public key credential with assertion response data. + * @return List of pairs containing assertion response data and client extension results. * @throws IOException A communication error in the transport layer * @throws CommandException A communication in the protocol layer * @throws ClientError A higher level error */ - protected List> ctapGetAssertions( + protected List> ctapGetAssertions( byte[] clientDataHash, PublicKeyCredentialRequestOptions options, String effectiveDomain, @@ -650,13 +634,13 @@ protected List> ctapGetAssertio state ); - List> result = new ArrayList<>(); + List> result = new ArrayList<>(); for(final Ctap2Session.AssertionData assertionData : assertions) { - ClientExtensionResults results = new ClientExtensionResults(); + ClientExtensionResults clientExtensionResults = new ClientExtensionResults(); for (Extension.AuthenticationProcessor processor : authenticationProcessors) { - results.add(processor.getOutput(assertionData, authParams.pinToken)); + clientExtensionResults.add(processor.getOutput(assertionData, authParams.pinToken)); } - result.add(new WithExtensionResults<>(assertionData, results)); + result.add(new Pair<>(assertionData, clientExtensionResults)); } return result; diff --git a/fido/src/main/java/com/yubico/yubikit/fido/client/MultipleAssertionsAvailable.java b/fido/src/main/java/com/yubico/yubikit/fido/client/MultipleAssertionsAvailable.java index 6a6f84ca..ad510fe3 100755 --- a/fido/src/main/java/com/yubico/yubikit/fido/client/MultipleAssertionsAvailable.java +++ b/fido/src/main/java/com/yubico/yubikit/fido/client/MultipleAssertionsAvailable.java @@ -16,8 +16,10 @@ package com.yubico.yubikit.fido.client; +import com.yubico.yubikit.core.util.Pair; import com.yubico.yubikit.fido.ctap.Ctap2Session; import com.yubico.yubikit.fido.webauthn.AuthenticatorAssertionResponse; +import com.yubico.yubikit.fido.webauthn.ClientExtensionResults; import com.yubico.yubikit.fido.webauthn.PublicKeyCredential; import com.yubico.yubikit.fido.webauthn.PublicKeyCredentialDescriptor; import com.yubico.yubikit.fido.webauthn.PublicKeyCredentialUserEntity; @@ -34,9 +36,9 @@ */ public class MultipleAssertionsAvailable extends Throwable { private final byte[] clientDataJson; - private final List> assertions; + private final List> assertions; - MultipleAssertionsAvailable(byte[] clientDataJson, List> assertions) { + MultipleAssertionsAvailable(byte[] clientDataJson, List> assertions) { super("Request returned multiple assertions"); this.clientDataJson = clientDataJson; @@ -65,8 +67,8 @@ public int getAssertionCount() { */ public List getUsers() throws UserInformationNotAvailableError { List users = new ArrayList<>(); - for (BasicWebAuthnClient.WithExtensionResults assertion : assertions) { - Map user = assertion.data.getUser(); + for (Pair assertion : assertions) { + Map user = assertion.first.getUser(); if (user == null) { throw new UserInformationNotAvailableError(); } @@ -87,20 +89,23 @@ public PublicKeyCredential select(int index) { if (assertions.isEmpty()) { throw new IllegalStateException("Assertion has already been selected"); } - BasicWebAuthnClient.WithExtensionResults assertion = assertions.get(index); + Pair assertionPair = assertions.get(index); assertions.clear(); - final Map user = Objects.requireNonNull(assertion.data.getUser()); - final Map credential = Objects.requireNonNull(assertion.data.getCredential()); + final Ctap2Session.AssertionData assertion = assertionPair.first; + final ClientExtensionResults clientExtensionResults = assertionPair.second; + + final Map user = Objects.requireNonNull(assertion.getUser()); + final Map credential = Objects.requireNonNull(assertion.getCredential()); final byte[] credentialId = Objects.requireNonNull((byte[]) credential.get(PublicKeyCredentialDescriptor.ID)); return new PublicKeyCredential( credentialId, new AuthenticatorAssertionResponse( clientDataJson, - assertion.data.getAuthenticatorData(), - assertion.data.getSignature(), + assertion.getAuthenticatorData(), + assertion.getSignature(), Objects.requireNonNull((byte[]) user.get(PublicKeyCredentialUserEntity.ID)) ), - assertion.clientExtensionResults); + clientExtensionResults); } } \ No newline at end of file