From a733a7737e3411f5a9644ee3ceb2a6a00b596e7f Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 13 Feb 2024 10:32:59 +0100 Subject: [PATCH 01/12] Extract functions encodeDerSequence and encodeDerBitStringWithZeroUnused --- .../com/yubico/webauthn/WebAuthnCodecs.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java index 94ba42ea1..ae13fe65c 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java @@ -42,6 +42,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.stream.Stream; final class WebAuthnCodecs { @@ -151,6 +152,33 @@ private static ECPublicKey importCoseP256PublicKey(CBORObject cose) throws CoseE return (ECPublicKey) new OneKey(cose).AsPublicKey(); } + private static ByteArray encodeDerLength(final int length) { + if (length <= 127) { + return new ByteArray(new byte[] {(byte) length}); + } else if (length <= 0xffff) { + if (length <= 255) { + return new ByteArray(new byte[] {-127, (byte) length}); + } else { + return new ByteArray(new byte[] {-126, (byte) (length >> 8), (byte) (length & 0x00ff)}); + } + } else { + throw new UnsupportedOperationException("Too long: " + length); + } + } + + private static ByteArray encodeDerBitStringWithZeroUnused(final ByteArray content) { + return new ByteArray(new byte[] {0x03}) + .concat(encodeDerLength(1 + content.size())) + .concat(new ByteArray(new byte[] {0})) + .concat(content); + } + + private static ByteArray encodeDerSequence(final ByteArray... items) { + final ByteArray content = + Stream.of(items).reduce(ByteArray::concat).orElseGet(() -> new ByteArray(new byte[0])); + return new ByteArray(new byte[] {0x30}).concat(encodeDerLength(content.size())).concat(content); + } + private static PublicKey importCoseEdDsaPublicKey(CBORObject cose) throws InvalidKeySpecException, NoSuchAlgorithmException { final int curveId = cose.get(CBORObject.FromObject(-1)).AsInt32(); @@ -166,10 +194,7 @@ private static PublicKey importCoseEd25519PublicKey(CBORObject cose) throws InvalidKeySpecException, NoSuchAlgorithmException { final ByteArray rawKey = new ByteArray(cose.get(CBORObject.FromObject(-2)).GetByteString()); final ByteArray x509Key = - new ByteArray(new byte[] {0x30, (byte) (ED25519_CURVE_OID.size() + 3 + rawKey.size())}) - .concat(ED25519_CURVE_OID) - .concat(new ByteArray(new byte[] {0x03, (byte) (rawKey.size() + 1), 0})) - .concat(rawKey); + encodeDerSequence(ED25519_CURVE_OID, encodeDerBitStringWithZeroUnused(rawKey)); KeyFactory kFact = KeyFactory.getInstance("EdDSA"); return kFact.generatePublic(new X509EncodedKeySpec(x509Key.getBytes())); From 2c51f98cb3b087d8637140aa7a07f0f1a3495ea5 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 13 Feb 2024 10:38:13 +0100 Subject: [PATCH 02/12] Translate ECDSA keys to X.509 instead of using COSE-Java At this point this is the only thing we really use the COSE-Java library for. At the cost of this small bit of extra code we can eliminate the dependency, one benefit of which is that downstream security review gets easier. --- .../com/yubico/webauthn/WebAuthnCodecs.java | 59 +++++++++++++++++-- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java index ae13fe65c..70c8ebfdd 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java @@ -25,7 +25,6 @@ package com.yubico.webauthn; import COSE.CoseException; -import COSE.OneKey; import com.google.common.primitives.Bytes; import com.upokecenter.cbor.CBORObject; import com.yubico.webauthn.data.ByteArray; @@ -46,6 +45,19 @@ final class WebAuthnCodecs { + private static final ByteArray EC_PUBLIC_KEY_OID = + new ByteArray( + new byte[] { + 0x2A, -122, 0x48, -50, 0x3D, 0x02, 0x01 + }); // OID 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) + private static final ByteArray P256_CURVE_OID = + new ByteArray( + new byte[] {0x2A, -122, 0x48, -50, 0x3D, 0x03, 0x01, 7}); // OID 1.2.840.10045.3.1.7 + private static final ByteArray P384_CURVE_OID = + new ByteArray(new byte[] {0x2B, -127, 0x04, 0, 34}); // OID 1.3.132.0.34 + private static final ByteArray P512_CURVE_OID = + new ByteArray(new byte[] {0x2B, -127, 0x04, 0, 35}); // OID 1.3.132.0.35 + private static final ByteArray ED25519_CURVE_OID = new ByteArray(new byte[] {0x30, 0x05, 0x06, 0x03, 0x2B, 0x65, 0x70}); @@ -130,7 +142,7 @@ static PublicKey importCosePublicKey(ByteArray key) // additional dependency to parse EdDSA keys via the OneKey constructor return importCoseEdDsaPublicKey(cose); case 2: - return importCoseP256PublicKey(cose); + return importCoseEcdsaPublicKey(cose); case 3: // COSE-JAVA supports RSA in v1.1.0 but not in v1.0.0 return importCoseRsaPublicKey(cose); @@ -148,8 +160,43 @@ private static PublicKey importCoseRsaPublicKey(CBORObject cose) return KeyFactory.getInstance("RSA").generatePublic(spec); } - private static ECPublicKey importCoseP256PublicKey(CBORObject cose) throws CoseException { - return (ECPublicKey) new OneKey(cose).AsPublicKey(); + private static PublicKey importCoseEcdsaPublicKey(CBORObject cose) + throws NoSuchAlgorithmException, InvalidKeySpecException { + final int crv = cose.get(CBORObject.FromObject(-1)).AsInt32Value(); + final ByteArray x = new ByteArray(cose.get(CBORObject.FromObject(-2)).GetByteString()); + final ByteArray y = new ByteArray(cose.get(CBORObject.FromObject(-3)).GetByteString()); + + final ByteArray curveOid; + switch (crv) { + case 1: + curveOid = P256_CURVE_OID; + break; + + case 2: + curveOid = P384_CURVE_OID; + break; + + case 3: + curveOid = P512_CURVE_OID; + break; + + default: + throw new IllegalArgumentException("Unknown COSE EC2 curve: " + crv); + } + + final ByteArray algId = + encodeDerSequence(encodeDerObjectId(EC_PUBLIC_KEY_OID), encodeDerObjectId(curveOid)); + + final ByteArray rawKey = + encodeDerBitStringWithZeroUnused( + new ByteArray(new byte[] {0x04}) // Raw EC public key with x and y + .concat(x) + .concat(y)); + + final ByteArray x509Key = encodeDerSequence(algId, rawKey); + + KeyFactory kFact = KeyFactory.getInstance("EC"); + return kFact.generatePublic(new X509EncodedKeySpec(x509Key.getBytes())); } private static ByteArray encodeDerLength(final int length) { @@ -166,6 +213,10 @@ private static ByteArray encodeDerLength(final int length) { } } + private static ByteArray encodeDerObjectId(final ByteArray oid) { + return new ByteArray(new byte[] {0x06, (byte) oid.size()}).concat(oid); + } + private static ByteArray encodeDerBitStringWithZeroUnused(final ByteArray content) { return new ByteArray(new byte[] {0x03}) .concat(encodeDerLength(1 + content.size())) From 3b672e27ca8771296c14fe99b34fba584cb50283 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 13 Feb 2024 15:12:08 +0100 Subject: [PATCH 03/12] Rename constant ED25519_CURVE_OID to ED25519_ALG_ID --- .../com/yubico/webauthn/WebAuthnCodecs.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java index 70c8ebfdd..070c9b774 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java @@ -58,8 +58,20 @@ final class WebAuthnCodecs { private static final ByteArray P512_CURVE_OID = new ByteArray(new byte[] {0x2B, -127, 0x04, 0, 35}); // OID 1.3.132.0.35 - private static final ByteArray ED25519_CURVE_OID = - new ByteArray(new byte[] {0x30, 0x05, 0x06, 0x03, 0x2B, 0x65, 0x70}); + private static final ByteArray ED25519_ALG_ID = + new ByteArray( + new byte[] { + // SEQUENCE (5 bytes) + 0x30, + 0x05, + // OID (3 bytes) + 0x06, + 0x03, + // OID 1.3.101.112 + 0x2B, + 0x65, + 0x70 + }); static ByteArray ecPublicKeyToRaw(ECPublicKey key) { @@ -245,7 +257,7 @@ private static PublicKey importCoseEd25519PublicKey(CBORObject cose) throws InvalidKeySpecException, NoSuchAlgorithmException { final ByteArray rawKey = new ByteArray(cose.get(CBORObject.FromObject(-2)).GetByteString()); final ByteArray x509Key = - encodeDerSequence(ED25519_CURVE_OID, encodeDerBitStringWithZeroUnused(rawKey)); + encodeDerSequence(ED25519_ALG_ID, encodeDerBitStringWithZeroUnused(rawKey)); KeyFactory kFact = KeyFactory.getInstance("EdDSA"); return kFact.generatePublic(new X509EncodedKeySpec(x509Key.getBytes())); From 77ee463ba713c6748e92c8449ceae9f7b5649943 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 13 Feb 2024 10:22:38 +0100 Subject: [PATCH 04/12] Drop dependency on COSE-Java --- NEWS | 7 +++++++ build.gradle | 1 - settings.gradle.kts | 1 - .../build.gradle.kts | 3 --- .../yubico/webauthn/BouncyCastleProviderPresenceTest.java | 5 ++--- .../java/com/yubico/webauthn/CryptoAlgorithmsTest.java | 7 +++---- .../java-dep-webauthn-server-core/build.gradle.kts | 3 --- .../yubico/webauthn/BouncyCastleProviderPresenceTest.java | 3 +-- .../java/com/yubico/webauthn/CryptoAlgorithmsTest.java | 5 ++--- webauthn-server-core/build.gradle.kts | 1 - .../com/yubico/webauthn/AttestationStatementVerifier.java | 3 +-- .../webauthn/FidoU2fAttestationStatementVerifier.java | 7 +++---- .../java/com/yubico/webauthn/FinishAssertionSteps.java | 3 +-- .../java/com/yubico/webauthn/FinishRegistrationSteps.java | 5 ++--- .../webauthn/PackedAttestationStatementVerifier.java | 3 +-- .../yubico/webauthn/TpmAttestationStatementVerifier.java | 5 ++--- .../src/main/java/com/yubico/webauthn/WebAuthnCodecs.java | 3 +-- 17 files changed, 26 insertions(+), 39 deletions(-) diff --git a/NEWS b/NEWS index 979a4eafd..b5f91702b 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,10 @@ +== Version 2.5.1 (unreleased) == + +Changes: + +* Dropped dependency on COSE-Java. + + == Version 2.5.0 == `webauthn-server-core`: diff --git a/build.gradle b/build.gradle index d61a8e0bf..5bfbf93ac 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,6 @@ dependencies { constraints { api(constraintLibs.bundles.jackson) api(constraintLibs.cbor) - api(constraintLibs.cose) api(constraintLibs.guava) api(constraintLibs.httpclient5) api(constraintLibs.slf4j) diff --git a/settings.gradle.kts b/settings.gradle.kts index 3cb500697..83a4d55e2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,7 +15,6 @@ dependencyResolutionManagement { versionCatalogs { create("constraintLibs") { library("cbor", "com.upokecenter:cbor:[4.5.1,5)") - library("cose", "com.augustcellars.cose:cose-java:[1.0.0,2)") library("guava", "com.google.guava:guava:[24.1.1,33)") library("httpclient5", "org.apache.httpcomponents.client5:httpclient5:[5.0.0,6)") library("slf4j", "org.slf4j:slf4j-api:[1.7.25,3)") diff --git a/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/build.gradle.kts b/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/build.gradle.kts index 801446db1..3d5d07c94 100644 --- a/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/build.gradle.kts +++ b/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/build.gradle.kts @@ -12,9 +12,6 @@ dependencies { testImplementation("junit:junit:4.12") testImplementation("org.mockito:mockito-core:[2.27.0,3)") - // Runtime-only internal dependency of webauthn-server-core - testImplementation("com.augustcellars.cose:cose-java:[1.0.0,2)") - // Transitive dependencies from coreTestOutput testImplementation("org.scala-lang:scala-library:[2.13.1,3)") } diff --git a/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/src/test/java/com/yubico/webauthn/BouncyCastleProviderPresenceTest.java b/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/src/test/java/com/yubico/webauthn/BouncyCastleProviderPresenceTest.java index e38997392..b789838d2 100644 --- a/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/src/test/java/com/yubico/webauthn/BouncyCastleProviderPresenceTest.java +++ b/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/src/test/java/com/yubico/webauthn/BouncyCastleProviderPresenceTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertTrue; -import COSE.CoseException; import com.yubico.webauthn.data.AttestationObject; import com.yubico.webauthn.data.RelyingPartyIdentity; import java.io.IOException; @@ -72,7 +71,7 @@ public void bouncyCastleProviderIsNotLoadedAfterInstantiatingRelyingParty() { @Test public void bouncyCastleProviderIsNotLoadedAfterAttemptingToLoadEddsaKey() - throws IOException, CoseException, InvalidKeySpecException { + throws IOException, InvalidKeySpecException { try { WebAuthnCodecs.importCosePublicKey( new AttestationObject( @@ -92,7 +91,7 @@ public void bouncyCastleProviderIsNotLoadedAfterAttemptingToLoadEddsaKey() @Test(expected = NoSuchAlgorithmException.class) public void doesNotFallBackToBouncyCastleAutomatically() - throws IOException, CoseException, InvalidKeySpecException, NoSuchAlgorithmException { + throws IOException, InvalidKeySpecException, NoSuchAlgorithmException { for (Provider prov : Security.getProviders()) { Security.removeProvider(prov.getName()); } diff --git a/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/src/test/java/com/yubico/webauthn/CryptoAlgorithmsTest.java b/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/src/test/java/com/yubico/webauthn/CryptoAlgorithmsTest.java index 78201c6a2..57cd1bcc3 100644 --- a/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/src/test/java/com/yubico/webauthn/CryptoAlgorithmsTest.java +++ b/test-dependent-projects/java-dep-webauthn-server-core-and-bouncycastle/src/test/java/com/yubico/webauthn/CryptoAlgorithmsTest.java @@ -3,7 +3,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import COSE.CoseException; import com.yubico.webauthn.data.AttestationObject; import com.yubico.webauthn.data.RelyingPartyIdentity; import java.io.IOException; @@ -47,7 +46,7 @@ public void tearDown() { @Test public void importRsa() - throws IOException, CoseException, NoSuchAlgorithmException, InvalidKeySpecException { + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { PublicKey key = WebAuthnCodecs.importCosePublicKey( new AttestationObject( @@ -61,7 +60,7 @@ public void importRsa() @Test public void importEcdsa() - throws IOException, CoseException, NoSuchAlgorithmException, InvalidKeySpecException { + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { PublicKey key = WebAuthnCodecs.importCosePublicKey( new AttestationObject( @@ -75,7 +74,7 @@ public void importEcdsa() @Test public void importEddsa() - throws IOException, CoseException, NoSuchAlgorithmException, InvalidKeySpecException { + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { PublicKey key = WebAuthnCodecs.importCosePublicKey( new AttestationObject( diff --git a/test-dependent-projects/java-dep-webauthn-server-core/build.gradle.kts b/test-dependent-projects/java-dep-webauthn-server-core/build.gradle.kts index 1e8977835..29f2ab537 100644 --- a/test-dependent-projects/java-dep-webauthn-server-core/build.gradle.kts +++ b/test-dependent-projects/java-dep-webauthn-server-core/build.gradle.kts @@ -11,9 +11,6 @@ dependencies { testImplementation("junit:junit:4.12") testImplementation("org.mockito:mockito-core:[2.27.0,3)") - // Runtime-only internal dependency of webauthn-server-core - testImplementation("com.augustcellars.cose:cose-java:[1.0.0,2)") - // Transitive dependencies from coreTestOutput testImplementation("org.scala-lang:scala-library:[2.13.1,3)") } diff --git a/test-dependent-projects/java-dep-webauthn-server-core/src/test/java/com/yubico/webauthn/BouncyCastleProviderPresenceTest.java b/test-dependent-projects/java-dep-webauthn-server-core/src/test/java/com/yubico/webauthn/BouncyCastleProviderPresenceTest.java index 6ce756bbc..27c43e834 100644 --- a/test-dependent-projects/java-dep-webauthn-server-core/src/test/java/com/yubico/webauthn/BouncyCastleProviderPresenceTest.java +++ b/test-dependent-projects/java-dep-webauthn-server-core/src/test/java/com/yubico/webauthn/BouncyCastleProviderPresenceTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertTrue; -import COSE.CoseException; import com.yubico.webauthn.data.AttestationObject; import com.yubico.webauthn.data.RelyingPartyIdentity; import java.io.IOException; @@ -51,7 +50,7 @@ public void bouncyCastleProviderIsNotLoadedAfterInstantiatingRelyingParty() { @Test public void bouncyCastleProviderIsNotLoadedAfterAttemptingToLoadEddsaKey() - throws IOException, CoseException, InvalidKeySpecException { + throws IOException, InvalidKeySpecException { try { WebAuthnCodecs.importCosePublicKey( new AttestationObject( diff --git a/test-dependent-projects/java-dep-webauthn-server-core/src/test/java/com/yubico/webauthn/CryptoAlgorithmsTest.java b/test-dependent-projects/java-dep-webauthn-server-core/src/test/java/com/yubico/webauthn/CryptoAlgorithmsTest.java index f35ce43ae..5a96dac81 100644 --- a/test-dependent-projects/java-dep-webauthn-server-core/src/test/java/com/yubico/webauthn/CryptoAlgorithmsTest.java +++ b/test-dependent-projects/java-dep-webauthn-server-core/src/test/java/com/yubico/webauthn/CryptoAlgorithmsTest.java @@ -2,7 +2,6 @@ import static org.junit.Assert.assertEquals; -import COSE.CoseException; import com.yubico.webauthn.data.AttestationObject; import com.yubico.webauthn.data.RelyingPartyIdentity; import java.io.IOException; @@ -45,7 +44,7 @@ public void tearDown() { @Test public void importRsa() - throws IOException, CoseException, NoSuchAlgorithmException, InvalidKeySpecException { + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { PublicKey key = WebAuthnCodecs.importCosePublicKey( new AttestationObject( @@ -59,7 +58,7 @@ public void importRsa() @Test public void importEcdsa() - throws IOException, CoseException, NoSuchAlgorithmException, InvalidKeySpecException { + throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { PublicKey key = WebAuthnCodecs.importCosePublicKey( new AttestationObject( diff --git a/webauthn-server-core/build.gradle.kts b/webauthn-server-core/build.gradle.kts index 79ed2a335..9bbd2bda8 100644 --- a/webauthn-server-core/build.gradle.kts +++ b/webauthn-server-core/build.gradle.kts @@ -16,7 +16,6 @@ dependencies { api(platform(rootProject)) implementation(project(":yubico-util")) - implementation("com.augustcellars.cose:cose-java") implementation("com.fasterxml.jackson.core:jackson-databind") implementation("com.google.guava:guava") implementation("com.upokecenter:cbor") diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/AttestationStatementVerifier.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/AttestationStatementVerifier.java index a962164e3..b815aa320 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/AttestationStatementVerifier.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/AttestationStatementVerifier.java @@ -24,7 +24,6 @@ package com.yubico.webauthn; -import COSE.CoseException; import com.yubico.webauthn.data.AttestationObject; import com.yubico.webauthn.data.AttestationType; import com.yubico.webauthn.data.ByteArray; @@ -34,7 +33,7 @@ interface AttestationStatementVerifier { AttestationType getAttestationType(AttestationObject attestation) - throws IOException, CoseException, CertificateException; + throws IOException, CertificateException; boolean verifyAttestationSignature( AttestationObject attestationObject, ByteArray clientDataJsonHash); diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/FidoU2fAttestationStatementVerifier.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/FidoU2fAttestationStatementVerifier.java index ac3f1f2f1..5806222c2 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/FidoU2fAttestationStatementVerifier.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/FidoU2fAttestationStatementVerifier.java @@ -26,7 +26,6 @@ import static com.yubico.webauthn.Crypto.isP256; -import COSE.CoseException; import com.fasterxml.jackson.databind.JsonNode; import com.yubico.internal.util.ExceptionUtil; import com.yubico.webauthn.data.AttestationObject; @@ -76,7 +75,7 @@ private static boolean validSelfSignature(X509Certificate cert) { } private static ByteArray getRawUserPublicKey(AttestationObject attestationObject) - throws IOException, CoseException { + throws IOException { final ByteArray pubkeyCose = attestationObject .getAuthenticatorData() @@ -102,7 +101,7 @@ private static ByteArray getRawUserPublicKey(AttestationObject attestationObject @Override public AttestationType getAttestationType(AttestationObject attestationObject) - throws CoseException, IOException, CertificateException { + throws IOException, CertificateException { X509Certificate attestationCertificate = getAttestationCertificate(attestationObject); if (attestationCertificate.getPublicKey() instanceof ECPublicKey @@ -153,7 +152,7 @@ && isP256(((ECPublicKey) attestationCertificate.getPublicKey()).getParams()))) { try { userPublicKey = getRawUserPublicKey(attestationObject); - } catch (IOException | CoseException e) { + } catch (IOException e) { RuntimeException err = new RuntimeException( String.format( diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionSteps.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionSteps.java index 88b792435..c39a87780 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionSteps.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishAssertionSteps.java @@ -26,7 +26,6 @@ import static com.yubico.internal.util.ExceptionUtil.assertTrue; -import COSE.CoseException; import com.yubico.internal.util.OptionalUtil; import com.yubico.webauthn.data.AuthenticatorAssertionResponse; import com.yubico.webauthn.data.ByteArray; @@ -495,7 +494,7 @@ public void validate() { try { key = WebAuthnCodecs.importCosePublicKey(cose); - } catch (CoseException | IOException | InvalidKeySpecException e) { + } catch (IOException | InvalidKeySpecException e) { throw new IllegalArgumentException( String.format( "Failed to decode public key: Credential ID: %s COSE: %s", diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishRegistrationSteps.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishRegistrationSteps.java index 172da13dd..4f8e20cd2 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishRegistrationSteps.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/FinishRegistrationSteps.java @@ -27,7 +27,6 @@ import static com.yubico.internal.util.ExceptionUtil.assertTrue; import static com.yubico.internal.util.ExceptionUtil.wrapAndLog; -import COSE.CoseException; import com.upokecenter.cbor.CBORObject; import com.yubico.internal.util.CertificateParser; import com.yubico.internal.util.OptionalUtil; @@ -335,7 +334,7 @@ public void validate() { .collect(Collectors.toList())); try { WebAuthnCodecs.importCosePublicKey(publicKeyCose); - } catch (CoseException | IOException | InvalidKeySpecException | NoSuchAlgorithmException e) { + } catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) { throw wrapAndLog(log, "Failed to parse credential public key", e); } } @@ -421,7 +420,7 @@ public AttestationType attestationType() { return AttestationType.UNKNOWN; } } - } catch (IOException | CoseException | CertificateException e) { + } catch (IOException | CertificateException e) { throw new IllegalArgumentException("Failed to resolve attestation type.", e); } } diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/PackedAttestationStatementVerifier.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/PackedAttestationStatementVerifier.java index ed513dbb4..0e8a97bbe 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/PackedAttestationStatementVerifier.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/PackedAttestationStatementVerifier.java @@ -24,7 +24,6 @@ package com.yubico.webauthn; -import COSE.CoseException; import com.fasterxml.jackson.databind.JsonNode; import com.upokecenter.cbor.CBORObject; import com.yubico.internal.util.CertificateParser; @@ -95,7 +94,7 @@ private boolean verifySelfAttestationSignature( .getAttestedCredentialData() .get() .getCredentialPublicKey()); - } catch (IOException | CoseException | InvalidKeySpecException e) { + } catch (IOException | InvalidKeySpecException e) { throw ExceptionUtil.wrapAndLog( log, String.format( diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/TpmAttestationStatementVerifier.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/TpmAttestationStatementVerifier.java index ee051e770..fc91e4205 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/TpmAttestationStatementVerifier.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/TpmAttestationStatementVerifier.java @@ -24,7 +24,6 @@ package com.yubico.webauthn; -import COSE.CoseException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.upokecenter.cbor.CBORObject; @@ -178,7 +177,7 @@ public boolean verifyAttestationSignature( // is identical to the credentialPublicKey in the attestedCredentialData in authenticatorData. try { verifyPublicKeysMatch(attestationObject, pubArea); - } catch (CoseException | IOException | InvalidKeySpecException | NoSuchAlgorithmException e) { + } catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) { throw new RuntimeException( "Failed to verify that public key in TPM attestation matches public key in authData.", e); } @@ -267,7 +266,7 @@ private void validateCertInfo( } private void verifyPublicKeysMatch(AttestationObject attestationObject, TpmtPublic pubArea) - throws CoseException, IOException, InvalidKeySpecException, NoSuchAlgorithmException { + throws IOException, InvalidKeySpecException, NoSuchAlgorithmException { final PublicKey credentialPubKey = WebAuthnCodecs.importCosePublicKey( attestationObject diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java index 070c9b774..1be854f73 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java @@ -24,7 +24,6 @@ package com.yubico.webauthn; -import COSE.CoseException; import com.google.common.primitives.Bytes; import com.upokecenter.cbor.CBORObject; import com.yubico.webauthn.data.ByteArray; @@ -145,7 +144,7 @@ static ByteArray rawEcKeyToCose(ByteArray key) { } static PublicKey importCosePublicKey(ByteArray key) - throws CoseException, IOException, InvalidKeySpecException, NoSuchAlgorithmException { + throws IOException, InvalidKeySpecException, NoSuchAlgorithmException { CBORObject cose = CBORObject.DecodeFromBytes(key.getBytes()); final int kty = cose.get(CBORObject.FromObject(1)).AsInt32(); switch (kty) { From ee3ecf3ec485c6317a443fe170a565718a6bc917 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 13 Feb 2024 10:23:09 +0100 Subject: [PATCH 05/12] Add dependency promotion/demotion step to release checklist --- doc/releasing.md | 56 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/doc/releasing.md b/doc/releasing.md index 88083b50c..3c2a46c88 100644 --- a/doc/releasing.md +++ b/doc/releasing.md @@ -6,13 +6,22 @@ Release candidate versions 1. Make sure release notes in `NEWS` are up to date. - 2. Run the tests one more time: + 2. Review the diff from the previous version for any changes to the public API, + and adjust the upcoming version number accordingly. + + If any implementation dependencies have been added to method signatures in + the public API, including `throws` declarations, change these dependencies + from `implementation` to `api` dependency declarations in the relevant + Gradle build script. Conversely, remove or downgrade to `implementation` any + dependencies no longer exposed in the public API. + + 3. Run the tests one more time: ``` $ ./gradlew clean check ``` - 3. Update the Java version in the [`release-verify-signatures` + 4. Update the Java version in the [`release-verify-signatures` workflow](https://github.com/Yubico/java-webauthn-server/blob/main/.github/workflows/release-verify-signatures.yml#L42). See the `openjdk version` line of output from `java -version`: @@ -34,7 +43,7 @@ Release candidate versions Commit this change, if any. - 4. Tag the head commit with an `X.Y.Z-RCN` tag: + 5. Tag the head commit with an `X.Y.Z-RCN` tag: ``` $ git tag -a -s 1.4.0-RC1 -m "Pre-release 1.4.0-RC1" @@ -42,13 +51,13 @@ Release candidate versions No tag body needed. - 5. Publish to Sonatype Nexus: + 6. Publish to Sonatype Nexus: ``` $ ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository ``` - 6. Push to GitHub. + 7. Push to GitHub. If the pre-release makes significant changes to the project README, such that the README does not accurately reflect the latest non-pre-release @@ -66,7 +75,7 @@ Release candidate versions $ git push origin main 1.4.0-RC1 ``` - 7. Make GitHub release. + 8. Make GitHub release. - Use the new tag as the release tag. - Check the pre-release checkbox. @@ -76,7 +85,7 @@ Release candidate versions - Note the JDK version shown by `java -version` in step 3. For example: `openjdk version "17.0.7" 2023-04-18`. - 8. Check that the ["Reproducible binary" + 9. Check that the ["Reproducible binary" workflow](https://github.com/Yubico/java-webauthn-server/actions/workflows/release-verify-signatures.yml) runs and succeeds. @@ -86,7 +95,16 @@ Release versions 1. Make sure release notes in `NEWS` are up to date. - 2. Make a no-fast-forward merge from the last (non release candidate) release + 2. Review the diff from the previous version for any changes to the public API, + and adjust the upcoming version number accordingly. + + If any implementation dependencies have been added to method signatures in + the public API, including `throws` declarations, change these dependencies + from `implementation` to `api` dependency declarations in the relevant + Gradle build script. Conversely, remove or downgrade to `implementation` any + dependencies no longer exposed in the public API. + + 3. Make a no-fast-forward merge from the last (non release candidate) release to the commit to be released: ``` @@ -108,13 +126,13 @@ Release versions $ git branch -d release-1.4.0 ``` - 3. Remove the "(unreleased)" tag from `NEWS`. + 4. Remove the "(unreleased)" tag from `NEWS`. - 4. Update the version in the dependency snippets in the README. + 5. Update the version in the dependency snippets in the README. - 5. Update the version in JavaDoc links in the READMEs. + 6. Update the version in JavaDoc links in the READMEs. - 6. Update the Java version in the [`release-verify-signatures` + 7. Update the Java version in the [`release-verify-signatures` workflow](https://github.com/Yubico/java-webauthn-server/blob/main/.github/workflows/release-verify-signatures.yml#L42). See the `openjdk version` line of output from `java -version`: @@ -134,20 +152,20 @@ Release versions java: ["17.0.7"] ``` - 7. Amend these changes into the merge commit: + 8. Amend these changes into the merge commit: ``` $ git add NEWS README */README .github/workflows/release-verify-signatures.yml $ git commit --amend --reset-author ``` - 8. Run the tests one more time: + 9. Run the tests one more time: ``` $ ./gradlew clean check ``` - 9. Tag the merge commit with an `X.Y.Z` tag: +10. Tag the merge commit with an `X.Y.Z` tag: ``` $ git tag -a -s 1.4.0 -m "Release 1.4.0" @@ -155,19 +173,19 @@ Release versions No tag body needed since that's included in the commit. -10. Publish to Sonatype Nexus: +11. Publish to Sonatype Nexus: ``` $ ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository ``` -11. Push to GitHub: +12. Push to GitHub: ``` $ git push origin main 1.4.0 ``` -12. Make GitHub release. +13. Make GitHub release. - Use the new tag as the release tag. - Copy the release notes from `NEWS` into the GitHub release notes; reformat @@ -176,6 +194,6 @@ Release versions - Note the JDK version shown by `java -version` in step 6. For example: `openjdk version "17.0.7" 2023-04-18`. -13. Check that the ["Reproducible binary" +14. Check that the ["Reproducible binary" workflow](https://github.com/Yubico/java-webauthn-server/actions/workflows/release-verify-signatures.yml) runs and succeeds. From 7ede25a534e92ce2dba77b34926983ec303b4f53 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Thu, 15 Feb 2024 12:40:06 +0100 Subject: [PATCH 06/12] Use decimal notation for some ASN.1 bytes to better align with comments --- .../java/com/yubico/webauthn/WebAuthnCodecs.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java index 1be854f73..0981e0736 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java @@ -47,11 +47,11 @@ final class WebAuthnCodecs { private static final ByteArray EC_PUBLIC_KEY_OID = new ByteArray( new byte[] { - 0x2A, -122, 0x48, -50, 0x3D, 0x02, 0x01 + 0x2A, -122, 0x48, -50, 0x3D, 2, 1 }); // OID 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) private static final ByteArray P256_CURVE_OID = new ByteArray( - new byte[] {0x2A, -122, 0x48, -50, 0x3D, 0x03, 0x01, 7}); // OID 1.2.840.10045.3.1.7 + new byte[] {0x2A, -122, 0x48, -50, 0x3D, 3, 1, 7}); // OID 1.2.840.10045.3.1.7 private static final ByteArray P384_CURVE_OID = new ByteArray(new byte[] {0x2B, -127, 0x04, 0, 34}); // OID 1.3.132.0.34 private static final ByteArray P512_CURVE_OID = @@ -62,14 +62,14 @@ final class WebAuthnCodecs { new byte[] { // SEQUENCE (5 bytes) 0x30, - 0x05, + 5, // OID (3 bytes) 0x06, - 0x03, + 3, // OID 1.3.101.112 0x2B, - 0x65, - 0x70 + 101, + 112 }); static ByteArray ecPublicKeyToRaw(ECPublicKey key) { From 7667c0e67e3c948f8a6a719c681b6306030052e0 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Thu, 15 Feb 2024 12:50:14 +0100 Subject: [PATCH 07/12] Use hexadecimal notation instead of negative decimal --- .../main/java/com/yubico/webauthn/WebAuthnCodecs.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java index 0981e0736..ac091e443 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java @@ -47,15 +47,17 @@ final class WebAuthnCodecs { private static final ByteArray EC_PUBLIC_KEY_OID = new ByteArray( new byte[] { - 0x2A, -122, 0x48, -50, 0x3D, 2, 1 + 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 2, 1 }); // OID 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type) private static final ByteArray P256_CURVE_OID = new ByteArray( - new byte[] {0x2A, -122, 0x48, -50, 0x3D, 3, 1, 7}); // OID 1.2.840.10045.3.1.7 + new byte[] { + 0x2A, (byte) 0x86, 0x48, (byte) 0xCE, 0x3D, 3, 1, 7 // OID 1.2.840.10045.3.1.7 + }); private static final ByteArray P384_CURVE_OID = - new ByteArray(new byte[] {0x2B, -127, 0x04, 0, 34}); // OID 1.3.132.0.34 + new ByteArray(new byte[] {0x2B, (byte) 0x81, 0x04, 0, 34}); // OID 1.3.132.0.34 private static final ByteArray P512_CURVE_OID = - new ByteArray(new byte[] {0x2B, -127, 0x04, 0, 35}); // OID 1.3.132.0.35 + new ByteArray(new byte[] {0x2B, (byte) 0x81, 0x04, 0, 35}); // OID 1.3.132.0.35 private static final ByteArray ED25519_ALG_ID = new ByteArray( From abcb0e05eb9a8b29bbbe0721018edab0ab961f66 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Thu, 15 Feb 2024 12:50:48 +0100 Subject: [PATCH 08/12] Remove comments about COSE-Java workarounds --- .../src/main/java/com/yubico/webauthn/WebAuthnCodecs.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java index ac091e443..24dffeb4c 100644 --- a/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java +++ b/webauthn-server-core/src/main/java/com/yubico/webauthn/WebAuthnCodecs.java @@ -151,13 +151,10 @@ static PublicKey importCosePublicKey(ByteArray key) final int kty = cose.get(CBORObject.FromObject(1)).AsInt32(); switch (kty) { case 1: - // COSE-JAVA is hardcoded to ed25519-java provider ("EdDSA") which would require an - // additional dependency to parse EdDSA keys via the OneKey constructor return importCoseEdDsaPublicKey(cose); case 2: return importCoseEcdsaPublicKey(cose); case 3: - // COSE-JAVA supports RSA in v1.1.0 but not in v1.0.0 return importCoseRsaPublicKey(cose); default: throw new IllegalArgumentException("Unsupported key type: " + kty); From fefbfd3161acf9620d7f19932a905c210d2a8301 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 19 Feb 2024 15:55:45 +0100 Subject: [PATCH 09/12] Run mutation test workflow on release-* branches But still update the badge and previous result only on the main branch. --- .github/workflows/coverage.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index e2bbe639e..fbdaee05c 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -3,7 +3,9 @@ name: Test coverage on: push: - branches: [main] + branches: + - main + - 'release-*' jobs: test: @@ -45,6 +47,7 @@ jobs: sed "s/{shortcommit}/${GITHUB_SHA:0:8}/g;s/{commit}/${GITHUB_SHA}/g;s#{repo}#${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}#g" .github/workflows/coverage/index.html.template > build/gh-pages/index.html - name: Create coverage badge + if: ${{ github.ref == 'refs/heads/main' }} # This creates a file that defines a [Shields.io endpoint badge](https://shields.io/endpoint) # which we can then include in the project README. uses: ./.github/actions/pit-results-badge @@ -69,6 +72,7 @@ jobs: prev-mutations-file: prev-mutations.xml - name: Push to GitHub Pages + if: ${{ github.ref == 'refs/heads/main' }} run: | git config user.name github-actions git config user.email github-actions@github.com From eb37b615465a881405620602f5029a4601485f28 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Mon, 4 Mar 2024 16:56:56 +0100 Subject: [PATCH 10/12] Exclude Jackson 2.17.0-rc1 from dependency resolution - See: https://github.com/Yubico/java-webauthn-server/issues/350 - See: https://github.com/FasterXML/jackson-databind/issues/4413 --- NEWS | 2 ++ settings.gradle.kts | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index b5f91702b..2c7819928 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,8 @@ Changes: * Dropped dependency on COSE-Java. +* Excluded Jackson version 2.17.0-rc1 from dependency resolution due to an + incompatible regression. == Version 2.5.0 == diff --git a/settings.gradle.kts b/settings.gradle.kts index 83a4d55e2..7fc6b7898 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,7 +19,10 @@ dependencyResolutionManagement { library("httpclient5", "org.apache.httpcomponents.client5:httpclient5:[5.0.0,6)") library("slf4j", "org.slf4j:slf4j-api:[1.7.25,3)") - val jacksonVer = version("jackson", "[2.13.2.1,3)") + val jacksonVer = version("jackson") { + require("[2.13.2.1,3)") + reject("2.17.0-rc1") // Regression: https://github.com/FasterXML/jackson-databind/issues/4413 + } library("jackson-bom", "com.fasterxml.jackson", "jackson-bom").versionRef(jacksonVer) library("jackson-databind", "com.fasterxml.jackson.core", "jackson-databind").versionRef(jacksonVer) library("jackson-dataformat-cbor", "com.fasterxml.jackson.dataformat", "jackson-dataformat-cbor").versionRef(jacksonVer) From c5a18afc431672ad9830df7817574f4d09853ef3 Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2024 07:36:14 +0100 Subject: [PATCH 11/12] Fix incompatibility with Jackson 2.17.0-rc1 `@JsonSerialize(contentConverter = ...)` is incompatible with property type `Optional>`, which is the detected serialization type because of the auto-detected getter, because `contentConverter` only descends one container level. See: https://github.com/FasterXML/jackson-databind/issues/4413#issuecomment-1977989776 --- NEWS | 3 +-- settings.gradle.kts | 5 +---- .../java/com/yubico/fido/metadata/MetadataBLOBHeader.java | 4 ++++ 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 2c7819928..824fa647b 100644 --- a/NEWS +++ b/NEWS @@ -3,8 +3,7 @@ Changes: * Dropped dependency on COSE-Java. -* Excluded Jackson version 2.17.0-rc1 from dependency resolution due to an - incompatible regression. +* Fixed incompatibility with Jackson version 2.17.0-rc1. == Version 2.5.0 == diff --git a/settings.gradle.kts b/settings.gradle.kts index 7fc6b7898..83a4d55e2 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,10 +19,7 @@ dependencyResolutionManagement { library("httpclient5", "org.apache.httpcomponents.client5:httpclient5:[5.0.0,6)") library("slf4j", "org.slf4j:slf4j-api:[1.7.25,3)") - val jacksonVer = version("jackson") { - require("[2.13.2.1,3)") - reject("2.17.0-rc1") // Regression: https://github.com/FasterXML/jackson-databind/issues/4413 - } + val jacksonVer = version("jackson", "[2.13.2.1,3)") library("jackson-bom", "com.fasterxml.jackson", "jackson-bom").versionRef(jacksonVer) library("jackson-databind", "com.fasterxml.jackson.core", "jackson-databind").versionRef(jacksonVer) library("jackson-dataformat-cbor", "com.fasterxml.jackson.dataformat", "jackson-dataformat-cbor").versionRef(jacksonVer) diff --git a/webauthn-server-attestation/src/main/java/com/yubico/fido/metadata/MetadataBLOBHeader.java b/webauthn-server-attestation/src/main/java/com/yubico/fido/metadata/MetadataBLOBHeader.java index 116095dc7..0a4689011 100644 --- a/webauthn-server-attestation/src/main/java/com/yubico/fido/metadata/MetadataBLOBHeader.java +++ b/webauthn-server-attestation/src/main/java/com/yubico/fido/metadata/MetadataBLOBHeader.java @@ -1,5 +1,6 @@ package com.yubico.fido.metadata; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.net.URL; @@ -86,6 +87,9 @@ public Optional getX5u() { * @see RFC 7515 ยง4.1.6. * "x5c" (X.509 Certificate Chain) Header Parameter */ + // @JsonIgnore needed because of: + // https://github.com/FasterXML/jackson-databind/issues/4413#issuecomment-1977989776 + @JsonIgnore public Optional> getX5c() { return Optional.ofNullable(x5c); } From cdf95131266e9d89bed3df9c52644b06306e1cea Mon Sep 17 00:00:00 2001 From: Emil Lundberg Date: Tue, 5 Mar 2024 08:52:00 +0100 Subject: [PATCH 12/12] Drop slf4j-test from webauthn-server-attestation test dependencies This prevents the unit test XML reports from containing large stdout logs which are not used for anything but crash the default settings of EnricoMi/publish-unit-test-result-action@v2 . --- webauthn-server-attestation/build.gradle.kts | 7 +------ .../src/test/resources/slf4jtest.properties | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 webauthn-server-attestation/src/test/resources/slf4jtest.properties diff --git a/webauthn-server-attestation/build.gradle.kts b/webauthn-server-attestation/build.gradle.kts index 9535ce0f1..1748835d2 100644 --- a/webauthn-server-attestation/build.gradle.kts +++ b/webauthn-server-attestation/build.gradle.kts @@ -47,13 +47,8 @@ dependencies { testImplementation("org.scalatest:scalatest_2.13") testImplementation("org.scalatestplus:junit-4-13_2.13") testImplementation("org.scalatestplus:scalacheck-1-16_2.13") - testImplementation("uk.org.lidalia:slf4j-test") - testImplementation("org.slf4j:slf4j-api") { - version { - strictly("[1.7.25,1.8-a)") // Pre-1.8 version required by slf4j-test - } - } + testImplementation("org.slf4j:slf4j-api") } val integrationTest = task("integrationTest") { diff --git a/webauthn-server-attestation/src/test/resources/slf4jtest.properties b/webauthn-server-attestation/src/test/resources/slf4jtest.properties deleted file mode 100644 index eacb68e5f..000000000 --- a/webauthn-server-attestation/src/test/resources/slf4jtest.properties +++ /dev/null @@ -1 +0,0 @@ -print.level=DEBUG