From 160e0e2c9256d68f7ebe48ae7c6544b3edf245a4 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 25 Nov 2024 12:49:14 +0100 Subject: [PATCH] Fix crash on unknown COSEAlgorithmIdentifier in FIDO MDS --- NEWS | 11 +++++ .../fido/metadata/AuthenticatorGetInfo.java | 43 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/NEWS b/NEWS index 61ff613e2..e51a85ddb 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,14 @@ +== Version 2.5.4 (unreleased) == + +`webauthn-server-attestation`: + +Fixes: + +* `AuthenticatorGetInfo.algorithms` now silently ignores unknown + `COSEAlgorithmIdentifier` and `PublicKeyCredentialType` values instead of + rejecting the MDS BLOB. + + == Version 2.5.3 == `webauthn-server-attestation`: diff --git a/webauthn-server-attestation/src/main/java/com/yubico/fido/metadata/AuthenticatorGetInfo.java b/webauthn-server-attestation/src/main/java/com/yubico/fido/metadata/AuthenticatorGetInfo.java index 1d878b93a..f44301432 100644 --- a/webauthn-server-attestation/src/main/java/com/yubico/fido/metadata/AuthenticatorGetInfo.java +++ b/webauthn-server-attestation/src/main/java/com/yubico/fido/metadata/AuthenticatorGetInfo.java @@ -1,6 +1,7 @@ package com.yubico.fido.metadata; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.core.JacksonException; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; @@ -19,6 +20,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import lombok.Builder; import lombok.NonNull; import lombok.Value; @@ -116,6 +118,7 @@ public class AuthenticatorGetInfo { * href="https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html#authenticatorGetInfo">Client * to Authenticator Protocol (CTAP) ยง6.4. authenticatorGetInfo (0x04) */ + @JsonDeserialize(using = ListPublicKeyCredentialParametersIgnoringUnknownValuesDeserializer.class) List algorithms; /** @@ -377,4 +380,44 @@ public void serialize( value.stream().reduce(0, (acc, next) -> acc | next.getValue(), (a, b) -> a | b)); } } + + @Value + @JsonDeserialize(using = PublicKeyCredentialParametersIgnoringUnknownValues.Deserializer.class) + private static class PublicKeyCredentialParametersIgnoringUnknownValues { + PublicKeyCredentialParameters value; + + private static class Deserializer + extends JsonDeserializer { + @Override + public PublicKeyCredentialParametersIgnoringUnknownValues deserialize( + JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException { + try { + return new PublicKeyCredentialParametersIgnoringUnknownValues( + p.readValueAs(PublicKeyCredentialParameters.class)); + } catch (IOException e) { + return null; + } + } + } + } + + private static class ListPublicKeyCredentialParametersIgnoringUnknownValuesDeserializer + extends JsonDeserializer> { + @Override + public List deserialize( + JsonParser p, DeserializationContext ctxt) throws IOException { + PublicKeyCredentialParametersIgnoringUnknownValues[] pkcpiuvs = + p.readValueAs(PublicKeyCredentialParametersIgnoringUnknownValues[].class); + return Arrays.stream(pkcpiuvs) + .flatMap( + pkcpiuv -> { + if (pkcpiuv != null && pkcpiuv.value != null) { + return Stream.of(pkcpiuv.value); + } else { + return Stream.empty(); + } + }) + .collect(Collectors.toList()); + } + } }