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 387b8aab..6afe6640 100644 Binary files a/src/test/resources/ocsp_response_with_2_responses.der and b/src/test/resources/ocsp_response_with_2_responses.der differ