From 84e7ebc53158b42df8f32c62cf25fd0c9e8f3ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20=C5=A0trobl?= Date: Tue, 19 Mar 2024 20:15:18 +0800 Subject: [PATCH] Fix #1413: FIDO2: Unify AAGUID format (#1416) --- .../converter/RegistrationConverter.java | 22 ++++++++++++------- .../service/Fido2AuthenticatorService.java | 18 ++++----------- .../fido2/service/RegistrationService.java | 2 +- .../Fido2AuthenticatorServiceTest.java | 11 ++-------- .../model/entity/ActivationRecordEntity.java | 2 +- .../fido2/PowerAuthAssertionProvider.java | 7 +++--- 6 files changed, 25 insertions(+), 37 deletions(-) diff --git a/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/rest/model/converter/RegistrationConverter.java b/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/rest/model/converter/RegistrationConverter.java index f55eac03c..a2bef66e8 100644 --- a/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/rest/model/converter/RegistrationConverter.java +++ b/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/rest/model/converter/RegistrationConverter.java @@ -24,17 +24,14 @@ import com.wultra.powerauth.fido2.rest.model.entity.RegistrationChallenge; import com.wultra.powerauth.fido2.rest.model.request.RegistrationRequest; import com.wultra.powerauth.fido2.rest.model.response.RegistrationResponse; -import com.wultra.powerauth.fido2.service.Fido2AuthenticatorService; import com.wultra.powerauth.fido2.service.model.Fido2Authenticator; import com.wultra.security.powerauth.client.model.enumeration.ActivationStatus; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; +import java.nio.ByteBuffer; +import java.util.*; /** * Converter class for registration related objects. @@ -46,8 +43,6 @@ @Slf4j public class RegistrationConverter { - private final Fido2AuthenticatorService fido2AuthenticatorService; - /** * Convert registration challenge to authenticator detail. * @param challenge Registration challenge. @@ -113,9 +108,20 @@ private Map convertExtras(RegistrationRequest requestObject) thr params.put("origin", authenticatorParameters.getResponse().getClientDataJSON().getOrigin()); params.put("topOrigin", authenticatorParameters.getResponse().getClientDataJSON().getTopOrigin()); params.put("isCrossOrigin", authenticatorParameters.getResponse().getClientDataJSON().isCrossOrigin()); - params.put("aaguid", authenticatorParameters.getResponse().getAttestationObject().getAuthData().getAttestedCredentialData().getAaguid()); + final byte[] aaguidBytes = authenticatorParameters.getResponse().getAttestationObject().getAuthData().getAttestedCredentialData().getAaguid(); + params.put("aaguid", bytesToUUID(aaguidBytes)); params.put("transports", authenticatorParameters.getResponse().getTransports()); return params; } + public UUID bytesToUUID(byte[] bytes) { + if (bytes == null) { + return null; + } + final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); + long mostSigBits = byteBuffer.getLong(); + long leastSigBits = byteBuffer.getLong(); + return new UUID(mostSigBits, leastSigBits); + } + } diff --git a/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/Fido2AuthenticatorService.java b/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/Fido2AuthenticatorService.java index 4febe2ae1..445bdddf7 100644 --- a/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/Fido2AuthenticatorService.java +++ b/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/Fido2AuthenticatorService.java @@ -52,14 +52,13 @@ public class Fido2AuthenticatorService { * @return Fido2Authenticator with registered details. */ @Cacheable("fido2-authenticators-cache") - public Fido2Authenticator findByAaguid(final byte[] aaguid) { - final UUID uuid = uuidFromBytes(aaguid); - if (uuid == null) { + public Fido2Authenticator findByAaguid(final UUID aaguid) { + if (aaguid == null) { return unknownAuthenticator(); } - return fido2AuthenticatorRepository.findById(uuid.toString()) + return fido2AuthenticatorRepository.findById(aaguid.toString()) .map(Fido2AuthenticatorService::convert) - .orElseGet(() -> unknownAuthenticator(uuid)); + .orElseGet(() -> unknownAuthenticator(aaguid)); } private static Fido2Authenticator convert(final Fido2AuthenticatorEntity entity) { @@ -74,13 +73,4 @@ private static Fido2Authenticator unknownAuthenticator(final UUID aaguid) { return new Fido2Authenticator(aaguid, UNKNOWN_AUTHENTICATOR_DESCRIPTION, UNKNOWN_AUTHENTICATOR_SIGNATURE_TYPE); } - private static UUID uuidFromBytes(final byte[] bytes) { - if (bytes == null || bytes.length != 16) { // strange byte array length, UUID requires 16 bytes - logger.debug("Invalid byte length provided for UUID: {}", bytes); - return null; - } - final ByteBuffer bb = ByteBuffer.wrap(bytes); - return new UUID(bb.getLong(), bb.getLong()); - } - } diff --git a/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/RegistrationService.java b/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/RegistrationService.java index 34b6e6b3d..ace308130 100644 --- a/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/RegistrationService.java +++ b/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/RegistrationService.java @@ -147,7 +147,7 @@ public RegistrationResponse register(RegistrationRequest requestObject) throws E logger.info("No signature verification on registration"); } - final Fido2Authenticator model = fido2AuthenticatorService.findByAaguid(aaguid); + final Fido2Authenticator model = fido2AuthenticatorService.findByAaguid(registrationConverter.bytesToUUID(aaguid)); final RegistrationChallenge challenge = registrationProvider.findRegistrationChallengeByValue(applicationId, challengeValue); final AuthenticatorDetail authenticator = registrationConverter.convert(challenge, requestObject, model, cryptographyService.publicKeyToBytes(attestedCredentialData.getPublicKeyObject())) .orElseThrow(() -> new Fido2AuthenticationFailedException("Invalid request")); diff --git a/powerauth-fido2/src/test/java/com/wultra/powerauth/fido2/service/Fido2AuthenticatorServiceTest.java b/powerauth-fido2/src/test/java/com/wultra/powerauth/fido2/service/Fido2AuthenticatorServiceTest.java index 790dbf82d..8e14de880 100644 --- a/powerauth-fido2/src/test/java/com/wultra/powerauth/fido2/service/Fido2AuthenticatorServiceTest.java +++ b/powerauth-fido2/src/test/java/com/wultra/powerauth/fido2/service/Fido2AuthenticatorServiceTest.java @@ -61,7 +61,7 @@ void testFindByAaguid() { when(fido2AuthenticatorRepository.findById(aaguid.toString())) .thenReturn(Optional.of(entity)); - final Fido2Authenticator authenticator = tested.findByAaguid(toBytes(aaguid)); + final Fido2Authenticator authenticator = tested.findByAaguid(aaguid); assertEquals(aaguid, authenticator.aaguid()); assertEquals("My FIDO2 Authenticator", authenticator.description()); assertEquals(SignatureType.POSSESSION, authenticator.signatureType()); @@ -73,7 +73,7 @@ void testFindByAaguid_unknown() { when(fido2AuthenticatorRepository.findById(aaguid.toString())) .thenReturn(Optional.empty()); - final Fido2Authenticator authenticator = tested.findByAaguid(toBytes(aaguid)); + final Fido2Authenticator authenticator = tested.findByAaguid(aaguid); assertEquals(aaguid, authenticator.aaguid()); assertEquals("Unknown FIDO2 Authenticator", authenticator.description()); assertEquals(SignatureType.POSSESSION, authenticator.signatureType()); @@ -87,11 +87,4 @@ void testFindByAaguid_missingAaguid() { assertEquals(SignatureType.POSSESSION, authenticator.signatureType()); } - private static byte[] toBytes(final UUID aaguid) { - ByteBuffer bb = ByteBuffer.wrap(new byte[16]); - bb.putLong(aaguid.getMostSignificantBits()); - bb.putLong(aaguid.getLeastSignificantBits()); - return bb.array(); - } - } diff --git a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/database/model/entity/ActivationRecordEntity.java b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/database/model/entity/ActivationRecordEntity.java index 559cc7c19..a100886c1 100644 --- a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/database/model/entity/ActivationRecordEntity.java +++ b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/database/model/entity/ActivationRecordEntity.java @@ -67,7 +67,7 @@ public class ActivationRecordEntity implements Serializable { @Column(name = "activation_name") private String activationName; - @Column(name = "extras") + @Column(name = "extras", columnDefinition = "CLOB") private String extras; @Column(name = "protocol") diff --git a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthAssertionProvider.java b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthAssertionProvider.java index ee75f6772..dc6b2dd90 100644 --- a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthAssertionProvider.java +++ b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthAssertionProvider.java @@ -288,10 +288,9 @@ private void handleStatus(OperationStatus status) throws Fido2AuthenticationFail } private SignatureType supportedSignatureType(AuthenticatorDetail authenticatorDetail, boolean userVerified) { - final String aaguidBase64 = (String) authenticatorDetail.getExtras().get("aaguid"); - if (aaguidBase64 != null) { - final byte[] aaguid = Base64.getDecoder().decode(aaguidBase64); - return userVerified ? fido2AuthenticatorService.findByAaguid(aaguid).signatureType() : SignatureType.POSSESSION; + final String aaguid = (String) authenticatorDetail.getExtras().get("aaguid"); + if (aaguid != null) { + return userVerified ? fido2AuthenticatorService.findByAaguid(UUID.fromString(aaguid)).signatureType() : SignatureType.POSSESSION; } else { return SignatureType.POSSESSION; }