diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/oauth/jwt/UaaMacSigner.java b/server/src/main/java/org/cloudfoundry/identity/uaa/oauth/jwt/UaaMacSigner.java index e95447cd7b7..b32fcfc0a80 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/oauth/jwt/UaaMacSigner.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/oauth/jwt/UaaMacSigner.java @@ -18,6 +18,7 @@ import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; import java.text.ParseException; import java.util.Collections; import java.util.LinkedHashSet; @@ -84,8 +85,10 @@ public static JWTClaimsSet verify(String jwToken, JWKSet jwkSet) { String kid = header.getKeyID(); JWK jwKey = jwkSet.getKeys().stream().filter(e -> kid.equals(e.getKeyID())).findFirst().orElseThrow(); UaaMacSigner internal = new UaaMacSigner((String) jwKey.toJSONObject().get(JWKParameterNames.OCT_KEY_VALUE)); - // symmetric signature check: create internal signature and compare if matches the signature from token - if (token.getSignature().equals(internal.sign(header, token.getSigningInput())) && SUPPORTED_ALGORITHMS.contains(header.getAlgorithm())) { + // symmetric signature check: create internal signature and compare if matches the signature from token, + // using a constant-time comparison to avoid leaking timing information about the expected HMAC + Base64URL expectedSignature = internal.sign(header, token.getSigningInput()); + if (MessageDigest.isEqual(token.getSignature().decode(), expectedSignature.decode()) && SUPPORTED_ALGORITHMS.contains(header.getAlgorithm())) { return token.getJWTClaimsSet(); } throw new InvalidSignatureException("HMAC not mached");