Skip to content

Commit

Permalink
replace WithExtensionResults<> with Pair<>
Browse files Browse the repository at this point in the history
  • Loading branch information
AdamVe committed Nov 25, 2024
1 parent 1850f47 commit 681a059
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -226,16 +227,18 @@ public PublicKeyCredential makeCredential(
byte[] clientDataHash = Utils.hash(clientDataJson);

try {
WithExtensionResults<Ctap2Session.CredentialData> result = ctapMakeCredential(
Pair<Ctap2Session.CredentialData, ClientExtensionResults> result = ctapMakeCredential(
clientDataHash,
options,
effectiveDomain,
pin,
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,
Expand All @@ -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());
Expand Down Expand Up @@ -282,7 +285,7 @@ public PublicKeyCredential getAssertion(
) throws MultipleAssertionsAvailable, IOException, CommandException, ClientError {
byte[] clientDataHash = Utils.hash(clientDataJson);
try {
final List<WithExtensionResults<Ctap2Session.AssertionData>> assertions = ctapGetAssertions(
final List<Pair<Ctap2Session.AssertionData, ClientExtensionResults>> results = ctapGetAssertions(
clientDataHash,
options,
effectiveDomain,
Expand All @@ -294,18 +297,17 @@ public PublicKeyCredential getAssertion(
options.getAllowCredentials()
);

if (assertions.size() == 1) {
final WithExtensionResults<Ctap2Session.AssertionData> 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) {
Expand Down Expand Up @@ -418,24 +420,6 @@ public CredentialManager getCredentialManager(char[] pin)
}
}

protected static class WithExtensionResults<T> {
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.
* <p>
Expand All @@ -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<Ctap2Session.CredentialData> ctapMakeCredential(
protected Pair<Ctap2Session.CredentialData, ClientExtensionResults> ctapMakeCredential(
byte[] clientDataHash,
PublicKeyCredentialCreationOptions options,
String effectiveDomain,
Expand Down Expand Up @@ -555,12 +539,12 @@ protected WithExtensionResults<Ctap2Session.CredentialData> 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);
}

/**
Expand All @@ -578,12 +562,12 @@ protected WithExtensionResults<Ctap2Session.CredentialData> 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<WithExtensionResults<Ctap2Session.AssertionData>> ctapGetAssertions(
protected List<Pair<Ctap2Session.AssertionData, ClientExtensionResults>> ctapGetAssertions(
byte[] clientDataHash,
PublicKeyCredentialRequestOptions options,
String effectiveDomain,
Expand Down Expand Up @@ -650,13 +634,13 @@ protected List<WithExtensionResults<Ctap2Session.AssertionData>> ctapGetAssertio
state
);

List<WithExtensionResults<Ctap2Session.AssertionData>> result = new ArrayList<>();
List<Pair<Ctap2Session.AssertionData, ClientExtensionResults>> 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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,9 +36,9 @@
*/
public class MultipleAssertionsAvailable extends Throwable {
private final byte[] clientDataJson;
private final List<BasicWebAuthnClient.WithExtensionResults<Ctap2Session.AssertionData>> assertions;
private final List<Pair<Ctap2Session.AssertionData, ClientExtensionResults>> assertions;

MultipleAssertionsAvailable(byte[] clientDataJson, List<BasicWebAuthnClient.WithExtensionResults<Ctap2Session.AssertionData>> assertions) {
MultipleAssertionsAvailable(byte[] clientDataJson, List<Pair<Ctap2Session.AssertionData, ClientExtensionResults>> assertions) {
super("Request returned multiple assertions");

this.clientDataJson = clientDataJson;
Expand Down Expand Up @@ -65,8 +67,8 @@ public int getAssertionCount() {
*/
public List<PublicKeyCredentialUserEntity> getUsers() throws UserInformationNotAvailableError {
List<PublicKeyCredentialUserEntity> users = new ArrayList<>();
for (BasicWebAuthnClient.WithExtensionResults<Ctap2Session.AssertionData> assertion : assertions) {
Map<String, ?> user = assertion.data.getUser();
for (Pair<Ctap2Session.AssertionData, ClientExtensionResults> assertion : assertions) {
Map<String, ?> user = assertion.first.getUser();
if (user == null) {
throw new UserInformationNotAvailableError();
}
Expand All @@ -87,20 +89,23 @@ public PublicKeyCredential select(int index) {
if (assertions.isEmpty()) {
throw new IllegalStateException("Assertion has already been selected");
}
BasicWebAuthnClient.WithExtensionResults<Ctap2Session.AssertionData> assertion = assertions.get(index);
Pair<Ctap2Session.AssertionData, ClientExtensionResults> assertionPair = assertions.get(index);
assertions.clear();

final Map<String, ?> user = Objects.requireNonNull(assertion.data.getUser());
final Map<String, ?> credential = Objects.requireNonNull(assertion.data.getCredential());
final Ctap2Session.AssertionData assertion = assertionPair.first;
final ClientExtensionResults clientExtensionResults = assertionPair.second;

final Map<String, ?> user = Objects.requireNonNull(assertion.getUser());
final Map<String, ?> 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);
}
}

0 comments on commit 681a059

Please sign in to comment.