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..b96651a86ed 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,11 +85,14 @@ 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())) { - return token.getJWTClaimsSet(); + // symmetric signature check: create internal signature and compare if matches the signature from token, using a constant-time comparison + if (SUPPORTED_ALGORITHMS.contains(header.getAlgorithm())) { + Base64URL expectedSignature = internal.sign(header, token.getSigningInput()); + if (MessageDigest.isEqual(token.getSignature().decode(), expectedSignature.decode())) { + return token.getJWTClaimsSet(); + } } - throw new InvalidSignatureException("HMAC not mached"); + throw new InvalidSignatureException("HMAC not matched"); } catch (ParseException | JOSEException e) { throw new InvalidSignatureException("Invalid signed token", e); } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/ldap/PasswordComparisonAuthenticator.java b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/ldap/PasswordComparisonAuthenticator.java index c16844f4403..738358440fd 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/ldap/PasswordComparisonAuthenticator.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/ldap/PasswordComparisonAuthenticator.java @@ -34,7 +34,7 @@ import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; -import java.util.Arrays; +import java.security.MessageDigest; import java.util.function.Supplier; /** @@ -117,7 +117,7 @@ public DirContextOperations localCompareAuthenticate(DirContextOperations user, } else { String encodedPassword = passwordEncoder.encode(password); byte[] passwordBytes = Utf8.encode(encodedPassword); - match = Arrays.equals(passwordBytes, valBytes); + match = MessageDigest.isEqual(passwordBytes, valBytes); } } } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/oauth/ExternalOAuthAuthenticationManager.java b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/oauth/ExternalOAuthAuthenticationManager.java index 9ec2c1d1025..2ffcb898f71 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/oauth/ExternalOAuthAuthenticationManager.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/oauth/ExternalOAuthAuthenticationManager.java @@ -98,6 +98,7 @@ import java.net.URISyntaxException; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -658,13 +659,20 @@ protected > Map it.get("algorithm")) .orElse(null); - if (algorithm != null && !"HMAC-SHA256".equals(algorithm)) { - log.debug("Unknown algorithm was used to sign request! No claims returned."); + if (!"HMAC-SHA256".equals(algorithm)) { + log.debug("Missing or unknown algorithm was used to sign request! No claims returned."); return null; } - //check if data is signed correctly - if (!hmacSignAndEncode(signedRequests[1], secret).equals(signature)) { - log.debug("Signature is not correct, possibly the data was tampered with! No claims returned."); + // check if data is signed correctly using constant-time comparison + try { + byte[] expectedMac = Base64.decodeBase64(hmacSignAndEncode(signedRequests[1], secret)); + byte[] suppliedMac = Base64.decodeBase64(signature); + if (!MessageDigest.isEqual(expectedMac, suppliedMac)) { + log.debug("Signature is not correct, possibly the data was tampered with! No claims returned."); + return null; + } + } catch (Exception _) { + log.debug("Failed to validate signature due to encoding or computation error! No claims returned."); return null; } return jsonData;