[java-oidc-common] 27/35: Relax algorithm check on credentials and JSON web keys
Phil Smart
philip.smart at jisc.ac.uk
Tue Sep 20 14:19:27 UTC 2022
This is an automated email from the git hooks/post-receive script.
philsmart pushed a commit to branch dev/JCOMOIDC-41
in repository java-oidc-common.
View the commit online:
http://git.shibboleth.net/view/?p=java-oidc-common.git;a=commit;h=d396c37562b20b5dba245664b1fea4e85ae1fa1c
commit d396c37562b20b5dba245664b1fea4e85ae1fa1c
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Aug 19 14:20:12 2022 +0100
Relax algorithm check on credentials and JSON web keys
- As 'alg' is optional in the JWK spec. the credential to algorithm
matching must be relaxed to only use key type if 'alg' is not present.
- As 'use' is optional in the JWK spec. the use type of UNSPECIFIED
must also be allowed alongside ENCRYPTION
---
.../impl/BasicJWTEncryptionParametersResolver.java | 37 ++++++++-
...oviderMetadataEncryptionParametersResolver.java | 96 ++++++++++++++++++++--
.../BasicJWTEncryptionParametersResolverTest.java | 93 +++++++++++++++++++--
...erMetadataEncryptionParametersResolverTest.java | 93 ++++++++++++++++++++-
...ider-resolver-remote-jwkset-response-no-alg.jwk | 4 +-
...-resolver-remote-jwkset-response-no-keyuse.jwk} | 5 +-
...olver-remote-jwkset-response-wrong-key-use.jwk} | 6 +-
7 files changed, 301 insertions(+), 33 deletions(-)
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolver.java
index 93e1ce0..2f648fc 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolver.java
@@ -43,6 +43,7 @@ import org.slf4j.LoggerFactory;
import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.EncryptionMethod;
import com.nimbusds.jose.JWEAlgorithm;
+import com.nimbusds.jose.jwk.KeyType;
import net.shibboleth.oidc.security.JWTEncryptionConfiguration;
import net.shibboleth.oidc.security.JWTEncryptionParameters;
@@ -423,7 +424,8 @@ public class BasicJWTEncryptionParametersResolver extends AbstractSecurityParame
* <li>The credential must be a {@link JWKCredential}</li>
* <li>The credential must have a {@link UsageType} of {@link UsageType#ENCRYPTION}
* or {@link UsageType#UNSPECIFIED}</li>
- * <li>The credentials algorithm must match to one of the input key transport algorithms</li>
+ * <li>If the credentials JWEAlgorithm is present, the credential's algorithm must match to the
+ * input JWEAlgorithm. Else, the key's algorithm must match the JWE algorithm family.</li>
* <li>The credential's key must match the keylength required by that algorithm</li>
* </ol>
*
@@ -443,11 +445,41 @@ public class BasicJWTEncryptionParametersResolver extends AbstractSecurityParame
.filter(JWKCredential.class::isInstance)
.filter(k -> UsageType.ENCRYPTION == k.getUsageType() || UsageType.UNSPECIFIED == k.getUsageType())
.map(JWKCredential.class::cast)
- .filter(k -> algorithm.equals(k.getAlgorithm()))
+ .filter(k -> checkKeyWithAlgorithm(k, algorithm))
.filter(k -> checkKeyAlgorithmAndLength(k, algorithm.getName()))
.findFirst().orElse(null);
}
+ /**
+ * Check the credential supports the algorithm specified. If the algorithm is present, check that is
+ * identical to the algorithm supplied. If not, check key algorithm is compatible with the algorithm
+ * family.
+ *
+ * @param credential the credential to check
+ * @param algorithm the algorithm to check compatibility with
+ * @return true of the key is compatible with the algorithm, false otherwise
+ */
+ private boolean checkKeyWithAlgorithm(
+ @Nonnull final JWKCredential credential, @Nonnull final JWEAlgorithm algorithm) {
+
+ if (credential.getAlgorithm() != null) {
+ // Have algorithm, so that must match exactly
+ return algorithm.equals(credential.getAlgorithm());
+ }
+ // Else check key type
+ final Key key = CredentialSupport.extractEncryptionKey(credential);
+
+ if (JWEAlgorithm.Family.RSA.contains(algorithm) && key.getAlgorithm().equals("RSA")) {
+ return true;
+ } else if (JWEAlgorithm.Family.ECDH_ES.contains(algorithm) && key.getAlgorithm().equals("EC")) {
+ return true;
+ } else if (JWEAlgorithm.Family.SYMMETRIC.contains(algorithm) && key.getAlgorithm().equals("AES")) {
+ return true;
+ }
+ return false;
+
+ }
+
/**
* Find an encryption method that is supported by the credential. That is, supports the algorithm and
* has the correct key length.
@@ -643,6 +675,7 @@ public class BasicJWTEncryptionParametersResolver extends AbstractSecurityParame
return AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(algorithm));
}
+
/**
* Evaluate whether the specified algorithm is a key encryption or key wrapping algorithm.
*
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ProviderMetadataEncryptionParametersResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ProviderMetadataEncryptionParametersResolver.java
index 6b2184e..d4df4ee 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ProviderMetadataEncryptionParametersResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/ProviderMetadataEncryptionParametersResolver.java
@@ -17,6 +17,7 @@
package net.shibboleth.oidc.security.impl;
+import java.security.Key;
import java.time.Duration;
import java.time.Instant;
import java.util.Collections;
@@ -29,6 +30,8 @@ import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.opensaml.security.credential.UsageType;
+import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,7 +42,6 @@ import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.KeyType;
-import com.nimbusds.jose.jwk.KeyUse;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.openid.connect.sdk.op.OIDCProviderMetadata;
@@ -50,6 +52,7 @@ import net.shibboleth.oidc.security.credential.BasicJWKCredential;
import net.shibboleth.oidc.security.criterion.JWKSetCriterion;
import net.shibboleth.oidc.security.criterion.JWTEncryptionConfigurationCriterion;
import net.shibboleth.oidc.security.criterion.ProviderMetadataCriterion;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.annotation.constraint.Positive;
import net.shibboleth.utilities.java.support.logic.Constraint;
import net.shibboleth.utilities.java.support.logic.FunctionSupport;
@@ -270,8 +273,10 @@ public class ProviderMetadataEncryptionParametersResolver extends BasicJWTEncryp
final JWK key =
providerKeySet.getKeys().stream()
.filter(Objects::nonNull)
- .filter(k -> KeyUse.ENCRYPTION == k.getKeyUse())
- .filter(k -> k.getAlgorithm().equals(algorithm))
+ .filter(k -> UsageType.ENCRYPTION == CredentialConversionUtil.getUsageType(k)
+ || UsageType.UNSPECIFIED == CredentialConversionUtil.getUsageType(k))
+ .filter(k -> checkKeyAlgorithmAndLength(k, algorithm.getName()))
+ .filter(k -> checkKeyTypeWithAlgorithm(k, algorithm))
.findFirst().orElse(null);
if (key != null) {
@@ -288,13 +293,86 @@ public class ProviderMetadataEncryptionParametersResolver extends BasicJWTEncryp
log.warn("Unable to parse keyset", e);
return;
}
- if (checkKeyAlgorithmAndLength(jwkCredential, algorithm.getName())) {
- log.debug("Selected key '{}' for alg {} and enc {}", key.getKeyID(),
- algorithm.getName(), encryptionMethod.getName());
- params.setKeyTransportEncryptionCredential(jwkCredential);
- params.setKeyTransportEncryptionAlgorithm(algorithm.getName());
- params.setDataEncryptionAlgorithm(encryptionMethod.getName());
+ log.debug("Selected key '{}' for alg {} and enc {}", key.getKeyID(),
+ algorithm.getName(), encryptionMethod.getName());
+ params.setKeyTransportEncryptionCredential(jwkCredential);
+ params.setKeyTransportEncryptionAlgorithm(algorithm.getName());
+ params.setDataEncryptionAlgorithm(encryptionMethod.getName());
+
+ }
+
+ }
+
+ /**
+ * Check the JWK supports the algorithm specified. If 'alg' is present, check that is identical to the
+ * supplied algorithm. If not, check the 'kty' or key type parameter of the JWK is compatible with the
+ * algorithm family.
+ *
+ * @param jwk the JSON web key
+ * @param algorithm the algorithm to check compatibility with
+ *
+ * @return true of the key is compatible with the algorithm, false otherwise
+ */
+ private boolean checkKeyTypeWithAlgorithm(@Nonnull final JWK jwk, @Nonnull final JWEAlgorithm algorithm) {
+ if (jwk.getAlgorithm() != null) {
+ // Have algorithm, so that must match exactly
+ return algorithm.equals(jwk.getAlgorithm());
+ }
+ if (JWEAlgorithm.Family.RSA.contains(algorithm) && jwk.getKeyType().equals(KeyType.RSA)) {
+ return true;
+ } else if (JWEAlgorithm.Family.ECDH_ES.contains(algorithm) && jwk.getKeyType().equals(KeyType.EC)) {
+ return true;
+ } else if (JWEAlgorithm.Family.SYMMETRIC.contains(algorithm) && jwk.getKeyType().equals(KeyType.OCT)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Evaluate whether the specified JWK key is supported for use with the specified algorithm URI
+ * and the key length matches.
+ *
+ * @param jwkKey the JWK to evaluate
+ * @param algorithm the algorithm URI to evaluate against
+ *
+ * @return true if credential may be used with the supplied algorithm URI and the key length matches,
+ * false otherwise
+ */
+ private boolean checkKeyAlgorithmAndLength(@Nonnull final JWK jwk,
+ @Nonnull @NotEmpty final String algorithm) {
+
+ final Key key = extractEncryptionKeyFromJWK(jwk);
+ if (key == null) {
+ return false;
+ }
+
+ return AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(algorithm));
+ }
+
+ /**
+ * Extract the encryption key from the JWK.
+ *
+ * @param jwk the JWK containing the encryption key
+ * @return the encryption key (either a public key or a secret (symmetric) key
+ */
+ @Nullable private Key extractEncryptionKeyFromJWK(@Nullable final JWK jwk) {
+ if (jwk == null) {
+ return null;
+ }
+ try {
+ if (jwk.getKeyType() == KeyType.EC) {
+ return jwk.toECKey().toPublicKey();
+ } else if (jwk.getKeyType() == KeyType.RSA) {
+ return jwk.toRSAKey().toPublicKey();
+ } else if (jwk.getKeyType() == KeyType.OCT) {
+ return jwk.toOctetSequenceKey().toSecretKey();
+ } else {
+ return null;
}
+ //TODO support for OKP
+ } catch (final JOSEException e) {
+ log.trace("Unable to extract encryption key from JWK '{}'", jwk.getKeyID());
+ return null;
}
}
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolverTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolverTest.java
index ceb9014..25c83b1 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolverTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolverTest.java
@@ -24,19 +24,13 @@ import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
-import java.security.KeyException;
-import java.time.Duration;
import java.util.List;
import org.opensaml.core.config.InitializationException;
-import org.opensaml.security.credential.UsageType;
-import org.opensaml.security.crypto.KeySupport;
import org.opensaml.xmlsec.config.GlobalAlgorithmRegistryInitializer;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import com.nimbusds.jose.Algorithm;
-import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWEAlgorithm;
import com.nimbusds.jose.jwk.Curve;
import com.nimbusds.jose.jwk.ECKey;
@@ -48,7 +42,7 @@ import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
import net.shibboleth.oidc.jwa.support.EncryptionConstants;
import net.shibboleth.oidc.jwa.support.KeyManagementConstants;
import net.shibboleth.oidc.security.JWTEncryptionParameters;
-import net.shibboleth.oidc.security.credential.BasicExpiringJWKCredential;
+import net.shibboleth.oidc.security.credential.BasicJWKCredential;
import net.shibboleth.oidc.security.credential.JWKCredential;
import net.shibboleth.oidc.security.criterion.JWTEncryptionConfigurationCriterion;
import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
@@ -107,6 +101,32 @@ public class BasicJWTEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256);
assertNotNull(param.getKeyTransportEncryptionCredential());
assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
+
+ }
+
+ @Test
+ public void testBasicRSA_NoAlgorithmSpecifiedInJWKCredential() throws Exception {
+ final CriteriaSet criteria = buildBasicCriteriaSet();
+ final RSAKey key = new RSAKeyGenerator(2048)
+ .algorithm(JWEAlgorithm.RSA_OAEP_256)
+ .keyUse(KeyUse.ENCRYPTION)
+ .keyID("mock-key")
+ .generate();
+ final JWKCredential cred = TestCredentialHelper.createKeyEncryptionCredential(key);
+ // Blank algorithm, this should work on the 'key algorithm' alone
+ ((BasicJWKCredential)cred).setAlgorithm(null);
+ config.setKeyTransportEncryptionCredentials(List.of(cred));
+ final JWTEncryptionParameters param = resolver.resolveSingle(criteria);
+
+ assertNotNull(param);
+ assertNotNull(param.getDataEncryptionAlgorithm());
+ assertNotNull(param.getKeyTransportEncryptionAlgorithm());
+ assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256);
+ assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256);
+ assertNotNull(param.getKeyTransportEncryptionCredential());
+ assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
}
@@ -130,6 +150,36 @@ public class BasicJWTEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_ECDH_ES);
assertNotNull(param.getKeyTransportEncryptionCredential());
assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"EC");
+
+ }
+
+ @Test
+ public void testBasicEC_NoAlgorithmSpecifiedInJWKCredential() throws Exception {
+ final CriteriaSet criteria = buildBasicCriteriaSet();
+ config.setKeyTransportEncryptionAlgorithms(
+ List.of(KeyManagementConstants.ALGO_ID_ALG_ECDH_ES));
+ final ECKey key = new ECKeyGenerator(Curve.P_256)
+ .keyUse(KeyUse.ENCRYPTION)
+ .algorithm(JWEAlgorithm.ECDH_ES)
+ .keyID("mock-key")
+ .generate();
+
+ final JWKCredential cred = TestCredentialHelper.createKeyAgreementCredential(key);
+ ((BasicJWKCredential)cred).setAlgorithm(null);
+ config.setKeyTransportEncryptionCredentials(List.of(cred));
+
+ config.setKeyTransportEncryptionCredentials(List.of(cred));
+ final JWTEncryptionParameters param = resolver.resolveSingle(criteria);
+
+ assertNotNull(param);
+ assertNotNull(param.getDataEncryptionAlgorithm());
+ assertNotNull(param.getKeyTransportEncryptionAlgorithm());
+ assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256);
+ assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_ECDH_ES);
+ assertNotNull(param.getKeyTransportEncryptionCredential());
+ assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"EC");
}
@@ -149,6 +199,32 @@ public class BasicJWTEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_AES_256_KW);
assertNotNull(param.getKeyTransportEncryptionCredential());
assertNotNull(param.getKeyTransportEncryptionCredential().getSecretKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getSecretKey().getAlgorithm(),"AES");
+
+ }
+
+ @Test
+ public void testBasicAESKeyWrap_NoAlgorithmSpecifiedInJWKCredential() throws Exception {
+ final CriteriaSet criteria = buildBasicCriteriaSet();
+ config.setKeyTransportEncryptionAlgorithms(
+ List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));
+
+ final JWKCredential cred = TestCredentialHelper.createSharedSecretCredential("mock-key",
+ SYMMETRIC_KEY, JWEAlgorithm.A256KW);
+ // Blank algorithm, this should work on the 'key algorithm' alone
+ ((BasicJWKCredential)cred).setAlgorithm(null);
+
+ config.setKeyTransportEncryptionCredentials(List.of(cred));
+ final JWTEncryptionParameters param = resolver.resolveSingle(criteria);
+
+ assertNotNull(param);
+ assertNotNull(param.getDataEncryptionAlgorithm());
+ assertNotNull(param.getKeyTransportEncryptionAlgorithm());
+ assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256);
+ assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_AES_256_KW);
+ assertNotNull(param.getKeyTransportEncryptionCredential());
+ assertNotNull(param.getKeyTransportEncryptionCredential().getSecretKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getSecretKey().getAlgorithm(),"AES");
}
@@ -169,6 +245,7 @@ public class BasicJWTEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_DIR);
assertNotNull(param.getDataEncryptionCredential());
assertNotNull(param.getDataEncryptionCredential().getSecretKey());
+ assertEquals(param.getDataEncryptionCredential().getSecretKey().getAlgorithm(),"AES");
}
@@ -189,6 +266,7 @@ public class BasicJWTEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_DIR);
assertNotNull(param.getDataEncryptionCredential());
assertNotNull(param.getDataEncryptionCredential().getSecretKey());
+ assertEquals(param.getDataEncryptionCredential().getSecretKey().getAlgorithm(),"AES");
}
/* The key is 256bit and does not support the 128bit enc. algo.*/
@@ -254,6 +332,7 @@ public class BasicJWTEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256);
assertNotNull(param.getKeyTransportEncryptionCredential());
assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
}
@Test
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ProviderMetadataEncryptionParametersResolverTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ProviderMetadataEncryptionParametersResolverTest.java
index 4d74ec7..7678d84 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ProviderMetadataEncryptionParametersResolverTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ProviderMetadataEncryptionParametersResolverTest.java
@@ -83,6 +83,14 @@ public class ProviderMetadataEncryptionParametersResolverTest {
private static final ClassPathResource REMOTE_JWKSET_NO_ALG_PARAM =
new ClassPathResource("/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk");
+ /** A remote JWKSet with no 'alg' parameters.*/
+ private static final ClassPathResource REMOTE_JWKSET_NO_KEY_USE =
+ new ClassPathResource("/credentials/test-provider-resolver-remote-jwkset-response-no-keyuse.jwk");
+
+ /** A remote JWKSet where key 87ff206d-15f9-4b8c-ba88-a8c17014da13 has the wrong key use.*/
+ private static final ClassPathResource REMOTE_JWKSET_WRONG_KEYUSE =
+ new ClassPathResource("/credentials/test-provider-resolver-remote-jwkset-response-wrong-key-use.jwk");
+
/** The client_secret.*/
private static final String CLIENT_SECRET = "Xp2s5v8y/B?E(H+MbQeThWmYq3t6w9z$";
@@ -98,6 +106,9 @@ public class ProviderMetadataEncryptionParametersResolverTest {
/** The basic config.*/
private BasicJWTEncryptionConfiguration config;
+ /** The cache being used by the resolver.*/
+ private RemoteJwkSetCache cache;
+
/**
* Read a file into a string.
*
@@ -128,7 +139,7 @@ public class ProviderMetadataEncryptionParametersResolverTest {
resolver = new ProviderMetadataEncryptionParametersResolver();
resolver.setProviderEncryptionMethodsLookupStrategy(OIDCProviderMetadata::getRequestObjectJWEEncs);
resolver.setProviderKeyTransportAlgorithmsLookupStrategy(OIDCProviderMetadata::getRequestObjectJWEAlgs);
- final RemoteJwkSetCache cache = new RemoteJwkSetCache();
+ cache = new RemoteJwkSetCache();
cache.setStorage(buildStorageService());
cache.setHttpClient(createMockHttpClient(readJsonFromFile(REMOTE_JWKSET)));
resolver.setRemoteJwkSetCache(cache);
@@ -172,16 +183,44 @@ public class ProviderMetadataEncryptionParametersResolverTest {
final Iterable<JWTEncryptionParameters> params = resolver.resolve(buildBasicCriteriaSet());
assertNotNull(params);
assertTrue(params.iterator().hasNext());
+ }
+
+ /* Algorithms are know because they are limited by config.*/
+ @Test
+ public void testSuccessfulResolution_ForKeyEncryption() throws Exception {
+ final CriteriaSet criteria = buildBasicCriteriaSet();
+ config.setKeyTransportEncryptionAlgorithms(List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP));
+ config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
+
+ final Iterable<JWTEncryptionParameters> params = resolver.resolve(criteria);
+ assertNotNull(params);
+ assertTrue(params.iterator().hasNext());
final JWTEncryptionParameters param = params.iterator().next();
assertNotNull(param.getDataEncryptionAlgorithm());
- assertNotNull(param.getKeyTransportEncryptionAlgorithm());
+ assertNotNull(param.getKeyTransportEncryptionAlgorithm());
+ assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512);
+ assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP);
assertNotNull(param.getKeyTransportEncryptionCredential());
assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
}
- /* Algorithms are know because they are limited by config.*/
+ /* Key 87ff206d-15f9-4b8c-ba88-a8c17014da13 has a key use of 'sig' rather than 'end'.*/
@Test
- public void testSuccessfulResolution_ForKeyEncryption() throws Exception {
+ public void testUnSuccessfulResolution_ForKeyEncryption_WrongKeyUse() throws Exception {
+ cache.setHttpClient(createMockHttpClient(readJsonFromFile(REMOTE_JWKSET_WRONG_KEYUSE)));
+ final CriteriaSet criteria = buildBasicCriteriaSet();
+ config.setKeyTransportEncryptionAlgorithms(List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP));
+ config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
+
+ final Iterable<JWTEncryptionParameters> params = resolver.resolve(criteria);
+ assertFalse(params.iterator().hasNext());
+ }
+
+ /* Key 87ff206d-15f9-4b8c-ba88-a8c17014da13 has no key use, so assume unspecified.*/
+ @Test
+ public void testSuccessfulResolution_ForKeyEncryption_NoKeyUse() throws Exception {
+ cache.setHttpClient(createMockHttpClient(readJsonFromFile(REMOTE_JWKSET_NO_KEY_USE)));
final CriteriaSet criteria = buildBasicCriteriaSet();
config.setKeyTransportEncryptionAlgorithms(List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP));
config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
@@ -196,6 +235,49 @@ public class ProviderMetadataEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP);
assertNotNull(param.getKeyTransportEncryptionCredential());
assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
+ }
+
+ /* Test credential choice if the keys do not specify their 'alg', only the mandatory 'kty'*/
+ @Test
+ public void testSuccessfulResolution_ForKeyEncryption_NoAlgParams() throws Exception {
+ cache.setHttpClient(createMockHttpClient(readJsonFromFile(REMOTE_JWKSET_NO_ALG_PARAM)));
+ final CriteriaSet criteria = buildBasicCriteriaSet();
+ config.setKeyTransportEncryptionAlgorithms(List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP));
+ config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
+
+ final Iterable<JWTEncryptionParameters> params = resolver.resolve(criteria);
+ assertNotNull(params);
+ assertTrue(params.iterator().hasNext());
+ final JWTEncryptionParameters param = params.iterator().next();
+ assertNotNull(param.getDataEncryptionAlgorithm());
+ assertNotNull(param.getKeyTransportEncryptionAlgorithm());
+ assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512);
+ assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP);
+ assertNotNull(param.getKeyTransportEncryptionCredential());
+ assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
+ }
+
+ /* Test credential choice if the keys do not specify their 'alg', only the mandatory 'kty'*/
+ @Test
+ public void testSuccessfulResolution_ForKeyAgreement_NoAlgParams() throws Exception {
+ cache.setHttpClient(createMockHttpClient(readJsonFromFile(REMOTE_JWKSET_NO_ALG_PARAM)));
+ final CriteriaSet criteria = buildBasicCriteriaSet();
+ config.setKeyTransportEncryptionAlgorithms(List.of(KeyManagementConstants.ALGO_ID_ALG_ECDH_ES));
+ config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
+
+ final Iterable<JWTEncryptionParameters> params = resolver.resolve(criteria);
+ assertNotNull(params);
+ assertTrue(params.iterator().hasNext());
+ final JWTEncryptionParameters param = params.iterator().next();
+ assertNotNull(param.getDataEncryptionAlgorithm());
+ assertNotNull(param.getKeyTransportEncryptionAlgorithm());
+ assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512);
+ assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_ECDH_ES);
+ assertNotNull(param.getKeyTransportEncryptionCredential());
+ assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"EC");
}
/* Should chose key encryption creds as they are the only ones configured, and are first
@@ -217,6 +299,7 @@ public class ProviderMetadataEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP);
assertNotNull(param.getKeyTransportEncryptionCredential());
assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
}
/* Should chose key wrap creds first, as that algorithm is first in the list.*/
@@ -320,6 +403,7 @@ public class ProviderMetadataEncryptionParametersResolverTest {
assertNotNull(param.getKeyTransportEncryptionCredential());
assertTrue(param.getKeyTransportEncryptionCredential().getKeyNames().contains("mock-key"));
assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"RSA");
}
/* The first mockKey in the list should be resolved.*/
@@ -376,6 +460,7 @@ public class ProviderMetadataEncryptionParametersResolverTest {
assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_ECDH_ES);
assertNotNull(param.getKeyTransportEncryptionCredential());
assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+ assertEquals(param.getKeyTransportEncryptionCredential().getPublicKey().getAlgorithm(),"EC");
}
@Test
diff --git a/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk b/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk
index 5473bee..30639e2 100644
--- a/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk
+++ b/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk
@@ -50,7 +50,6 @@
"e": "AQAB",
"use": "enc",
"kid": "87ff206d-15f9-4b8c-ba88-a8c17014da13",
-"alg": "RSA-OAEP",
"n": "uAVnVD3cMEbrAsDg1c3n6GfzR3sSg9C9pbjTw39_jgWk5YQCHPPOt4zYyZZL2JCnm9TFjnndCCW5ZPWHPJjumiNB2r-vC0CmI-T66JSRX3YYw0h2Odiusr_74FNe_mYyEuClFa4hwo-RMgrp8L1sbrAWcgGOc84rD6-fZXVrWFMkOb0jg6tqF1EwBSxZFG1cfvUmatNuBXs6njPHvvqhd7Bz6adK4YkpzCUbD-jSjpvAvU-Q4TZT_bXq4WRFOPqXv2NX4ch7ErjEm5tJEk7BIqOh7Byg0pWB4WAwsMcZKnHlp7JjtB2T1s_45_iqD2xipxpF-NxoHUlz67qHt7-W4Q"
},
{
@@ -59,8 +58,7 @@
"crv": "P-256",
"kid": "c689ce91-8d82-45f2-b671-38ee38e7599f",
"x": "redOUw802EuKJRoS8kQx6_RjuCypx0dcMBhv4IAALvQ",
-"y": "oaypduaS_wPLGCDQfJ0SKtQu0urJzhr4ZRn5wYMhiyk",
-"alg": "ECDH-ES"
+"y": "oaypduaS_wPLGCDQfJ0SKtQu0urJzhr4ZRn5wYMhiyk"
}
]
}
\ No newline at end of file
diff --git a/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk b/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-keyuse.jwk
similarity index 95%
copy from oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk
copy to oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-keyuse.jwk
index 5473bee..10e7a50 100644
--- a/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk
+++ b/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-keyuse.jwk
@@ -48,9 +48,7 @@
{
"kty": "RSA",
"e": "AQAB",
-"use": "enc",
"kid": "87ff206d-15f9-4b8c-ba88-a8c17014da13",
-"alg": "RSA-OAEP",
"n": "uAVnVD3cMEbrAsDg1c3n6GfzR3sSg9C9pbjTw39_jgWk5YQCHPPOt4zYyZZL2JCnm9TFjnndCCW5ZPWHPJjumiNB2r-vC0CmI-T66JSRX3YYw0h2Odiusr_74FNe_mYyEuClFa4hwo-RMgrp8L1sbrAWcgGOc84rD6-fZXVrWFMkOb0jg6tqF1EwBSxZFG1cfvUmatNuBXs6njPHvvqhd7Bz6adK4YkpzCUbD-jSjpvAvU-Q4TZT_bXq4WRFOPqXv2NX4ch7ErjEm5tJEk7BIqOh7Byg0pWB4WAwsMcZKnHlp7JjtB2T1s_45_iqD2xipxpF-NxoHUlz67qHt7-W4Q"
},
{
@@ -59,8 +57,7 @@
"crv": "P-256",
"kid": "c689ce91-8d82-45f2-b671-38ee38e7599f",
"x": "redOUw802EuKJRoS8kQx6_RjuCypx0dcMBhv4IAALvQ",
-"y": "oaypduaS_wPLGCDQfJ0SKtQu0urJzhr4ZRn5wYMhiyk",
-"alg": "ECDH-ES"
+"y": "oaypduaS_wPLGCDQfJ0SKtQu0urJzhr4ZRn5wYMhiyk"
}
]
}
\ No newline at end of file
diff --git a/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk b/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-wrong-key-use.jwk
similarity index 95%
copy from oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk
copy to oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-wrong-key-use.jwk
index 5473bee..a388099 100644
--- a/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-no-alg.jwk
+++ b/oidc-common-crypto-impl/src/test/resources/credentials/test-provider-resolver-remote-jwkset-response-wrong-key-use.jwk
@@ -48,9 +48,8 @@
{
"kty": "RSA",
"e": "AQAB",
-"use": "enc",
+"use": "sig",
"kid": "87ff206d-15f9-4b8c-ba88-a8c17014da13",
-"alg": "RSA-OAEP",
"n": "uAVnVD3cMEbrAsDg1c3n6GfzR3sSg9C9pbjTw39_jgWk5YQCHPPOt4zYyZZL2JCnm9TFjnndCCW5ZPWHPJjumiNB2r-vC0CmI-T66JSRX3YYw0h2Odiusr_74FNe_mYyEuClFa4hwo-RMgrp8L1sbrAWcgGOc84rD6-fZXVrWFMkOb0jg6tqF1EwBSxZFG1cfvUmatNuBXs6njPHvvqhd7Bz6adK4YkpzCUbD-jSjpvAvU-Q4TZT_bXq4WRFOPqXv2NX4ch7ErjEm5tJEk7BIqOh7Byg0pWB4WAwsMcZKnHlp7JjtB2T1s_45_iqD2xipxpF-NxoHUlz67qHt7-W4Q"
},
{
@@ -59,8 +58,7 @@
"crv": "P-256",
"kid": "c689ce91-8d82-45f2-b671-38ee38e7599f",
"x": "redOUw802EuKJRoS8kQx6_RjuCypx0dcMBhv4IAALvQ",
-"y": "oaypduaS_wPLGCDQfJ0SKtQu0urJzhr4ZRn5wYMhiyk",
-"alg": "ECDH-ES"
+"y": "oaypduaS_wPLGCDQfJ0SKtQu0urJzhr4ZRn5wYMhiyk"
}
]
}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list