From 2f124bbc17b3434b3e42f110c56a60806794230b Mon Sep 17 00:00:00 2001 From: Mart Somermaa Date: Fri, 22 Mar 2024 19:10:05 +0200 Subject: [PATCH] Update JJWT to version 0.12 and use Jackson ObjectReader, update other dependencies Note that JJWT 0.12 API is not compatible with 0.11, so this was a non-trivial upgrade. Signed-off-by: Mart Somermaa --- pom.xml | 14 +++---- .../AuthTokenSignatureValidator.java | 38 +++++++++--------- .../validator/AuthTokenValidatorImpl.java | 5 ++- .../AuthTokenSignatureValidatorTest.java | 9 +++-- .../ocsp_response_with_2_responses.der | Bin 267 -> 3102 bytes 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/pom.xml b/pom.xml index b618f740..97417c01 100644 --- a/pom.xml +++ b/pom.xml @@ -12,13 +12,13 @@ 11 - 0.11.5 - 1.76 - 2.15.2 - 2.0.5 - 5.9.2 - 3.24.2 - 5.2.0 + 0.12.5 + 1.77 + 2.17.0 + 2.0.9 + 5.10.2 + 3.25.3 + 5.11.0 2.22.2 3.3.0 3.6.2 diff --git a/src/main/java/eu/webeid/security/validator/AuthTokenSignatureValidator.java b/src/main/java/eu/webeid/security/validator/AuthTokenSignatureValidator.java index a5e91525..168e2170 100644 --- a/src/main/java/eu/webeid/security/validator/AuthTokenSignatureValidator.java +++ b/src/main/java/eu/webeid/security/validator/AuthTokenSignatureValidator.java @@ -25,11 +25,12 @@ import eu.webeid.security.exceptions.AuthTokenParseException; import eu.webeid.security.exceptions.AuthTokenSignatureValidationException; import eu.webeid.security.exceptions.ChallengeNullOrEmptyException; -import io.jsonwebtoken.SignatureAlgorithm; -import io.jsonwebtoken.impl.crypto.DefaultSignatureValidatorFactory; -import io.jsonwebtoken.impl.crypto.SignatureValidator; -import io.jsonwebtoken.security.SignatureException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.impl.security.DefaultVerifySecureDigestRequest; +import io.jsonwebtoken.security.SignatureAlgorithm; +import io.jsonwebtoken.security.VerifySecureDigestRequest; +import java.io.ByteArrayInputStream; import java.net.URI; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; @@ -73,25 +74,20 @@ public void validate(String algorithm, String signature, PublicKey publicKey, St throw new AuthTokenParseException("Unsupported signature algorithm"); } - SignatureAlgorithm signatureAlgorithm; + final SignatureAlgorithm signatureAlgorithm = (SignatureAlgorithm) Jwts.SIG.get().forKey(algorithm); + if (signatureAlgorithm == null) { + // Should not happen, see ALLOWED_SIGNATURE_ALGORITHMS check above. + throw new AuthTokenParseException("JJWT does not support signature algorithm: " + algorithm); + } MessageDigest hashAlgorithm; try { - signatureAlgorithm = SignatureAlgorithm.forName(algorithm); hashAlgorithm = hashAlgorithmForName(algorithm); - } catch (SignatureException e) { - // Should not happen, see ALLOWED_SIGNATURE_ALGORITHMS check above. - throw new AuthTokenParseException("Invalid signature algorithm", e); } catch (NoSuchAlgorithmException e) { - throw new AuthTokenParseException("Invalid hash algorithm", e); - } - if (signatureAlgorithm == null || signatureAlgorithm == SignatureAlgorithm.NONE) { // Should not happen, see ALLOWED_SIGNATURE_ALGORITHMS check above. - throw new AuthTokenParseException("Invalid signature algorithm"); + throw new AuthTokenParseException("Invalid hash algorithm", e); } Objects.requireNonNull(hashAlgorithm, "hashAlgorithm"); - signatureAlgorithm.assertValidVerificationKey(publicKey); - final SignatureValidator signatureValidator = DefaultSignatureValidatorFactory.INSTANCE - .createSignatureValidator(signatureAlgorithm, publicKey); + final byte[] decodedSignature = decodeBase64(signature); final byte[] originHash = hashAlgorithm.digest(originBytes); @@ -100,9 +96,13 @@ public void validate(String algorithm, String signature, PublicKey publicKey, St // Note that in case of ECDSA, the eID card outputs raw R||S, but JCA's SHA384withECDSA signature // validation implementation requires the signature in DER encoding. - // JJWT's EllipticCurveProvider.transcodeSignatureToDER() internally takes care of transcoding - // raw R||S to DER as needed inside EllipticCurveProvider.isValid(). - if (!signatureValidator.isValid(concatSignedFields, decodedSignature)) { + // JJWT internally takes care of transcoding raw R||S to DER as needed. + final VerifySecureDigestRequest verificationRequest = + new DefaultVerifySecureDigestRequest<>( + new ByteArrayInputStream(concatSignedFields), + null, null, + publicKey, decodedSignature); + if (!signatureAlgorithm.verify(verificationRequest)) { throw new AuthTokenSignatureValidationException(); } } diff --git a/src/main/java/eu/webeid/security/validator/AuthTokenValidatorImpl.java b/src/main/java/eu/webeid/security/validator/AuthTokenValidatorImpl.java index cd2308c2..7e5cbbbf 100644 --- a/src/main/java/eu/webeid/security/validator/AuthTokenValidatorImpl.java +++ b/src/main/java/eu/webeid/security/validator/AuthTokenValidatorImpl.java @@ -23,6 +23,7 @@ package eu.webeid.security.validator; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; import eu.webeid.security.authtoken.WebEidAuthToken; import eu.webeid.security.certificate.CertificateLoader; import eu.webeid.security.certificate.CertificateValidator; @@ -57,7 +58,7 @@ final class AuthTokenValidatorImpl implements AuthTokenValidator { private static final int TOKEN_MAX_LENGTH = 10000; private static final Logger LOG = LoggerFactory.getLogger(AuthTokenValidatorImpl.class); - private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final ObjectReader OBJECT_READER = new ObjectMapper().readerFor(WebEidAuthToken.class); private final AuthTokenValidationConfiguration configuration; private final SubjectCertificateValidatorBatch simpleSubjectCertificateValidators; @@ -138,7 +139,7 @@ private void validateTokenLength(String authToken) throws AuthTokenParseExceptio private WebEidAuthToken parseToken(String authToken) throws AuthTokenParseException { try { - final WebEidAuthToken token = objectMapper.readValue(authToken, WebEidAuthToken.class); + final WebEidAuthToken token = OBJECT_READER.readValue(authToken); if (token == null) { throw new AuthTokenParseException("Web eID authentication token is null"); } diff --git a/src/test/java/eu/webeid/security/validator/AuthTokenSignatureValidatorTest.java b/src/test/java/eu/webeid/security/validator/AuthTokenSignatureValidatorTest.java index 4e07d8a8..cb29e921 100644 --- a/src/test/java/eu/webeid/security/validator/AuthTokenSignatureValidatorTest.java +++ b/src/test/java/eu/webeid/security/validator/AuthTokenSignatureValidatorTest.java @@ -23,6 +23,7 @@ package eu.webeid.security.validator; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; import eu.webeid.security.certificate.CertificateLoader; import org.junit.jupiter.api.Test; import eu.webeid.security.authtoken.WebEidAuthToken; @@ -36,9 +37,9 @@ class AuthTokenSignatureValidatorTest { - private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final ObjectReader OBJECT_READER = new ObjectMapper().readerFor(WebEidAuthToken.class); - static String VALID_RS256_AUTH_TOKEN = "{\"algorithm\":\"RS256\"," + + private static final String VALID_RS256_AUTH_TOKEN = "{\"algorithm\":\"RS256\"," + "\"unverifiedCertificate\":\"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\"," + "\"issuerApp\":\"https://web-eid.eu/web-eid-app/releases/2.0.0+0\"," + "\"signature\":\"xsjXsQvVYXWcdV0YPhxLthJxtf0//R8p9WFFlYJGRARrl1ruyoAUwl0xeHgeZOKeJtwiCYCNWJzCG3VM3ydgt92bKhhk1u0JXIPVqvOkmDY72OCN4q73Y8iGSPVTgjk93TgquHlodf7YcqZNhutwNNf3oldHEWJD5zmkdwdpBFXgeOwTAdFwGljDQZbHr3h1Dr+apUDuloS0WuIzUuu8YXN2b8lh8FCTlF0G0DEjhHd/MGx8dbe3UTLHmD7K9DXv4zLJs6EF9i2v/C10SIBQDkPBSVPqMxCDPECjbEPi2+ds94eU7ThOhOQlFFtJ4KjQNTUa2crSixH7cYZF2rNNmA==\"," + @@ -49,7 +50,7 @@ void whenValidES384Signature_thenSucceeds() throws Exception { final AuthTokenSignatureValidator signatureValidator = new AuthTokenSignatureValidator(URI.create("https://ria.ee")); - final WebEidAuthToken authToken = objectMapper.readValue(VALID_AUTH_TOKEN, WebEidAuthToken.class); + final WebEidAuthToken authToken = OBJECT_READER.readValue(VALID_AUTH_TOKEN); final X509Certificate x509Certificate = CertificateLoader.decodeCertificateFromBase64(authToken.getUnverifiedCertificate()); assertThatCode(() -> signatureValidator @@ -62,7 +63,7 @@ void whenValidRS256Signature_thenSucceeds() throws Exception { final AuthTokenSignatureValidator signatureValidator = new AuthTokenSignatureValidator(URI.create("https://ria.ee")); - final WebEidAuthToken authToken = objectMapper.readValue(VALID_RS256_AUTH_TOKEN, WebEidAuthToken.class); + final WebEidAuthToken authToken = OBJECT_READER.readValue(VALID_RS256_AUTH_TOKEN); final X509Certificate x509Certificate = CertificateLoader.decodeCertificateFromBase64(authToken.getUnverifiedCertificate()); assertThatCode(() -> signatureValidator diff --git a/src/test/resources/ocsp_response_with_2_responses.der b/src/test/resources/ocsp_response_with_2_responses.der index 387b8aabda6b4befb8d3194ab1112cf9563d39c5..6afe6640d2afa9ed4f2463429864f729a562b9ae 100644 GIT binary patch literal 3102 zcmeH|YfKzf6oBW>+?{;`WtVp-yDnf@!g6MI2rPw4fh`4;C`*9?(jafeE{~;)8e15e zrAb>#vD#wMt`r;X>z5+7hcT7LNOgu+c1-H8CjQ~a%$#q| zx%b?A&OPS>uL)Nn!pm!Pz-#=2DH!&GW!SX9+s$Y&qenZ9sO?h+U3hwKXGIr zZnEI~4wCz0U{O^}DB^a$MF!X!(Z05<*w@Q%l(;Le507^ePjclAeUj$?Ux1ocnmv0w z%UXnFl#CD~=H*pi0g3CE-h6DF$5Ltr$O66So6H=Ex5@J2_0^RtYV&a4A> z*bic!|FoxNuxvWgzIcDOhL4yU)z;kMJ~>yKeJ}4L`MXWS$rqin?r2@#KGbVkN%$eZ zqItyBaqIfB?xZ^@qIM`^cs}Q2MG$?eWG+0vKsK^8y@w4-(=-1_&)qJ+)s}=4%M2ZG}I2h}{ zztX(0|Iqm9N8Vq?bB4a*uD)*$1V2&jkI>&33z?=NP-LCR3ZR7#iG-p;UyFYYm`9TW zOn`!>F>&%up@x*S923WuG6a#O)j};|)P2f`5CRhzX~kM`k|;Q+!R2ahOHE94yWN(y z*DSTQiCHf?K`ms->urqE?E2QuLQ%fE2e$ zF;I#+De8St2+qG^<-1=&>$_h8eM2W84Q4T&F=CPpuze#-lyXxdHzf?OZpgy4l~4h3 z8w|)3DP~njYE@&^dQxj^6Y8A@tE*NkC~?!2^qAI7tJe*Ei`-IE+iIz9bwTLH07PL8 zsMgL|?{48JfVko)90$)rjMwBfdZPYozUtN{-v&i>9VejcD49w8IJP?_a%R4%uz&7_ zp8DH{*3wY-j+{%%?BwW~&s$Pm6E6+M-Ysm{r69Por+b{n+~1t9^o{mU-@n)Q4tIn} zH8L(S$CWhiIT9*>u|zr592w_58~YZWeut=77JL2k9yr_@^i0SdzADgXcg literal 267 zcmXqLVr1uHWLVI|$Y9X;myJ`Kjggg=-GGsirSZK%;~Rs