From 9af222e7bf5c63c9917e594d4de93d5d7b469db8 Mon Sep 17 00:00:00 2001 From: Roman Strobl Date: Wed, 28 Feb 2024 15:37:12 +0800 Subject: [PATCH] Fix #1289: FIDO2: Do not allow duplicate registration of same authenticator --- .../powerauth/fido2/service/RegistrationService.java | 7 ++++--- .../fido2/service/provider/RegistrationProvider.java | 3 ++- .../service/fido2/PowerAuthRegistrationProvider.java | 11 +++++++++-- 3 files changed, 15 insertions(+), 6 deletions(-) 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 7aa8c1474..ece894b97 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 @@ -115,6 +115,7 @@ public RegistrationResponse register(RegistrationRequest requestObject) throws E throw new Fido2AuthenticationFailedException(error); } + final String authenticatorId = requestObject.getAuthenticatorParameters().getId(); final AuthenticatorAttestationResponse response = requestObject.getAuthenticatorParameters().getResponse(); final CollectedClientData clientDataJSON = response.getClientDataJSON(); @@ -130,7 +131,7 @@ public RegistrationResponse register(RegistrationRequest requestObject) throws E final String fmt = attestationObject.getFmt(); final byte[] aaguid = attestationObject.getAuthData().getAttestedCredentialData().getAaguid(); - validateRegistrationRequest(applicationId, fmt, aaguid, challengeValue); + validateRegistrationRequest(applicationId, authenticatorId, fmt, aaguid, challengeValue); if (Fmt.FMT_PACKED.getValue().equals(fmt)) { final boolean verifySignature = cryptographyService.verifySignatureForRegistration(applicationId, clientDataJSON, authData, signature, attestedCredentialData); @@ -151,8 +152,8 @@ public RegistrationResponse register(RegistrationRequest requestObject) throws E return registrationConverter.convertRegistrationResponse(authenticatorDetailResponse); } - private void validateRegistrationRequest(final String applicationId, final String attestationFormat, final byte[] aaguid, final String challengeValue) throws Exception { - if (!registrationProvider.registrationAllowed(applicationId, attestationFormat, aaguid)) { + private void validateRegistrationRequest(final String applicationId, final String authenticatorId, final String attestationFormat, final byte[] aaguid, final String challengeValue) throws Exception { + if (!registrationProvider.registrationAllowed(applicationId, authenticatorId, attestationFormat, aaguid)) { logger.warn("Invalid request for FIDO2 registration"); // Immediately revoke the challenge registrationProvider.revokeRegistrationByChallengeValue(applicationId, challengeValue); diff --git a/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/provider/RegistrationProvider.java b/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/provider/RegistrationProvider.java index 0349baafc..e9a18488a 100644 --- a/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/provider/RegistrationProvider.java +++ b/powerauth-fido2/src/main/java/com/wultra/powerauth/fido2/service/provider/RegistrationProvider.java @@ -59,11 +59,12 @@ public interface RegistrationProvider { /** * Verify registration parameters and determine whether registration is allowed. * @param applicationId Application ID. + * @param authenticatorId Authenticator ID. * @param attestationFormat FIDO2 registration attestation format. * @param aaguid FIDO2 registration AAGUID value. * @return Whether registration is allowed. * @throws Exception In case any issue occur during processing. */ - boolean registrationAllowed(String applicationId, String attestationFormat, byte[] aaguid) throws Exception; + boolean registrationAllowed(String applicationId, String authenticatorId, String attestationFormat, byte[] aaguid) throws Exception; } diff --git a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthRegistrationProvider.java b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthRegistrationProvider.java index 820022630..e9f57f229 100644 --- a/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthRegistrationProvider.java +++ b/powerauth-java-server/src/main/java/io/getlime/security/powerauth/app/server/service/fido2/PowerAuthRegistrationProvider.java @@ -31,6 +31,7 @@ import io.getlime.security.powerauth.app.server.database.model.entity.ActivationRecordEntity; import io.getlime.security.powerauth.app.server.database.model.entity.ApplicationEntity; import io.getlime.security.powerauth.app.server.database.model.enumeration.ActivationStatus; +import io.getlime.security.powerauth.app.server.database.repository.ActivationRepository; import io.getlime.security.powerauth.app.server.service.behavior.ServiceBehaviorCatalogue; import io.getlime.security.powerauth.app.server.service.behavior.tasks.ApplicationConfigServiceBehavior; import io.getlime.security.powerauth.app.server.service.exceptions.GenericServiceException; @@ -152,7 +153,7 @@ public void revokeRegistrationByChallengeValue(String applicationId, String chal @Override @Transactional(readOnly = true) - public boolean registrationAllowed(String applicationId, String attestationFormat, byte[] aaguid) throws Exception { + public boolean registrationAllowed(String applicationId, String authenticatorId, String attestationFormat, byte[] aaguid) throws Exception { final ApplicationConfigServiceBehavior configService = serviceBehaviorCatalogue.getApplicationConfigServiceBehavior(); final GetApplicationConfigRequest configRequest = new GetApplicationConfigRequest(); configRequest.setApplicationId(applicationId); @@ -175,7 +176,6 @@ public boolean registrationAllowed(String applicationId, String attestationForma .findFirst(); if (configAaguids.isPresent()) { - System.out.println(aaguidStr); List allowedAaguids = configAaguids.get().getValues(); if (!allowedAaguids.contains(aaguidStr)) { logger.warn("Rejected AAGUID value for FIDO2 registration: {}", aaguidStr); @@ -183,6 +183,13 @@ public boolean registrationAllowed(String applicationId, String attestationForma } } + final ActivationRepository activationRepository = repositoryCatalogue.getActivationRepository(); + final List existingActivations = activationRepository.findByExternalId(applicationId, authenticatorId); + if (!existingActivations.isEmpty()) { + logger.warn("Rejected duplicate external ID for registration, application ID: {}, external ID: {}", applicationId, authenticatorId); + return false; + } + return true; } }