[java-oidc-common] branch dev/JCOMOIDC-41 updated: JCOMOIDC-41 - Move OIDC Signature Validation resolvers and parameter classes to commons

Phil Smart philip.smart at jisc.ac.uk
Thu Aug 18 13:54:58 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=29d093a6df357bbaaeb022d1f47fcd00285b73eb

The following commit(s) were added to refs/heads/dev/JCOMOIDC-41 by this push:
     new 29d093a  JCOMOIDC-41 - Move OIDC Signature Validation resolvers and parameter classes to commons
29d093a is described below

commit 29d093a6df357bbaaeb022d1f47fcd00285b73eb
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Thu Aug 18 14:54:52 2022 +0100

    JCOMOIDC-41 - Move OIDC Signature Validation resolvers and parameter
    classes to commons
    
     - Created new JWT versions of the encryption and decryption
    configuration and parameter classes.
     - Updated the populate JWT parameters resolver to support the new
    classes.
     - Created a new Basic JWT encryption parameter resolver with logic more
    appropriate to parameter resolution for use by the Nimbus encrypters.
     - Substantially improved the
    ProviderMetadataEncryptionParametersResolver to support the new base
    resolver.
    
    
    https://shibboleth.atlassian.net/browse/JCOMOIDC-41
---
 ...ration.java => JWTDecryptionConfiguration.java} |   2 +-
 .../oidc/security/JWTEncryptionConfiguration.java  |  44 ++
 .../oidc/security/JWTEncryptionParameters.java     |  95 +++
 ...n.java => JWTEncryptionParametersResolver.java} |  21 +-
 .../security/JWTSignatureSigningParameters.java    |  71 +++
 ... => JWTSignatureSigningParametersResolver.java} |  22 +-
 .../security/SignatureValidationConfiguration.java |   2 -
 .../context/JWTSecurityParametersContext.java      |  16 +-
 .../DecryptionConfigurationCriterion.java          |  12 +-
 .../oidc/security/criterion/JWKSetCriterion.java   | 100 +++
 ...va => JWTEncryptionConfigurationCriterion.java} |  27 +-
 .../impl/BasicJWTDecryptionConfiguration.java      |   6 +-
 .../impl/BasicJWTEncryptionConfiguration.java      | 133 ++++
 .../impl/BasicJWTEncryptionParametersResolver.java | 670 +++++++++++++++++++++
 ...BasicJWTSignatureSigningParametersResolver.java | 278 +++++++++
 .../DefaultJWTDecryptionParametersResolver.java    |   6 +-
 .../PopulateJWTSignatureSigningParameters.java     |   9 +-
 ...pulateJWTSignatureSigningParametersHandler.java |  11 +-
 .../BasicJWTEncryptionParametersResolverTest.java  | 400 ++++++++++++
 .../impl/ExplicitKeySignedJWTTrustEngineTest.java  |   3 +-
 .../profile/config/OIDCSecurityConfiguration.java  |  37 +-
 21 files changed, 1875 insertions(+), 90 deletions(-)

diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/DecryptionConfiguration.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTDecryptionConfiguration.java
similarity index 94%
rename from oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/DecryptionConfiguration.java
rename to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTDecryptionConfiguration.java
index eb4b62b..f55a1f9 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/DecryptionConfiguration.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTDecryptionConfiguration.java
@@ -23,7 +23,7 @@ import org.opensaml.xmlsec.AlgorithmPolicyConfiguration;
 
 import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
 
-public interface DecryptionConfiguration extends AlgorithmPolicyConfiguration {
+public interface JWTDecryptionConfiguration extends AlgorithmPolicyConfiguration {
     
     /**
      * Get the CredentialResolver to use when processing the encrypted content.
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTEncryptionConfiguration.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTEncryptionConfiguration.java
new file mode 100644
index 0000000..53ca21e
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTEncryptionConfiguration.java
@@ -0,0 +1,44 @@
+package net.shibboleth.oidc.security;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.xmlsec.AlgorithmPolicyConfiguration;
+
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+
+public interface JWTEncryptionConfiguration extends AlgorithmPolicyConfiguration {
+
+    /**
+     * Get the list of data encryption credentials to use, in preference order.
+     * 
+     * @return the list of encryption credentials, may be empty
+     */
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<Credential> getDataEncryptionCredentials();
+    
+    /**
+     * Get the list of preferred data encryption algorithm URIs, in preference order.
+     * 
+     * @return the list of algorithm URIs, may be empty
+     */
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<String> getDataEncryptionAlgorithms();
+    
+    /**
+     * Get the list of key transport encryption credentials to use, in preference order.
+     * 
+     * @return the list of encryption credentials, may be empty
+     */
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<Credential> getKeyTransportEncryptionCredentials();
+    
+    /**
+     * Get the list of preferred key transport encryption algorithm URIs, in preference order.
+     * 
+     * @return the list of algorithm URIs, may be empty
+     */
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<String> getKeyTransportEncryptionAlgorithms();
+
+}
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTEncryptionParameters.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTEncryptionParameters.java
new file mode 100644
index 0000000..04601dc
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTEncryptionParameters.java
@@ -0,0 +1,95 @@
+package net.shibboleth.oidc.security;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+
+/**
+ * The effective parameters to use when generating encrypted JWTs.
+ */
+public class JWTEncryptionParameters {
+    
+    /** The EncryptedData encryption credential. */
+    private Credential dataEncryptionCredential;
+    
+    /** The EncryptedKey encryption credential. */
+    private Credential keyTransportEncryptionCredential;
+    
+    /** The EncryptedData encryption algorithm URI. */
+    private String dataEncryptionAlgorithmURI;
+    
+    /** The EncryptedKey encryption algorithm URI. */
+    private String keyTransportEncryptionAlgorithmURI;
+    
+    /**
+     * Get the encryption credential to use when encrypting the EncryptedData.
+     * 
+     * @return the encryption credential
+     */
+    @Nullable public Credential getDataEncryptionCredential() {
+        return dataEncryptionCredential;
+    }
+    
+    /**
+     * Set the encryption credential to use when encrypting the EncryptedData.
+     * 
+     * @param credential the encryption credential
+     */
+    public void setDataEncryptionCredential(@Nullable final Credential credential) {
+        dataEncryptionCredential = credential;
+    }
+    
+    /**
+     * Get the encryption credential to use when encrypting the EncryptedKey.
+     * 
+     * @return the encryption credential
+     */
+    @Nullable public Credential getKeyTransportEncryptionCredential() {
+        return keyTransportEncryptionCredential;
+    }
+    
+    /**
+     * Set the encryption credential to use when encrypting the EncryptedKey.
+     * 
+     * @param credential the encryption credential
+     */
+    public void setKeyTransportEncryptionCredential(@Nullable final Credential credential) {
+        keyTransportEncryptionCredential = credential;
+    }
+
+    /**
+     * Get the encryption algorithm URI to use when encrypting the EncryptedData.
+     * 
+     * @return an encryption algorithm URI
+     */
+    @Nullable public String getDataEncryptionAlgorithm() {
+        return dataEncryptionAlgorithmURI;
+    }
+    
+    /**
+     * Set the encryption algorithm URI to use when encrypting the EncryptedData.
+     * 
+     * @param uri an encryption algorithm URI
+     */
+    public void setDataEncryptionAlgorithm(@Nullable final String uri) {
+        dataEncryptionAlgorithmURI = uri;
+    }
+    
+    /**
+     * Get the encryption algorithm URI to use when encrypting the EncryptedKey.
+     * 
+     * @return an encryption algorithm URI
+     */
+    @Nullable public String getKeyTransportEncryptionAlgorithm() {
+        return keyTransportEncryptionAlgorithmURI;
+    }
+
+    /**
+     * Set the encryption algorithm URI to use when encrypting the EncryptedKey.
+     * 
+     * @param uri an encryption algorithm URI
+     */
+    public void setKeyTransportEncryptionAlgorithm(@Nullable final String uri) {
+        keyTransportEncryptionAlgorithmURI = uri;
+    }
+}
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTEncryptionParametersResolver.java
similarity index 57%
copy from oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java
copy to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTEncryptionParametersResolver.java
index b593989..1215f16 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTEncryptionParametersResolver.java
@@ -17,25 +17,12 @@
 
 package net.shibboleth.oidc.security;
 
-import javax.annotation.Nullable;
-
-import org.opensaml.security.trust.TrustEngine;
-import org.opensaml.xmlsec.AlgorithmPolicyConfiguration;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.Resolver;
 
 /**
- * The configuration information to use when validating a signature.
- * 
- * @param <T> the token type to validate
+ * An interface for components which resolve {@link JWTEncryptionParameters} based on a {@link CriteriaSet}.
  */
-//TODO We can not use the existing SignatureValidationConfiguration
-//as it implements the signaturetrustengine which is only compatible with XML.
-public interface SignatureValidationConfiguration<T> extends AlgorithmPolicyConfiguration {
-    
-    /**
-     * Get the signature trust engine to use.
-     * 
-     * @return the signature trust engine
-     */
-    @Nullable public TrustEngine<T> getSignatureTrustEngine();
+public interface JWTEncryptionParametersResolver extends Resolver<JWTEncryptionParameters, CriteriaSet> {
 
 }
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTSignatureSigningParameters.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTSignatureSigningParameters.java
new file mode 100644
index 0000000..5fbd842
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTSignatureSigningParameters.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.security;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+
+/**
+ * The effective parameters to use when generating an JWT signature.
+ */
+public class JWTSignatureSigningParameters {
+    
+    /** The signing credential. */
+    private Credential signingCredential;
+    
+    /** The signature algorithm URI. */
+    private String signatureAlgorithmURI;
+    
+    /**
+     * Get the signing credential to use when signing.
+     * 
+     * @return the signing credential
+     */
+    @Nullable public Credential getSigningCredential() {
+        return signingCredential;
+    }
+    
+    /**
+     * Set the signing credential to use when signing.
+     * 
+     * @param credential the signing credential
+     */
+    public void setSigningCredential(@Nullable final Credential credential) {
+        signingCredential = credential;
+    }
+    
+    /**
+     * Get the signature algorithm URI to use when signing.
+     * 
+     * @return a signature algorithm URI mapping
+     */
+    @Nullable public String getSignatureAlgorithm() {
+        return signatureAlgorithmURI;
+    }
+    
+    /**
+     * Set the signature algorithm URI to use when signing.
+     * 
+     * @param uri a signature algorithm URI mapping
+     */
+    public void setSignatureAlgorithm(@Nullable final String uri) {
+        signatureAlgorithmURI = uri;
+    }
+
+}
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTSignatureSigningParametersResolver.java
similarity index 56%
copy from oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java
copy to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTSignatureSigningParametersResolver.java
index b593989..ac79925 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/JWTSignatureSigningParametersResolver.java
@@ -17,25 +17,9 @@
 
 package net.shibboleth.oidc.security;
 
-import javax.annotation.Nullable;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.Resolver;
 
-import org.opensaml.security.trust.TrustEngine;
-import org.opensaml.xmlsec.AlgorithmPolicyConfiguration;
-
-/**
- * The configuration information to use when validating a signature.
- * 
- * @param <T> the token type to validate
- */
-//TODO We can not use the existing SignatureValidationConfiguration
-//as it implements the signaturetrustengine which is only compatible with XML.
-public interface SignatureValidationConfiguration<T> extends AlgorithmPolicyConfiguration {
-    
-    /**
-     * Get the signature trust engine to use.
-     * 
-     * @return the signature trust engine
-     */
-    @Nullable public TrustEngine<T> getSignatureTrustEngine();
+public interface JWTSignatureSigningParametersResolver extends Resolver<JWTSignatureSigningParameters, CriteriaSet> {
 
 }
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java
index b593989..d708034 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/SignatureValidationConfiguration.java
@@ -27,8 +27,6 @@ import org.opensaml.xmlsec.AlgorithmPolicyConfiguration;
  * 
  * @param <T> the token type to validate
  */
-//TODO We can not use the existing SignatureValidationConfiguration
-//as it implements the signaturetrustengine which is only compatible with XML.
 public interface SignatureValidationConfiguration<T> extends AlgorithmPolicyConfiguration {
     
     /**
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/context/JWTSecurityParametersContext.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/context/JWTSecurityParametersContext.java
index 1dfa595..ac35481 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/context/JWTSecurityParametersContext.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/context/JWTSecurityParametersContext.java
@@ -21,12 +21,12 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import org.opensaml.messaging.context.BaseContext;
-import org.opensaml.xmlsec.EncryptionParameters;
-import org.opensaml.xmlsec.SignatureSigningParameters;
 
 import com.nimbusds.jwt.SignedJWT;
 
 import net.shibboleth.oidc.security.JWTDecryptionParameters;
+import net.shibboleth.oidc.security.JWTEncryptionParameters;
+import net.shibboleth.oidc.security.JWTSignatureSigningParameters;
 import net.shibboleth.oidc.security.SignatureValidationParameters;
 
 /**
@@ -39,13 +39,13 @@ public final class JWTSecurityParametersContext extends BaseContext {
     @Nullable private SignatureValidationParameters<SignedJWT> signatureValidationParameters;
     
     /** Signature signing parameters.*/
-    @Nullable private SignatureSigningParameters signatureSigningParameters;
+    @Nullable private JWTSignatureSigningParameters signatureSigningParameters;
     
     /** Decryption parameters. */
     @Nullable private JWTDecryptionParameters decryptionParameters;
     
     /** Encryption parameters.*/
-    @Nullable private EncryptionParameters encryptionParameters;
+    @Nullable private JWTEncryptionParameters encryptionParameters;
      
     /**
      * Get the parameters to use for signature validation operations.
@@ -74,7 +74,7 @@ public final class JWTSecurityParametersContext extends BaseContext {
      * 
      * @return the parameters
      */
-    @Nullable public SignatureSigningParameters getSignatureSigningParameters() {
+    @Nullable public JWTSignatureSigningParameters getSignatureSigningParameters() {
         return signatureSigningParameters;
     }
 
@@ -86,7 +86,7 @@ public final class JWTSecurityParametersContext extends BaseContext {
      * @return this context
      */
     @Nonnull public JWTSecurityParametersContext setSignatureSigningParameters(
-            @Nullable final SignatureSigningParameters params) {
+            @Nullable final JWTSignatureSigningParameters params) {
         signatureSigningParameters = params;
         return this;
     }
@@ -119,7 +119,7 @@ public final class JWTSecurityParametersContext extends BaseContext {
      * 
      * @return this context
      */
-    public JWTSecurityParametersContext setEncryptionParameters(@Nullable final EncryptionParameters params) {
+    public JWTSecurityParametersContext setEncryptionParameters(@Nullable final JWTEncryptionParameters params) {
         encryptionParameters = params;
         return this;
     }
@@ -129,7 +129,7 @@ public final class JWTSecurityParametersContext extends BaseContext {
      * 
      * @return the parameters
      */
-    @Nullable public EncryptionParameters getEncryptionParameters() {
+    @Nullable public JWTEncryptionParameters getEncryptionParameters() {
         return encryptionParameters;
     }
 
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/DecryptionConfigurationCriterion.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/DecryptionConfigurationCriterion.java
index 0fb0d22..368c588 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/DecryptionConfigurationCriterion.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/DecryptionConfigurationCriterion.java
@@ -21,7 +21,7 @@ import java.util.List;
 
 import javax.annotation.Nonnull;
 
-import net.shibboleth.oidc.security.DecryptionConfiguration;
+import net.shibboleth.oidc.security.JWTDecryptionConfiguration;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
@@ -30,12 +30,12 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.resolver.Criterion;
 
 /**
- * Criterion which holds one or more instances of {@link DecryptionConfiguration}.
+ * Criterion which holds one or more instances of {@link JWTDecryptionConfiguration}.
  */
 public class DecryptionConfigurationCriterion implements Criterion {
     
     /** The list of configuration instances. */
-    @Nonnull @NonnullElements private final List<DecryptionConfiguration> configs;
+    @Nonnull @NonnullElements private final List<JWTDecryptionConfiguration> configs;
     
     /**
      * Constructor.
@@ -43,7 +43,7 @@ public class DecryptionConfigurationCriterion implements Criterion {
      * @param configurations list of configuration instances
      */
     public DecryptionConfigurationCriterion(@Nonnull @NonnullElements @NotEmpty final
-            List<DecryptionConfiguration> configurations) {
+            List<JWTDecryptionConfiguration> configurations) {
         configs = List.copyOf(Constraint.isNotNull(configurations, "List of configurations cannot be null"));
         Constraint.isNotEmpty(configs, "At least one configuration is required");
         
@@ -55,7 +55,7 @@ public class DecryptionConfigurationCriterion implements Criterion {
      * @param configurations varargs array of configuration instances
      */
     public DecryptionConfigurationCriterion(@Nonnull @NonnullElements @NotEmpty final
-            DecryptionConfiguration... configurations) {
+            JWTDecryptionConfiguration... configurations) {
         configs = List.of(Constraint.isNotNull(configurations, "List of configurations cannot be null"));
         Constraint.isNotEmpty(configs, "At least one configuration is required");
     }
@@ -66,7 +66,7 @@ public class DecryptionConfigurationCriterion implements Criterion {
      * @return the list of configuration instances
      */
     @Nonnull @NonnullElements @NotLive @Unmodifiable @NotEmpty
-    public List<DecryptionConfiguration> getConfigurations() {
+    public List<JWTDecryptionConfiguration> getConfigurations() {
         return configs;
     }
     
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/JWKSetCriterion.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/JWKSetCriterion.java
new file mode 100644
index 0000000..b879911
--- /dev/null
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/JWKSetCriterion.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.security.criterion;
+
+import javax.annotation.Nullable;
+
+import com.nimbusds.jose.jwk.JWKSet;
+
+import net.shibboleth.utilities.java.support.resolver.Criterion;
+
+/**
+ * An implementation of {@link Criterion} which specifies criteria based
+ * on the contents of a {@link JWKSet} element.
+ */
+public final class JWKSetCriterion implements Criterion {
+    
+    /** The JWKSet which serves as a source of credentials. */
+    @Nullable private JWKSet jwkSet;
+    
+    /**
+     * Constructor.
+     *
+     * @param jwkSet the JWKSet credentials
+     */
+    public JWKSetCriterion(@Nullable final JWKSet jwkSet) {
+        setJWKSet(jwkSet);
+    }
+
+    /**
+     * Gets the JWKSet which is the source of credentials.
+     * 
+     * @return the JWKSet credentials
+     */
+    @Nullable public JWKSet getJWKSet() {
+        return jwkSet;
+    }
+    
+    /**
+     * Sets the JWKSet which is the source of credentials.
+     * 
+     * @param newJwkSet the JWKSet to use as a source of credentials
+     * 
+     */
+    public void setJWKSet(@Nullable final JWKSet newJwkSet) {
+        jwkSet = newJwkSet;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder();
+        builder.append("JWKSetCriterion [JWKSet=");
+        builder.append("<contents not displayable>");
+        builder.append("]");
+        return builder.toString();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int hashCode() {
+        if (jwkSet != null) {
+            return jwkSet.hashCode();
+        }
+        return super.hashCode();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj == null) {
+            return false;
+        }
+
+        if (obj instanceof JWKSetCriterion) {
+            return jwkSet.equals(((JWKSetCriterion) obj).jwkSet);
+        }
+
+        return false;
+    }
+
+}
\ No newline at end of file
diff --git a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/DecryptionConfigurationCriterion.java b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/JWTEncryptionConfigurationCriterion.java
similarity index 76%
copy from oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/DecryptionConfigurationCriterion.java
copy to oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/JWTEncryptionConfigurationCriterion.java
index 0fb0d22..f50f283 100644
--- a/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/DecryptionConfigurationCriterion.java
+++ b/oidc-common-crypto-api/src/main/java/net/shibboleth/oidc/security/criterion/JWTEncryptionConfigurationCriterion.java
@@ -21,7 +21,7 @@ import java.util.List;
 
 import javax.annotation.Nonnull;
 
-import net.shibboleth.oidc.security.DecryptionConfiguration;
+import net.shibboleth.oidc.security.JWTEncryptionConfiguration;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
@@ -30,20 +30,20 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.resolver.Criterion;
 
 /**
- * Criterion which holds one or more instances of {@link DecryptionConfiguration}.
+ * Criterion which holds one or more instances of {@link JWTEncryptionConfigurationCriterion}.
  */
-public class DecryptionConfigurationCriterion implements Criterion {
+public class JWTEncryptionConfigurationCriterion implements Criterion {
     
     /** The list of configuration instances. */
-    @Nonnull @NonnullElements private final List<DecryptionConfiguration> configs;
+    @Nonnull @NonnullElements private final List<JWTEncryptionConfiguration> configs;
     
     /**
      * Constructor.
      *
      * @param configurations list of configuration instances
      */
-    public DecryptionConfigurationCriterion(@Nonnull @NonnullElements @NotEmpty final
-            List<DecryptionConfiguration> configurations) {
+    public JWTEncryptionConfigurationCriterion(@Nonnull @NonnullElements @NotEmpty final
+            List<JWTEncryptionConfiguration> configurations) {
         configs = List.copyOf(Constraint.isNotNull(configurations, "List of configurations cannot be null"));
         Constraint.isNotEmpty(configs, "At least one configuration is required");
         
@@ -54,19 +54,18 @@ public class DecryptionConfigurationCriterion implements Criterion {
      *
      * @param configurations varargs array of configuration instances
      */
-    public DecryptionConfigurationCriterion(@Nonnull @NonnullElements @NotEmpty final
-            DecryptionConfiguration... configurations) {
+    public JWTEncryptionConfigurationCriterion(@Nonnull @NonnullElements @NotEmpty final
+            JWTEncryptionConfiguration... configurations) {
         configs = List.of(Constraint.isNotNull(configurations, "List of configurations cannot be null"));
         Constraint.isNotEmpty(configs, "At least one configuration is required");
     }
     
     /**
      * Get the list of configuration instances.
-     * 
      * @return the list of configuration instances
      */
     @Nonnull @NonnullElements @NotLive @Unmodifiable @NotEmpty
-    public List<DecryptionConfiguration> getConfigurations() {
+    public List<JWTEncryptionConfiguration> getConfigurations() {
         return configs;
     }
     
@@ -74,7 +73,7 @@ public class DecryptionConfigurationCriterion implements Criterion {
     @Override
     public String toString() {
         final StringBuilder builder = new StringBuilder();
-        builder.append("DecryptionConfigurationCriterion [configs=");
+        builder.append("EncryptionConfigurationCriterion [configs=");
         builder.append(configs);
         builder.append("]");
         return builder.toString();
@@ -97,11 +96,11 @@ public class DecryptionConfigurationCriterion implements Criterion {
             return false;
         }
 
-        if (obj instanceof DecryptionConfigurationCriterion) {
-            return configs.equals(((DecryptionConfigurationCriterion) obj).getConfigurations());
+        if (obj instanceof JWTEncryptionConfigurationCriterion) {
+            return configs.equals(((JWTEncryptionConfigurationCriterion) obj).getConfigurations());
         }
 
         return false;
     }
 
-}
\ No newline at end of file
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTDecryptionConfiguration.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTDecryptionConfiguration.java
index 7fce719..09abf1e 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTDecryptionConfiguration.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTDecryptionConfiguration.java
@@ -21,14 +21,14 @@ import javax.annotation.Nullable;
 
 import org.opensaml.xmlsec.impl.BasicAlgorithmPolicyConfiguration;
 
-import net.shibboleth.oidc.security.DecryptionConfiguration;
+import net.shibboleth.oidc.security.JWTDecryptionConfiguration;
 import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
 
 /**
- * Basic implementation of {@link DecryptionConfiguration} for handling JWEs.
+ * Basic implementation of {@link JWTDecryptionConfiguration} for handling JWEs.
  */
 public class BasicJWTDecryptionConfiguration 
-                extends BasicAlgorithmPolicyConfiguration implements DecryptionConfiguration {
+                extends BasicAlgorithmPolicyConfiguration implements JWTDecryptionConfiguration {
     
     /** The EncryptedKey's credential resolver. */ 
     @Nullable private JOSEObjectCredentialResolver kekKeyCredentialResolver;
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionConfiguration.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionConfiguration.java
new file mode 100644
index 0000000..5b58806
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionConfiguration.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.security.impl;
+
+import java.util.Collections;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.xmlsec.impl.BasicAlgorithmPolicyConfiguration;
+
+import net.shibboleth.oidc.security.JWTEncryptionConfiguration;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
+
+public class BasicJWTEncryptionConfiguration extends BasicAlgorithmPolicyConfiguration 
+    implements JWTEncryptionConfiguration {
+
+    /** Data encryption credentials. */
+    @Nonnull @NonnullElements private List<Credential> dataEncryptionCredentials;
+    
+    /** Data encryption algorithm URIs. */
+    @Nonnull @NonnullElements private List<String> dataEncryptionAlgorithms;
+
+    /** Key transport encryption credentials. */
+    @Nonnull @NonnullElements private List<Credential> keyTransportEncryptionCredentials;
+    
+    /** Key transport encryption algorithm URIs. */
+    @Nonnull @NonnullElements private List<String> keyTransportEncryptionAlgorithms;
+    
+    /** Constructor. */
+    public BasicJWTEncryptionConfiguration() {
+        dataEncryptionCredentials = Collections.emptyList();
+        dataEncryptionAlgorithms = Collections.emptyList();
+        keyTransportEncryptionCredentials = Collections.emptyList();
+        keyTransportEncryptionAlgorithms = Collections.emptyList();
+    }
+    
+    @Override
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<Credential> getDataEncryptionCredentials() {
+        return dataEncryptionCredentials;
+    }
+    
+    /**
+     * Set the data encryption credentials to use.
+     * 
+     * @param credentials the list of data encryption credentials
+     */
+    public void setDataEncryptionCredentials(@Nullable @NonnullElements final List<Credential> credentials) {
+        if (credentials == null) {
+            dataEncryptionCredentials  = Collections.emptyList();
+        } else {
+            dataEncryptionCredentials = List.copyOf(credentials);
+        }
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<String> getDataEncryptionAlgorithms() {
+        return dataEncryptionAlgorithms;
+    }
+    
+    /**
+     * Set the data encryption algorithms to use.
+     * 
+     * @param algorithms the list of algorithms
+     */
+    public void setDataEncryptionAlgorithms(@Nullable @NonnullElements final List<String> algorithms) {
+        if (algorithms == null) {
+            dataEncryptionAlgorithms = Collections.emptyList();
+        } else {
+            dataEncryptionAlgorithms = List.copyOf(StringSupport.normalizeStringCollection(algorithms));
+        }
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<Credential> getKeyTransportEncryptionCredentials() {
+        return keyTransportEncryptionCredentials;
+    }
+    
+    /**
+     * Set the key transport encryption credentials to use.
+     * 
+     * @param credentials the list of key transport encryption credentials
+     */
+    public void setKeyTransportEncryptionCredentials(@Nullable @NonnullElements final List<Credential> credentials) {
+        if (credentials == null) {
+            keyTransportEncryptionCredentials  = Collections.emptyList();
+        } else {
+            keyTransportEncryptionCredentials = List.copyOf(credentials);
+        }
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public List<String> getKeyTransportEncryptionAlgorithms() {
+        return keyTransportEncryptionAlgorithms;
+    }
+    
+    /**
+     * Set the key transport encryption algorithms to use.
+     * 
+     * @param algorithms the list of algorithms
+     */
+    public void setKeyTransportEncryptionAlgorithms(@Nullable @NonnullElements final List<String> algorithms) {
+        if (algorithms == null) {
+            keyTransportEncryptionAlgorithms = Collections.emptyList();
+        } else {
+            keyTransportEncryptionAlgorithms = List.copyOf(StringSupport.normalizeStringCollection(algorithms));
+        }
+    }
+
+}
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
new file mode 100644
index 0000000..8f7dcbc
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolver.java
@@ -0,0 +1,670 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.security.impl;
+
+import java.security.Key;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.CredentialSupport;
+import org.opensaml.security.credential.UsageType;
+import org.opensaml.xmlsec.EncryptionParametersResolver;
+import org.opensaml.xmlsec.algorithm.AlgorithmRegistry;
+import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
+import org.opensaml.xmlsec.criterion.EncryptionOptionalCriterion;
+import org.opensaml.xmlsec.impl.AbstractSecurityParametersResolver;
+import org.opensaml.xmlsec.impl.AlgorithmRuntimeSupportedPredicate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.jose.Algorithm;
+import com.nimbusds.jose.EncryptionMethod;
+import com.nimbusds.jose.JWEAlgorithm;
+
+import net.shibboleth.oidc.security.JWTEncryptionConfiguration;
+import net.shibboleth.oidc.security.JWTEncryptionParameters;
+import net.shibboleth.oidc.security.JWTEncryptionParametersResolver;
+import net.shibboleth.oidc.security.credential.JWKCredential;
+import net.shibboleth.oidc.security.criterion.JWTEncryptionConfigurationCriterion;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.PredicateSupport;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/**
+ * Basic implementation of an {@link EncryptionParametersResolver}. The resolver takes the first credential from 
+ * the local encryption configuration which matches a configured key transport algorithm. The key transport
+ * algorithms are tried in the order they are specified, until a suitable credential is found.
+ * 
+ * <p>
+ * The following {@link net.shibboleth.utilities.java.support.resolver.Criterion} inputs are supported:
+ * </p>
+ * <ul>
+ * <li>{@link JWTEncryptionConfigurationCriterion} - required</li> 
+ * <li>{@link EncryptionOptionalCriterion} - optional</li> 
+ * </ul>
+ */
+public class BasicJWTEncryptionParametersResolver extends AbstractSecurityParametersResolver<JWTEncryptionParameters> 
+        implements JWTEncryptionParametersResolver {
+    
+    /** Logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(BasicJWTEncryptionParametersResolver.class);
+    
+    /** The AlgorithmRegistry used when processing algorithm URIs. */
+    @Nonnull private AlgorithmRegistry algorithmRegistry;
+    
+    /** Constructor. */
+    public BasicJWTEncryptionParametersResolver() {
+        algorithmRegistry = AlgorithmSupport.getGlobalAlgorithmRegistry();
+    }
+    
+    /**
+     * Get the {@link AlgorithmRegistry} instance used when resolving algorithm URIs. Defaults to
+     * the registry resolved via {@link AlgorithmSupport#getGlobalAlgorithmRegistry()}.
+     * 
+     * @return the algorithm registry instance
+     */
+    @Nonnull public AlgorithmRegistry getAlgorithmRegistry() {
+        // Handle case where this resolver was ctored before the library was properly initialized.
+        if (algorithmRegistry == null) {
+            return AlgorithmSupport.getGlobalAlgorithmRegistry();
+        }
+        return algorithmRegistry;
+    }
+
+    /**
+     * Set the {@link AlgorithmRegistry} instance used when resolving algorithm URIs. Defaults to
+     * the registry resolved via {@link AlgorithmSupport#getGlobalAlgorithmRegistry()}.
+     * 
+     * @param registry the new algorithm registry instance
+     */
+    public void setAlgorithmRegistry(@Nonnull final AlgorithmRegistry registry) {
+        algorithmRegistry = Constraint.isNotNull(registry, "AlgorithmRegistry was null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nonnull public Iterable<JWTEncryptionParameters> resolve(@Nonnull final CriteriaSet criteria) 
+            throws ResolverException {
+        final JWTEncryptionParameters params = resolveSingle(criteria);
+        if (params != null) {
+            return Collections.singletonList(params);
+        }
+        return Collections.emptyList();
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    @Nullable public JWTEncryptionParameters resolveSingle(@Nonnull final CriteriaSet criteria) throws ResolverException {
+        Constraint.isNotNull(criteria, "CriteriaSet was null");
+        Constraint.isNotNull(criteria.get(JWTEncryptionConfigurationCriterion.class), 
+                "Resolver requires an instance of JWTEncryptionConfigurationCriterion");
+        
+        final Predicate<String> includeExcludePredicate = getIncludeExcludePredicate(criteria);
+        
+        final JWTEncryptionParameters params = new JWTEncryptionParameters();
+        
+        resolveAndPopulateCredentialsAndAlgorithms(params, criteria, includeExcludePredicate);
+        
+        boolean encryptionOptional = false;
+        final EncryptionOptionalCriterion encryptionOptionalCrit = criteria.get(EncryptionOptionalCriterion.class);
+        if (encryptionOptionalCrit != null) {
+            encryptionOptional = encryptionOptionalCrit.isEncryptionOptional();
+        }
+        
+        if (validate(params, encryptionOptional)) {
+            logResult(params);
+            return params;
+        }
+        return null;
+        
+    }
+
+    /**
+     * Log the resolved parameters.
+     * 
+     * @param params the resolved param
+     */
+    protected void logResult(@Nonnull final JWTEncryptionParameters params) {
+        if (log.isDebugEnabled()) {
+            log.debug("Resolved EncryptionParameters:");
+            
+            final Key keyTransportKey =
+                    CredentialSupport.extractEncryptionKey(params.getKeyTransportEncryptionCredential());
+            if (keyTransportKey != null) {
+                log.debug("\tKey transport credential with key algorithm: {}", keyTransportKey.getAlgorithm());
+            } else {
+                log.debug("\tKey transport credential: null"); 
+            }
+            
+            log.debug("\tKey transport algorithm URI: {}", params.getKeyTransportEncryptionAlgorithm());             
+                      
+            final Key dataKey = CredentialSupport.extractEncryptionKey(params.getDataEncryptionCredential());
+            if (dataKey != null) {
+                log.debug("\tData encryption credential with key algorithm: {}", dataKey.getAlgorithm());
+            } else {
+                log.debug("\tData encryption credential: null"); 
+            }
+            
+            log.debug("\tData encryption algorithm URI: {}", params.getDataEncryptionAlgorithm());            
+        }
+    }
+
+// Checkstyle: CyclomaticComplexity OFF
+    /**
+     * Validate that the {@link JWTEncryptionParameters} instance has all the required properties populated.
+     * 
+     * @param params the parameters instance to evaluate
+     * @param encryptionOptional whether to consider invalid parameters to be a problem
+     * 
+     * @return true if parameters instance passes validation, false otherwise
+     */
+    protected boolean validate(@Nonnull final JWTEncryptionParameters params, final boolean encryptionOptional) {
+        if (params.getKeyTransportEncryptionCredential() == null 
+                && params.getDataEncryptionCredential() == null) {
+            final String msg = "Validation failure: Failed to resolve an encryption key";
+            if (encryptionOptional) {
+                log.debug(msg);
+            } else {
+                log.warn(msg);
+            }
+            return false;
+        }
+        if (params.getKeyTransportEncryptionCredential() != null 
+                && params.getKeyTransportEncryptionAlgorithm() == null) {
+            final String msg = "Validation failure: Unable to resolve key encryption algorithm URI for credential";
+            if (encryptionOptional) {
+                log.debug(msg);
+            } else {
+                log.warn(msg);
+            }
+            return false;
+        }
+        if (params.getDataEncryptionCredential() != null 
+                && params.getDataEncryptionAlgorithm() == null) {
+            final String msg = "Validation failure: Unable to resolve data encryption algorithm URI for credential";
+            if (encryptionOptional) {
+                log.debug(msg);
+            } else {
+                log.warn(msg);
+            }
+            return false;
+        }
+        if (params.getKeyTransportEncryptionCredential() != null 
+                && params.getDataEncryptionCredential() == null
+                && params.getDataEncryptionAlgorithm() == null) {
+            final String msg = "Validation failure: Unable to resolve a data encryption algorithm URI " 
+                + "for auto-generation of data encryption key";
+            if (encryptionOptional) {
+                log.debug(msg);
+            } else {
+                log.warn(msg);
+            }
+            return false;
+        }
+        
+        return true;
+    }
+// Checkstyle: CyclomaticComplexity ON
+
+    /**
+     * Get a predicate which implements the effective configured include/exclude policy.
+     * 
+     * @param criteria the input criteria being evaluated
+     * 
+     * @return a include/exclude predicate instance
+     */
+    @Nonnull protected Predicate<String> getIncludeExcludePredicate(@Nonnull final CriteriaSet criteria) {
+        return resolveIncludeExcludePredicate(criteria, 
+                criteria.get(JWTEncryptionConfigurationCriterion.class).getConfigurations());
+    }
+    
+    /**
+     * Resolve and populate the data encryption and key transport credentials and algorithm URIs.
+     * 
+     * @param params the params instance being populated
+     * @param criteria the input criteria being evaluated
+     * @param includeExcludePredicate the include/exclude predicate with which to evaluate the 
+     *          candidate data encryption and key transport algorithm URIs
+     */
+    protected void resolveAndPopulateCredentialsAndAlgorithms(@Nonnull final JWTEncryptionParameters params, 
+            @Nonnull final CriteriaSet criteria, @Nonnull final Predicate<String> includeExcludePredicate) {
+        
+        if (!criteria.contains(JWTEncryptionConfigurationCriterion.class)) {
+            log.debug("No encryption configuration criterion, encryption parameters can not be resolved");
+            return;
+        }
+        // Pre-resolve these for efficiency
+        final List<Credential> keyTransportCredentials = getEffectiveKeyTransportCredentials(criteria);
+        final List<String> keyTransportAlgorithms =
+                getEffectiveKeyTransportAlgorithms(criteria, includeExcludePredicate);
+        log.trace("Resolved effective key transport algorithms: {}", keyTransportAlgorithms);
+        
+        final List<String> dataEncryptionAlgorithms = getEffectiveDataEncryptionAlgorithms(criteria, 
+                includeExcludePredicate);
+        final List<Credential> dataEncryptionCredentials = getEffectiveDataEncryptionCredentials(criteria);
+        log.trace("Resolved effective data encryption algorithms: {}", dataEncryptionAlgorithms);
+        
+        resolveCredentialForSupportedAlgorithm(criteria,
+                convertStringAlgorithmURIsToJwkAlgorithms(keyTransportAlgorithms), 
+                convertStringEncryptionMethodURIsToEncryptionMethods(dataEncryptionAlgorithms),
+                keyTransportCredentials, dataEncryptionCredentials, params);
+    }
+    
+    /**
+     * Resolve a credential compatible with one-of the supported algorithms. Algorithms are tried in the order
+     * they appear in the list of keyTransportAlgorithms.  
+     * 
+     * <p>For each algorithm (in order) locally obtained credentials are matched first, followed by those fetched 
+     * from any additional sources - implemented by subclasses.</p>
+     * 
+     * <p>In the normal case, it would be expected that direct encryption and key wrapping credentials will be 
+     * resolved from locally configured private keys. Whereas key encryption or key agreement credentials will be 
+     * resolved from those fetched from additional sources e.g. a subclass that resolves the OP's remote key set. 
+     * Although it is permissible that any key type is found in any of the sources. By default, no additional sources
+     * are configured, and so only locally configured credentials will be resolved.
+     * </p>
+     * <p>The first key that is compatible with the key transport algorithm is returned. That is, if two or more 
+     * keys support the same algorithm, the first key resolved will be returned. There is no guarantee which 
+     * key that is.</p>
+     * 
+     * @param criteria the set of criterion passed into additional source implementations
+     * @param keyTransportAlgorithms the set of supported key transport algorithms
+     * @param dataEncryptionAlgorithms the set of supported data encryption algorithms
+     * @param keyTransportCredentials the list of local key transport credentials that might 
+     *                                  represent a private/secret key from configuration
+     * @param dataEncryptionCredentials the list of local data encryption credentials 
+     * @param params the encryption parameters to add the credential to
+     */
+    protected void resolveCredentialForSupportedAlgorithm(
+            @Nonnull final CriteriaSet criteria,
+            @Nonnull final List<JWEAlgorithm> keyTransportAlgorithms,
+            @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
+            @Nonnull final List<Credential> keyTransportCredentials, 
+            @Nonnull final List<Credential> dataEncryptionCredentials,
+            @Nonnull final JWTEncryptionParameters params) {
+        
+        for (final JWEAlgorithm algorithm : keyTransportAlgorithms) {   
+            
+            if (JWEAlgorithm.DIR == algorithm) {  
+                // Is a direct encryption type, so need to populate the data enc. creds.
+                final Credential localCred = 
+                        findCredentialThatSupportsAlgorithm(dataEncryptionCredentials, algorithm);
+                
+                if (localCred != null) {
+                    final EncryptionMethod encryptionMethod = 
+                            findEncryptionMethodThatSupportsCredential(dataEncryptionAlgorithms, localCred);
+                    
+                    if (encryptionMethod != null) {
+                        
+                        if (log.isDebugEnabled()) {
+                            log.debug("Selected key '{}' for alg 'dir' and enc '{}'", 
+                                    CredentialConversionUtil.resolveKid(localCred),
+                                    encryptionMethod.getName());
+                        }
+                        params.setKeyTransportEncryptionAlgorithm(JWEAlgorithm.DIR.getName());
+                        params.setDataEncryptionCredential(localCred);
+                        params.setDataEncryptionAlgorithm(encryptionMethod.getName());
+                        return;
+                    } 
+                } else {
+                    // If a local direct encryption credential can not be found, delegate to 
+                    // specialised implementation specific logic - if any.
+                    resolveDataEncryptionCredentialForSupportedAlgorithmFromAdditionalSource(
+                            dataEncryptionAlgorithms, criteria, params);                
+                    if (params.getDataEncryptionCredential() != null) {
+                        return;
+                    }
+                }
+                
+            } else {
+                // Supports key encryption, key wrapping, or key agreement.
+                final Credential localCred = 
+                        findCredentialThatSupportsAlgorithm(keyTransportCredentials, algorithm); 
+                
+                final EncryptionMethod encryptionMethod = 
+                        resolveEncryptionMethod(dataEncryptionAlgorithms);
+                
+                if (localCred != null) {                    
+               
+                    if (log.isDebugEnabled()) {
+                        log.debug("Selected key '{}' for alg '{}' and enc '{}'", 
+                                CredentialConversionUtil.resolveKid(localCred),
+                                algorithm.getName(), encryptionMethod.getName());
+                    }
+                    params.setKeyTransportEncryptionCredential(localCred);
+                    params.setKeyTransportEncryptionAlgorithm(algorithm.getName());
+                    params.setDataEncryptionAlgorithm(encryptionMethod.getName());
+                    return;
+                } else {                
+                    // If a local credential can not be found, delegate to 
+                    // specialised implementation specific logic - if any.
+                    resolveKeyTransportCredentialForSupportedAlgorithmFromAdditionalSource(
+                            algorithm, encryptionMethod, criteria, params);                
+                    if (params.getKeyTransportEncryptionCredential() != null) {
+                        return;
+                    }
+                }
+                
+               
+            }
+        }
+    }
+    
+    /**
+     * Resolve data encryption credentials from an additional source. This is the 'hook' which a 
+     * specialised implementation class can use to provide additional behaviour to the base behaviour
+     * of this class. That is, to find credentials from a source other than the local configuration.
+     * 
+     * <p>
+     * The algorithm 'alg' will be always be 'dir' or direct encryption when this method is called.
+     * </p>
+     * 
+     * <p>Implementation classes should override this method, the default behaviour does nothing.</p>
+     * 
+     * @param dataEncryptionAlgorithms the list of supported data encryption algorithms the 
+     *                                      resolved credential must support one-of
+     * @param criteria any criterion that supports the resolution process
+     * @param params the encryption parameters to store the result
+     */
+    protected void resolveDataEncryptionCredentialForSupportedAlgorithmFromAdditionalSource(
+            @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
+            @Nonnull final CriteriaSet criteria, @Nonnull final JWTEncryptionParameters params) {
+        // Default method does nothing        
+    }
+    
+    /**
+     * Resolve key transport credentials from an additional source. This is the 'hook' which a 
+     * specialised implementation class can use to provide additional behaviour to the base behaviour
+     * of this class. That is, to find credentials from a source other than the local configuration.
+     * 
+     * <p>Implementation classes should override this method, the default behaviour does nothing.</p>
+     * 
+     * @param algorithm the key transport algorithm to find a suitable credential for
+     * @param encryptionMethod the chosen content encryption method to use
+     * @param criteriaa ny criterion that supports the resolution process
+     * @param params the encryption parameters to store the result.
+     */
+    protected void resolveKeyTransportCredentialForSupportedAlgorithmFromAdditionalSource(
+            @Nonnull final JWEAlgorithm algorithm, @Nonnull final EncryptionMethod encryptionMethod,
+            @Nonnull final CriteriaSet criteria, @Nonnull final JWTEncryptionParameters params) {
+        // Default method does nothing        
+    }
+
+    /**
+     * Determine if any of the given credentials match the given algorithm.
+     * 
+     * <p>For a credential to be returned, it must meet the following criteria:</p>
+     * <ol>
+     * <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>The credential's key must match the keylength required by that algorithm</li>
+     * </ol>
+     * 
+     * <p>The first key that is compatible with the algorithm is returned. That is, if two or more keys
+     * support the same algorithm, the first key in the local credentials list
+     * will be returned. There is no guarantee which key that is.</p>
+     * 
+     * @param credentials the credentials to match against the algorithm
+     * @param algorithm the algorithm to locate a credential for
+     * 
+     * @return the first credential that matches the algorithm, {@literal null} otherwise.
+     */
+    @Nullable protected Credential findCredentialThatSupportsAlgorithm(@Nonnull final  List<Credential> credentials,
+            @Nonnull final JWEAlgorithm algorithm) {
+        return credentials.stream()
+                .filter(Objects::nonNull)
+                .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 -> checkKeyAlgorithmAndLength(k, algorithm.getName()))
+                .findFirst().orElse(null);
+    }
+    
+    /**
+     * Find an encryption method that is supported by the credential. That is, supports the algorithm and
+     * has the correct key length.
+     * 
+     * @param dataEncryptionAlgorithms the data encryption algorithms
+     * @param credential the credential to test
+     * 
+     * @return the first supported encryption method, {@literal null} otherwise.
+     */
+    @Nullable private EncryptionMethod findEncryptionMethodThatSupportsCredential(
+            @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms,
+            @Nonnull final Credential credential) {
+        
+        final Key key = CredentialSupport.extractEncryptionKey(credential);
+        
+        for (final EncryptionMethod method : dataEncryptionAlgorithms) {
+            if (AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(method.getName()))) {
+                return method;
+            }
+        }
+        return null;
+        
+    }
+    
+    
+    /**
+     * Return the first encryption method in the supported list, or null otherwise.
+     * 
+     * @param dataEncryptionAlgorithms the supported data encryption method
+     * 
+     * @return the first supported encryption method, or {@literal null}.
+     */
+    @Nullable protected EncryptionMethod resolveEncryptionMethod(
+            @Nonnull final List<EncryptionMethod> dataEncryptionAlgorithms) {
+        if (!dataEncryptionAlgorithms.isEmpty()) {
+            return dataEncryptionAlgorithms.get(0);
+        } 
+        return null;
+    }
+    
+    /**
+     * Convert the algorithms represented as strings, into Nimbus {@link Algorithm}s for later comparison.
+     * This will preserve the order of the original list ({@link List} is ordered). 
+     * 
+     * @param algos the algorithms to convert
+     * 
+     * @return the converted algorithms
+     */
+    @Nonnull protected List<JWEAlgorithm> convertStringAlgorithmURIsToJwkAlgorithms(@Nonnull final List<String> algos) {
+        return algos.stream().filter(Objects::nonNull).map(JWEAlgorithm::parse).collect(Collectors.toList());
+    }
+    
+    /**
+     * Convert the encryption methods represented as strings, into Nimbus {@link EncryptionMethod}s for later 
+     * comparison. This will preserve the order of the original list ({@link List} is ordered). 
+     * 
+     * @param algos the encryption methods to convert
+     * 
+     * @return the converted encryption methods
+     */
+    @Nonnull protected List<EncryptionMethod> convertStringEncryptionMethodURIsToEncryptionMethods(
+            @Nonnull final List<String> encMethods) {
+        return encMethods.stream().filter(Objects::nonNull).map(EncryptionMethod::parse).collect(Collectors.toList());
+    }
+        
+    /**
+     * Get the effective list of data encryption credentials to consider.
+     * 
+     * @param criteria the input criteria being evaluated
+     * 
+     * @return the list of credentials
+     */
+    @Nonnull protected List<Credential> getEffectiveDataEncryptionCredentials(@Nonnull final CriteriaSet criteria) {
+        final ArrayList<Credential> accumulator = new ArrayList<>();
+        for (final JWTEncryptionConfiguration config : criteria.get(JWTEncryptionConfigurationCriterion.class)
+                .getConfigurations()) {
+            
+            accumulator.addAll(config.getDataEncryptionCredentials());
+            
+        }
+        return accumulator;
+    }
+    
+    /**
+     * Get the effective list of data encryption algorithm URIs to consider, including application of 
+     * include/exclude policy.
+     * 
+     * @param criteria the input criteria being evaluated
+     * @param includeExcludePredicate  the include/exclude predicate to use
+     * 
+     * @return the list of effective algorithm URIs
+     */
+    @Nonnull protected List<String> getEffectiveDataEncryptionAlgorithms(@Nonnull final CriteriaSet criteria, 
+            @Nonnull final Predicate<String> includeExcludePredicate) {
+        
+        final ArrayList<String> accumulator = new ArrayList<>();
+        for (final JWTEncryptionConfiguration config
+                : criteria.get(JWTEncryptionConfigurationCriterion.class).getConfigurations()) {
+            
+            config.getDataEncryptionAlgorithms()
+                .stream()
+                .filter(PredicateSupport.and(getAlgorithmRuntimeSupportedPredicate(), includeExcludePredicate))
+                .forEach(accumulator::add);
+        }
+        return accumulator;
+    }
+    
+    /**
+     * Get the effective list of key transport credentials to consider.
+     * 
+     * @param criteria the input criteria being evaluated
+     * 
+     * @return the list of credentials
+     */
+    @Nonnull protected List<Credential> getEffectiveKeyTransportCredentials(@Nonnull final CriteriaSet criteria) {
+        final ArrayList<Credential> accumulator = new ArrayList<>();
+        for (final JWTEncryptionConfiguration config : criteria.get(JWTEncryptionConfigurationCriterion.class)
+                .getConfigurations()) {
+
+            accumulator.addAll(config.getKeyTransportEncryptionCredentials());
+            
+        }
+        return accumulator;
+    }
+    
+    /**
+     * Get the effective list of key transport algorithm URIs to consider, including application of 
+     * include/exclude policy.
+     * 
+     * @param criteria the input criteria being evaluated
+     * @param includeExcludePredicate  the include/exclude predicate to use
+     * 
+     * @return the list of effective algorithm URIs
+     */
+    @Nonnull protected List<String> getEffectiveKeyTransportAlgorithms(@Nonnull final CriteriaSet criteria, 
+            @Nonnull final Predicate<String> includeExcludePredicate) {
+        
+        final ArrayList<String> accumulator = new ArrayList<>();
+        for (final JWTEncryptionConfiguration config
+                : criteria.get(JWTEncryptionConfigurationCriterion.class).getConfigurations()) {
+            
+            config.getKeyTransportEncryptionAlgorithms()
+                .stream()                
+                .filter(PredicateSupport.and(getAlgorithmRuntimeSupportedPredicate(), includeExcludePredicate))
+                .forEach(accumulator::add);
+        }
+        return accumulator;
+    }
+    
+    /**
+     * Get a predicate which evaluates whether a cryptographic algorithm is supported
+     * by the runtime environment.
+     * 
+     * @return the predicate
+     */
+    @Nonnull protected Predicate<String> getAlgorithmRuntimeSupportedPredicate() {
+        return new AlgorithmRuntimeSupportedPredicate(getAlgorithmRegistry());
+    }
+    
+    /**
+     * Evaluate whether the specified credential is supported for use with the specified algorithm URI.
+     * 
+     * @param credential the credential to evaluate
+     * @param algorithm the algorithm URI to evaluate
+     * 
+     * @return true if credential may be used with the supplied algorithm URI, false otherwise
+     */
+    protected boolean credentialSupportsAlgorithm(@Nonnull final Credential credential, 
+            @Nonnull @NotEmpty final String algorithm) {
+        
+        return AlgorithmSupport.credentialSupportsAlgorithmForEncryption(credential, 
+                getAlgorithmRegistry().get(algorithm));
+    }
+    
+    /**
+     * Evaluate whether the specified credential is supported for use with the specified algorithm URI
+     * and the key length matches.
+     * 
+     * @param credential the credential 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
+     */
+    protected boolean checkKeyAlgorithmAndLength(@Nonnull final Credential credential, 
+            @Nonnull @NotEmpty final String algorithm) {
+        
+        final Key key = CredentialSupport.extractEncryptionKey(credential);
+        if (key == null) {
+            return false;
+        }
+        
+        return AlgorithmSupport.checkKeyAlgorithmAndLength(key, getAlgorithmRegistry().get(algorithm));
+    }
+    
+    /**
+     * Evaluate whether the specified algorithm is a key encryption or key wrapping algorithm.
+     * 
+     * @param algorithm the algorithm URI to evaluate
+     * 
+     * @return true if is a key transport algorithm URI, false otherwise
+     */
+    protected boolean isKeyEncryptionAlgorithm(@Nonnull final String algorithm) {
+        
+        return AlgorithmSupport.isKeyEncryptionAlgorithm(getAlgorithmRegistry().get(algorithm));
+    }
+    
+    /**
+     * Evaluate whether the specified algorithm is a data encryption algorithm.
+     * 
+     * @param algorithm the algorithm URI to evaluate
+     * 
+     * @return true if is a key transport algorithm URI, false otherwise
+     */
+    protected boolean isDataEncryptionAlgorithm(final String algorithm) {
+        
+        return AlgorithmSupport.isDataEncryptionAlgorithm(getAlgorithmRegistry().get(algorithm));
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTSignatureSigningParametersResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTSignatureSigningParametersResolver.java
new file mode 100644
index 0000000..41f39bd
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicJWTSignatureSigningParametersResolver.java
@@ -0,0 +1,278 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.security.impl;
+
+import java.security.Key;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Predicate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.CredentialSupport;
+import org.opensaml.xmlsec.SignatureSigningConfiguration;
+import org.opensaml.xmlsec.algorithm.AlgorithmRegistry;
+import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
+import org.opensaml.xmlsec.criterion.SignatureSigningConfigurationCriterion;
+import org.opensaml.xmlsec.impl.AbstractSecurityParametersResolver;
+import org.opensaml.xmlsec.impl.AlgorithmRuntimeSupportedPredicate;
+import org.opensaml.xmlsec.impl.BasicSignatureSigningParametersResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import net.shibboleth.oidc.security.JWTSignatureSigningParameters;
+import net.shibboleth.oidc.security.JWTSignatureSigningParametersResolver;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.logic.PredicateSupport;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/**
+ * 
+ * Basic implementation of {@link JWTSignatureSigningParametersResolver}.
+ * 
+ * <p>
+ * The following {@link net.shibboleth.utilities.java.support.resolver.Criterion} inputs are supported:
+ * </p>
+ * <ul>
+ * <li>{@link SignatureSigningConfigurationCriterion} - required</li> 
+ * </ul>
+ * <p>See also (for the SAML case) {@link BasicSignatureSigningParametersResolver}.</p>
+ */
+public class BasicJWTSignatureSigningParametersResolver 
+    extends AbstractSecurityParametersResolver<JWTSignatureSigningParameters> 
+    implements JWTSignatureSigningParametersResolver {
+    
+    private final Logger log = LoggerFactory.getLogger(BasicJWTSignatureSigningParametersResolver.class);
+    
+    /** The AlgorithmRegistry used when processing algorithm URIs. */
+    private AlgorithmRegistry algorithmRegistry;
+    
+    /** Constructor. */
+    public BasicJWTSignatureSigningParametersResolver() {
+        algorithmRegistry = AlgorithmSupport.getGlobalAlgorithmRegistry();
+    }
+    
+    /**
+     * Get the {@link AlgorithmRegistry} instance used when resolving algorithm URIs. Defaults to
+     * the registry obtained via {@link AlgorithmSupport#getGlobalAlgorithmRegistry()}.
+     * 
+     * @return the algorithm registry instance
+     */
+    public AlgorithmRegistry getAlgorithmRegistry() {
+        // Handle case where this resolver was constructed before the library was properly initialized.
+        if (algorithmRegistry == null) {
+            return AlgorithmSupport.getGlobalAlgorithmRegistry();
+        }
+        return algorithmRegistry;
+    }
+
+    /**
+     * Set the {@link AlgorithmRegistry} instance used when resolving algorithm URIs. Defaults to
+     * the registry obtained via {@link AlgorithmSupport#getGlobalAlgorithmRegistry()}.
+     * 
+     * @param registry the new algorithm registry instance
+     */
+    public void setAlgorithmRegistry(@Nonnull final AlgorithmRegistry registry) {
+        algorithmRegistry = Constraint.isNotNull(registry, "AlgorithmRegistry was null");
+    }
+
+    @Override
+    @Nonnull
+    public Iterable<JWTSignatureSigningParameters> resolve(@Nonnull final CriteriaSet criteria) throws ResolverException {
+        final JWTSignatureSigningParameters params = resolveSingle(criteria);
+        if (params != null) {
+            return Collections.singletonList(params);
+        }
+        return Collections.emptyList();
+    }
+
+    @Override
+    @Nullable
+    public JWTSignatureSigningParameters resolveSingle(@Nonnull final CriteriaSet criteria) throws ResolverException {
+        Constraint.isNotNull(criteria, "CriteriaSet was null");
+        Constraint.isNotNull(criteria.get(SignatureSigningConfigurationCriterion.class), 
+                "Resolver requires an instance of SignatureSigningConfigurationCriterion");
+        
+        final Predicate<String> includeExcludePredicate = getIncludeExcludePredicate(criteria);
+        
+        final JWTSignatureSigningParameters params = new JWTSignatureSigningParameters();
+        
+        resolveAndPopulateCredentialAndSignatureAlgorithm(params, criteria, includeExcludePredicate);
+        
+        if (validate(params)) {
+            logResult(params);
+            return params;
+        }
+        return null;
+    }
+    
+    /**
+     * Log the resolved parameters.
+     * 
+     * @param params the resolved param
+     */
+    protected void logResult(@Nonnull final JWTSignatureSigningParameters params) {
+        if (log.isDebugEnabled()) {
+            log.debug("Resolved SignatureSigningParameters:");
+            
+            final Key signingKey = CredentialSupport.extractSigningKey(params.getSigningCredential());
+            if (signingKey != null) {
+                log.debug("\tSigning credential with key algorithm: {}", signingKey.getAlgorithm());
+            } else {
+                log.debug("\tSigning credential: null"); 
+            }
+            
+            log.debug("\tSignature algorithm URI: {}", params.getSignatureAlgorithm()); 
+        }
+    }
+    
+    /**
+     * Validate that the {@link JWTSignatureSigningParameters} instance has all the required properties populated.
+     * 
+     * @param params the parameters instance to evaluate
+     * 
+     * @return true if parameters instance passes validation, false otherwise
+     */
+    protected boolean validate(@Nonnull final JWTSignatureSigningParameters params) {
+        if (params.getSigningCredential() == null) {
+            log.warn("Validation failure: Unable to resolve signing credential");
+            return false;
+        }
+        if (params.getSignatureAlgorithm() == null) {
+            log.warn("Validation failure: Unable to resolve signing algorithm URI");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Get a predicate which implements the effective configured include/exclude policy.
+     * 
+     * @param criteria the input criteria being evaluated
+     * 
+     * @return include/exclude predicate instance
+     */
+    @Nonnull protected Predicate<String> getIncludeExcludePredicate(@Nonnull final CriteriaSet criteria) {
+        return resolveIncludeExcludePredicate(criteria, 
+                criteria.get(SignatureSigningConfigurationCriterion.class).getConfigurations());
+    }
+
+    /**
+     * Resolve and populate the signing credential and signature method algorithm URI on the 
+     * supplied parameters instance.
+     * 
+     * @param params the parameters instance being populated
+     * @param criteria the input criteria being evaluated
+     * @param includeExcludePredicate the include/exclude predicate with which to evaluate the 
+     *          candidate signing method algorithm URIs
+     */
+    protected void resolveAndPopulateCredentialAndSignatureAlgorithm(@Nonnull final JWTSignatureSigningParameters params, 
+            @Nonnull final CriteriaSet criteria, final Predicate<String> includeExcludePredicate) {
+        
+        final List<Credential> credentials = getEffectiveSigningCredentials(criteria);
+        final List<String> algorithms = getEffectiveSignatureAlgorithms(criteria, includeExcludePredicate);
+        log.trace("Resolved effective signature algorithms: {}", algorithms);
+        
+        for (final Credential credential : credentials) {
+            if (log.isTraceEnabled()) {
+                final Key key = CredentialSupport.extractSigningKey(credential);
+                log.trace("Evaluating credential of type: {}", key != null ? key.getAlgorithm() : "n/a");
+            }
+            for (final String algorithm : algorithms) {
+                log.trace("Evaluating credential against algorithm: {}", algorithm);
+                if (credentialSupportsAlgorithm(credential, algorithm)) {
+                    log.trace("Credential passed eval against algorithm: {}", algorithm);
+                    params.setSigningCredential(credential);
+                    params.setSignatureAlgorithm(algorithm);
+                    return;
+                }
+                log.trace("Credential failed eval against algorithm: {}", algorithm);
+            }
+        }
+        
+    }
+    
+    /**
+     * Get a predicate which evaluates whether a cryptographic algorithm is supported
+     * by the runtime environment.
+     * 
+     * @return the predicate
+     */
+    @Nonnull protected Predicate<String> getAlgorithmRuntimeSupportedPredicate() {
+        return new AlgorithmRuntimeSupportedPredicate(getAlgorithmRegistry());
+    }
+
+    /**
+     * Evaluate whether the specified credential is supported for use with the specified algorithm URI.
+     * 
+     * @param credential the credential to evaluate
+     * @param algorithm the algorithm URI to evaluate
+     * @return true if credential may be used with the supplied algorithm URI, false otherwise
+     */
+    protected boolean credentialSupportsAlgorithm(@Nonnull final Credential credential, 
+            @Nonnull @NotEmpty final String algorithm) {
+        
+        return AlgorithmSupport.credentialSupportsAlgorithmForSigning(credential, 
+                getAlgorithmRegistry().get(algorithm));
+    }
+
+    /**
+     * Get the effective list of signing credentials to consider.
+     * 
+     * @param criteria the input criteria being evaluated
+     * @return the list of credentials
+     */
+    @Nonnull protected List<Credential> getEffectiveSigningCredentials(@Nonnull final CriteriaSet criteria) {
+        final ArrayList<Credential> accumulator = new ArrayList<>();
+        for (final SignatureSigningConfiguration config : criteria.get(SignatureSigningConfigurationCriterion.class)
+                .getConfigurations()) {
+            
+            accumulator.addAll(config.getSigningCredentials());
+            
+        }
+        return accumulator;
+    }
+    
+    /**
+     * Get the effective list of signature algorithm URIs to consider, including application of 
+     * include/exclude policy.
+     * 
+     * @param criteria the input criteria being evaluated
+     * @param includeExcludePredicate  the include/exclude predicate to use
+     * @return the list of effective algorithm URIs
+     */
+    @Nonnull protected List<String> getEffectiveSignatureAlgorithms(@Nonnull final CriteriaSet criteria, 
+            @Nonnull final Predicate<String> includeExcludePredicate) {
+        final ArrayList<String> accumulator = new ArrayList<>();
+        for (final SignatureSigningConfiguration config : criteria.get(SignatureSigningConfigurationCriterion.class)
+                .getConfigurations()) {
+            
+            config.getSignatureAlgorithms()
+                .stream()
+                .filter(PredicateSupport.and(getAlgorithmRuntimeSupportedPredicate(), includeExcludePredicate))
+                .forEach(accumulator::add);
+        }
+        return accumulator;
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DefaultJWTDecryptionParametersResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DefaultJWTDecryptionParametersResolver.java
index 6217bd0..148d894 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DefaultJWTDecryptionParametersResolver.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/DefaultJWTDecryptionParametersResolver.java
@@ -10,7 +10,7 @@ import org.opensaml.xmlsec.impl.AbstractSecurityParametersResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import net.shibboleth.oidc.security.DecryptionConfiguration;
+import net.shibboleth.oidc.security.JWTDecryptionConfiguration;
 import net.shibboleth.oidc.security.JWTDecryptionParameters;
 import net.shibboleth.oidc.security.JWTDecryptionParametersResolver;
 import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
@@ -68,7 +68,7 @@ public class DefaultJWTDecryptionParametersResolver extends AbstractSecurityPara
     @Nullable protected JOSEObjectCredentialResolver resolveKEKCredentialResolver(
             @Nonnull final CriteriaSet criteria) {
         
-        for (final DecryptionConfiguration config : criteria.get(DecryptionConfigurationCriterion.class)
+        for (final JWTDecryptionConfiguration config : criteria.get(DecryptionConfigurationCriterion.class)
                 .getConfigurations()) {
             if (config.getKEKCredentialResolver() != null) {
                 return config.getKEKCredentialResolver();
@@ -87,7 +87,7 @@ public class DefaultJWTDecryptionParametersResolver extends AbstractSecurityPara
     @Nullable protected JOSEObjectCredentialResolver resolveContentEncryptionKeyCredentialResolver(
             @Nonnull final CriteriaSet criteria) {
         
-        for (final DecryptionConfiguration config : criteria.get(DecryptionConfigurationCriterion.class)
+        for (final JWTDecryptionConfiguration config : criteria.get(DecryptionConfigurationCriterion.class)
                 .getConfigurations()) {
             if (config.getContentEncryptionKeyCredentialResolver() != null) {
                 return config.getContentEncryptionKeyCredentialResolver();
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/PopulateJWTSignatureSigningParameters.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/PopulateJWTSignatureSigningParameters.java
index c74f997..55f7e96 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/PopulateJWTSignatureSigningParameters.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/PopulateJWTSignatureSigningParameters.java
@@ -13,17 +13,15 @@ import org.opensaml.messaging.context.navigate.ContextDataLookupFunction;
 import org.opensaml.profile.action.AbstractHandlerDelegatingProfileAction;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
 import org.opensaml.profile.context.navigate.OutboundMessageContextLookup;
 import org.opensaml.xmlsec.SecurityConfigurationSupport;
 import org.opensaml.xmlsec.SignatureSigningConfiguration;
-import org.opensaml.xmlsec.SignatureSigningParametersResolver;
-import org.opensaml.xmlsec.context.SecurityParametersContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
 import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
+import net.shibboleth.oidc.security.JWTSignatureSigningParametersResolver;
 import net.shibboleth.oidc.security.context.JWTSecurityParametersContext;
 import net.shibboleth.utilities.java.support.annotation.ParameterName;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
@@ -55,7 +53,7 @@ public class PopulateJWTSignatureSigningParameters
     private Function<ProfileRequestContext, OIDCProviderMetadataContext> oidcProviderMetadataContextLookupStrategy;
     
     /** Resolver for parameters to store into context. */
-    @NonnullAfterInit private SignatureSigningParametersResolver resolver;
+    @NonnullAfterInit private JWTSignatureSigningParametersResolver resolver;
     
     /** Whether failure to resolve parameters should be raised as an error. */
     private boolean noResultIsError;
@@ -147,7 +145,8 @@ public class PopulateJWTSignatureSigningParameters
      * 
      * @param newResolver resolver to use
      */
-    public void setSignatureSigningParametersResolver(@Nonnull final SignatureSigningParametersResolver newResolver) {
+    public void setSignatureSigningParametersResolver(
+            @Nonnull final JWTSignatureSigningParametersResolver newResolver) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
         resolver = Constraint.isNotNull(newResolver, "SignatureSigningParametersResolver cannot be null");
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/PopulateJWTSignatureSigningParametersHandler.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/PopulateJWTSignatureSigningParametersHandler.java
index d09da47..707fc29 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/PopulateJWTSignatureSigningParametersHandler.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/PopulateJWTSignatureSigningParametersHandler.java
@@ -32,8 +32,6 @@ import org.opensaml.messaging.handler.MessageHandlerException;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.xmlsec.SecurityConfigurationSupport;
 import org.opensaml.xmlsec.SignatureSigningConfiguration;
-import org.opensaml.xmlsec.SignatureSigningParameters;
-import org.opensaml.xmlsec.SignatureSigningParametersResolver;
 import org.opensaml.xmlsec.context.SecurityParametersContext;
 import org.opensaml.xmlsec.criterion.SignatureSigningConfigurationCriterion;
 import org.slf4j.Logger;
@@ -43,6 +41,8 @@ import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.oidc.metadata.context.OIDCMetadataContext;
 import net.shibboleth.oidc.metadata.context.OIDCProviderMetadataContext;
 import net.shibboleth.oidc.profile.config.OIDCAuthorizationConfiguration;
+import net.shibboleth.oidc.security.JWTSignatureSigningParameters;
+import net.shibboleth.oidc.security.JWTSignatureSigningParametersResolver;
 import net.shibboleth.oidc.security.context.JWTSecurityParametersContext;
 import net.shibboleth.oidc.security.criterion.ClientInformationCriterion;
 import net.shibboleth.oidc.security.criterion.ProviderMetadataCriterion;
@@ -80,7 +80,7 @@ public class PopulateJWTSignatureSigningParametersHandler extends AbstractMessag
     @Nonnull private Function<MessageContext, RelyingPartyContext> relyingPartyContextLookupStrategy;
     
     /** Resolver for parameters to store into context. */
-    @NonnullAfterInit private SignatureSigningParametersResolver resolver;
+    @NonnullAfterInit private JWTSignatureSigningParametersResolver resolver;
     
     /** Whether failure to resolve parameters should be raised as an error. */
     private boolean noResultIsError;
@@ -151,7 +151,8 @@ public class PopulateJWTSignatureSigningParametersHandler extends AbstractMessag
      * 
      * @param newResolver resolver to use
      */
-    public void setSignatureSigningParametersResolver(@Nonnull final SignatureSigningParametersResolver newResolver) {
+    public void setSignatureSigningParametersResolver(
+            @Nonnull final JWTSignatureSigningParametersResolver newResolver) {
         ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
 
         resolver = Constraint.isNotNull(newResolver, "SignatureSigningParametersResolver cannot be null");
@@ -297,7 +298,7 @@ public class PopulateJWTSignatureSigningParametersHandler extends AbstractMessag
         }
 
         try {
-            final SignatureSigningParameters params = resolver.resolveSingle(criteria);
+            final JWTSignatureSigningParameters params = resolver.resolveSingle(criteria);
             if (params == null && noResultIsError) {
                 log.error("Failed to resolve SignatureSigningParameters");
                 throw new MessageHandlerException("Failed to resolve SignatureSigningParameters");
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
new file mode 100644
index 0000000..a0a5b15
--- /dev/null
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/BasicJWTEncryptionParametersResolverTest.java
@@ -0,0 +1,400 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.oidc.security.impl;
+
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+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;
+import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.RSAKey;
+import com.nimbusds.jose.jwk.gen.ECKeyGenerator;
+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.JWKCredential;
+import net.shibboleth.oidc.security.criterion.JWTEncryptionConfigurationCriterion;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+
+public class BasicJWTEncryptionParametersResolverTest {
+    
+    /** The mock symmetric key e.g. for keywrap.*/
+    private static final String SYMMETRIC_KEY = "/A?D(G+KbPdSgVkYp3s6v9y$B&E)H at Mc";
+    
+    private BasicJWTEncryptionParametersResolver resolver;
+    
+    private BasicJWTEncryptionConfiguration config;
+            
+    
+    @BeforeMethod
+    public void setUp() {
+      //Create an algorithm registry here, as opensaml init will not take place for these tests      
+        try {
+            final GlobalAlgorithmRegistryInitializer gar = new GlobalAlgorithmRegistryInitializer();
+            gar.init();
+        } catch (final InitializationException e) {
+            fail();
+        }
+        
+        resolver = new BasicJWTEncryptionParametersResolver();
+    }
+    
+    private CriteriaSet buildBasicCriteriaSet() throws Exception {        
+        
+        config = new BasicJWTEncryptionConfiguration();
+        config.setKeyTransportEncryptionAlgorithms(
+                List.of(KeyManagementConstants.ALGO_ID_ALG_AES_128_KW, KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256,
+                KeyManagementConstants.ALGO_ID_ALG_ECDH_ES_AES_192_KW, KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP));
+        config.setDataEncryptionAlgorithms(
+                List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256,EncryptionConstants.ALGO_ID_ENC_ALG_A128GCM,
+                        EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
+        final CriteriaSet criteria = new CriteriaSet(new JWTEncryptionConfigurationCriterion(List.of(config)));       
+        return criteria;
+    }
+
+    @Test
+    public void testBasicRSA() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        final RSAKey key = new RSAKeyGenerator(2048)
+                .algorithm(JWEAlgorithm.RSA_OAEP_256)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID("mock-key")
+                .generate();
+        config.setKeyTransportEncryptionCredentials(List.of(createKeyEncryptionCredential(key)));
+        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());
+       
+    }
+    
+    @Test
+    public void testBasicEC() 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();
+        config.setKeyTransportEncryptionCredentials(List.of(createKeyAgreementCredential(key)));
+        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());
+       
+    }
+    
+    @Test
+    public void testBasicAESKeyWrap() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(
+                List.of(KeyManagementConstants.ALGO_ID_ALG_AES_256_KW));        
+        config.setKeyTransportEncryptionCredentials(List.of(createSharedSecretCredential("mock-key",
+                SYMMETRIC_KEY, JWEAlgorithm.A256KW)));
+        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());
+       
+    }
+    
+    /* Dir is not supported by the runtime.*/
+    @Test(enabled = false)
+    public void testBasicDirectEncryption() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(
+                List.of(KeyManagementConstants.ALGO_ID_ALG_DIR));        
+        config.setDataEncryptionCredentials(List.of(createSharedSecretCredential("mock-key",
+                SYMMETRIC_KEY, JWEAlgorithm.DIR)));
+        
+        final JWTEncryptionParameters param = resolver.resolveSingle(criteria);            
+        assertNotNull(param);
+        assertNotNull(param.getDataEncryptionAlgorithm());
+        assertNotNull(param.getKeyTransportEncryptionAlgorithm());  
+        assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512);
+        assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_DIR);
+        assertNotNull(param.getDataEncryptionCredential());
+        assertNotNull(param.getDataEncryptionCredential().getSecretKey());
+
+    }
+    
+    /* Dir is not supported by the runtime.*/
+    @Test(enabled = false)
+    public void testBasicDirectEncryption_WhereOtherAlgsSupported() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(
+                List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256, KeyManagementConstants.ALGO_ID_ALG_DIR));        
+        config.setDataEncryptionCredentials(List.of(createSharedSecretCredential("mock-key",
+                SYMMETRIC_KEY, JWEAlgorithm.DIR)));
+        
+        final JWTEncryptionParameters param = resolver.resolveSingle(criteria);            
+        assertNotNull(param);
+        assertNotNull(param.getDataEncryptionAlgorithm());
+        assertNotNull(param.getKeyTransportEncryptionAlgorithm());  
+        assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512);
+        assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_DIR);
+        assertNotNull(param.getDataEncryptionCredential());
+        assertNotNull(param.getDataEncryptionCredential().getSecretKey());
+    }
+    
+    /* The key is 256bit and does not support the 128bit enc. algo.*/
+    @Test
+    public void testBasicDirectEncryption_NoSupportedDataEncryptionMethods() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(
+                List.of(KeyManagementConstants.ALGO_ID_ALG_DIR));        
+        config.setDataEncryptionCredentials(List.of(createSharedSecretCredential("mock-key",
+                SYMMETRIC_KEY, JWEAlgorithm.DIR)));
+        config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A128CBC_HS256));
+        
+        final JWTEncryptionParameters param = resolver.resolveSingle(criteria);            
+        assertNull(param);
+    }
+    
+    /* Dir is not supported by the runtime.*/
+    @Test(enabled = false)
+    public void testBasicDirectEncryption_WhereOtherKeysExist_DirFirst() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(
+                List.of(KeyManagementConstants.ALGO_ID_ALG_DIR, KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256)); 
+        final RSAKey key = new RSAKeyGenerator(2048)
+                .algorithm(JWEAlgorithm.RSA_OAEP_256)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID("mock-key")
+                .generate();
+        config.setKeyTransportEncryptionCredentials(List.of(createKeyEncryptionCredential(key)));
+        config.setDataEncryptionCredentials(List.of(createSharedSecretCredential("mock-key",
+                SYMMETRIC_KEY, JWEAlgorithm.DIR)));
+        config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
+        
+        final JWTEncryptionParameters param = resolver.resolveSingle(criteria);            
+        assertNotNull(param);
+        assertNotNull(param.getDataEncryptionAlgorithm());
+        assertNotNull(param.getKeyTransportEncryptionAlgorithm());  
+        assertEquals(param.getDataEncryptionAlgorithm(),EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512);
+        assertEquals(param.getKeyTransportEncryptionAlgorithm(),KeyManagementConstants.ALGO_ID_ALG_DIR);
+        assertNotNull(param.getDataEncryptionCredential());
+        assertNotNull(param.getDataEncryptionCredential().getSecretKey());
+    }
+    
+    @Test
+    public void testBasicDirectEncryption_WhereOtherKeysExist_RSAFirst() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(
+                List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256,KeyManagementConstants.ALGO_ID_ALG_DIR)); 
+        final RSAKey key = new RSAKeyGenerator(2048)
+                .algorithm(JWEAlgorithm.RSA_OAEP_256)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID("mock-key")
+                .generate();
+        config.setKeyTransportEncryptionCredentials(List.of(createKeyEncryptionCredential(key)));
+        config.setDataEncryptionCredentials(List.of(createSharedSecretCredential("mock-key",
+                SYMMETRIC_KEY, JWEAlgorithm.DIR)));
+        config.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_ENC_ALG_A256CBC_HS512));
+        
+        final JWTEncryptionParameters param = resolver.resolveSingle(criteria);            
+        assertNotNull(param);
+        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_256);
+        assertNotNull(param.getKeyTransportEncryptionCredential());
+        assertNotNull(param.getKeyTransportEncryptionCredential().getPublicKey());
+    }
+    
+    @Test
+    public void testBasicRSA_WrongAlgorithmInKey() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256));
+        final RSAKey key = new RSAKeyGenerator(2048)
+                .algorithm(JWEAlgorithm.RSA_OAEP)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID("mock-key")
+                .generate();
+        config.setKeyTransportEncryptionCredentials(List.of(createKeyEncryptionCredential(key)));
+        final JWTEncryptionParameters param = resolver.resolveSingle(criteria);
+        
+        assertNull(param);           
+    }
+    
+    @Test
+    public void testBasicRSA_WrongAlgorithmInFirstKey_ChooseSecondKey() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256));
+        final RSAKey key = new RSAKeyGenerator(2048)
+                .algorithm(JWEAlgorithm.RSA_OAEP)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID("mock-key-wrong-type")
+                .generate();
+        final RSAKey keyCorrect = new RSAKeyGenerator(2048)
+                .algorithm(JWEAlgorithm.RSA_OAEP_256)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID("mock-key-correct-type")
+                .generate();
+        config.setKeyTransportEncryptionCredentials(List.of(createKeyEncryptionCredential(key),
+                createKeyEncryptionCredential(keyCorrect)));
+        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());
+        assertTrue(param.getKeyTransportEncryptionCredential().getKeyNames().contains("mock-key-correct-type"));
+    }
+    
+    @Test
+    public void testBasicRSAAndDir_NoSuitableKeys() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP_256, 
+                KeyManagementConstants.ALGO_ID_ALG_DIR));
+        final RSAKey key = new RSAKeyGenerator(2048)
+                .algorithm(JWEAlgorithm.RSA_OAEP)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID("mock-key-wrong-type")
+                .generate();        
+        config.setKeyTransportEncryptionCredentials(List.of(createKeyEncryptionCredential(key)));
+        config.setDataEncryptionCredentials(List.of(createSharedSecretCredential("mock-key",
+                SYMMETRIC_KEY, JWEAlgorithm.A128KW)));
+        final JWTEncryptionParameters param = resolver.resolveSingle(criteria);
+        
+        assertNull(param);       
+    }
+    
+    @Test
+    public void testBasicRSA_WrongAlgorithmInConfig() throws Exception {
+        final CriteriaSet criteria =  buildBasicCriteriaSet();
+        config.setKeyTransportEncryptionAlgorithms(List.of(KeyManagementConstants.ALGO_ID_ALG_RSA_OAEP));
+        final RSAKey key = new RSAKeyGenerator(2048)
+                .algorithm(JWEAlgorithm.RSA_OAEP_256)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID("mock-key")
+                .generate();
+        config.setKeyTransportEncryptionCredentials(List.of(createKeyEncryptionCredential(key)));
+        final JWTEncryptionParameters param = resolver.resolveSingle(criteria);
+        
+        assertNull(param);           
+    }
+    
+    /**
+     * Create a key encryption {@link JWKCredential} from the given RSA key.
+     * 
+     * @param secret the RSAKey to convert to a {@link JWKCredential}.
+     * 
+     * @return the credential
+     * @throws JOSEException  on error
+     */
+    public JWKCredential createKeyEncryptionCredential(final RSAKey secret) throws JOSEException {
+        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+        jwkCredential.setPrivateKey(secret.toPrivateKey());
+        jwkCredential.setPublicKey(secret.toPublicKey());
+        jwkCredential.setCredentialExpiresAt(Duration.ZERO);
+        jwkCredential.setUsageType(UsageType.ENCRYPTION);
+        
+        jwkCredential.setKid(secret.getKeyID());
+        jwkCredential.getKeyNames().add(secret.getKeyID());
+        jwkCredential.setAlgorithm(secret.getAlgorithm());
+        return jwkCredential;
+    }
+    
+    /**
+     * Create a key agreement encryption {@link JWKCredential} from the given EC key.
+     * 
+     * @param secret the ECKey to convert to a {@link JWKCredential}.
+     * 
+     * @return the credential
+     * @throws JOSEException  on error
+     */
+    public JWKCredential createKeyAgreementCredential(final ECKey secret) throws JOSEException {
+        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+        jwkCredential.setPrivateKey(secret.toPrivateKey());
+        jwkCredential.setPublicKey(secret.toPublicKey());
+        jwkCredential.setCredentialExpiresAt(Duration.ZERO);
+        jwkCredential.setUsageType(UsageType.ENCRYPTION);
+        
+        jwkCredential.setKid(secret.getKeyID());
+        jwkCredential.getKeyNames().add(secret.getKeyID());
+        jwkCredential.setAlgorithm(secret.getAlgorithm());
+        return jwkCredential;
+    }
+    
+    /**
+     * Create a simple symmetric key client credential from from the given shared secret.
+     * 
+     * @param kid the key ID
+     * @param secret the secret to convert to a {@link JWKCredential}.
+     * @param algorithm the JWA algorithm to set on the credential.
+     * 
+     * @return the credential
+     * @throws KeyException on error creating the key
+     */
+    public JWKCredential createSharedSecretCredential(final String kid, final String secret, 
+            final Algorithm algorithm) 
+            throws KeyException {
+        final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
+        jwkCredential.setSecretKey(KeySupport.decodeSecretKey(JWSAssemblyUtils.getSecretBytes(secret), "AES"));
+        jwkCredential.setCredentialExpiresAt(Duration.ZERO);
+        jwkCredential.setUsageType(UsageType.UNSPECIFIED);
+        jwkCredential.setKid(kid);
+        jwkCredential.setAlgorithm(algorithm);
+        jwkCredential.getKeyNames().add("mockKey");
+        return jwkCredential;
+    }
+    
+}
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
index 1bd1791..36e7cb2 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/ExplicitKeySignedJWTTrustEngineTest.java
@@ -98,7 +98,8 @@ public class ExplicitKeySignedJWTTrustEngineTest {
         assertTrue(valid);
     }
     
-    @Test
+    /* JKU resolution not currently supported by the joseObjectCredResolver.*/
+    @Test(enabled = false)
     public void testSuccess_WithInlineJKU() throws JOSEException, SecurityException, URISyntaxException { 
         
         // Create a new resolver which does not resolve any creds, the JKU ones need to be resolved.
diff --git a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCSecurityConfiguration.java b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCSecurityConfiguration.java
index 45d1c2b..24b72b8 100644
--- a/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCSecurityConfiguration.java
+++ b/oidc-common-profile-api/src/main/java/net/shibboleth/oidc/profile/config/OIDCSecurityConfiguration.java
@@ -25,6 +25,7 @@ import org.opensaml.xmlsec.SignatureSigningConfiguration;
 import com.nimbusds.jwt.SignedJWT;
 
 import net.shibboleth.idp.profile.config.SecurityConfiguration;
+import net.shibboleth.oidc.security.JWTEncryptionConfiguration;
 
 /**
  * Class extends SecurityConfiguration to support separate configuration for request object decryption and signature
@@ -34,10 +35,16 @@ import net.shibboleth.idp.profile.config.SecurityConfiguration;
 public class OIDCSecurityConfiguration extends SecurityConfiguration {
 
     /** Configuration used when decrypting request object information. */
+    //TODO Used by OP only? but should be decrypt config
     @Nullable
     private EncryptionConfiguration requestObjectDecryptConfig;
+    
+    /** Configuration used when encrypting request object information. */
+    @Nullable
+    private JWTEncryptionConfiguration requestObjectEncryptionConfig;
 
     /** Configuration used when validating request object information. */
+    //TODO JWT version of these?
     @Nullable
     private SignatureSigningConfiguration requestObjectSignatureValidationConfig;
     
@@ -55,11 +62,11 @@ public class OIDCSecurityConfiguration extends SecurityConfiguration {
     
     /** Configuration used when decrypting id_tokens. */
     @Nullable
-    private net.shibboleth.oidc.security.DecryptionConfiguration idTokenJwtDecryptConfig;
+    private net.shibboleth.oidc.security.JWTDecryptionConfiguration idTokenJwtDecryptConfig;
     
     /** Configuration used when decrypting UserInfo tokens. */
     @Nullable
-    private net.shibboleth.oidc.security.DecryptionConfiguration userInfoJwtDecryptConfig;
+    private net.shibboleth.oidc.security.JWTDecryptionConfiguration userInfoJwtDecryptConfig;
     
     /** Configuration used when validating UserInfo JWT signatures. */
     @Nullable
@@ -71,7 +78,7 @@ public class OIDCSecurityConfiguration extends SecurityConfiguration {
      * @param config configuration used when decrypting id_tokens, or null
      */
     public void setIdTokenJwtDecryptionConfiguration(@Nullable final 
-            net.shibboleth.oidc.security.DecryptionConfiguration config) {
+            net.shibboleth.oidc.security.JWTDecryptionConfiguration config) {
         idTokenJwtDecryptConfig = config;
     }
     
@@ -80,7 +87,7 @@ public class OIDCSecurityConfiguration extends SecurityConfiguration {
      * 
      * @return configuration used when decrypting id_tokens, or null
      */
-    @Nullable public net.shibboleth.oidc.security.DecryptionConfiguration getIdtokenJwtDecryptionConfiguration() {
+    @Nullable public net.shibboleth.oidc.security.JWTDecryptionConfiguration getIdtokenJwtDecryptionConfiguration() {
         return idTokenJwtDecryptConfig;
     }
     
@@ -90,16 +97,34 @@ public class OIDCSecurityConfiguration extends SecurityConfiguration {
      * @param config configuration used when decrypting UserInfo JWTs, or null
      */
     public void setUserInfoJwtDecryptionConfiguration(@Nullable final 
-            net.shibboleth.oidc.security.DecryptionConfiguration config) {
+            net.shibboleth.oidc.security.JWTDecryptionConfiguration config) {
         userInfoJwtDecryptConfig = config;
     }
     
+    /**
+     * Get the configuration used when encrypting RequestObject JWTs.
+     * 
+     * @return configuration used when decrypting id_tokens, or null
+     */
+    @Nullable public JWTEncryptionConfiguration getRequestObjectEncryptionConfig() {
+        return requestObjectEncryptionConfig;
+    }
+    
+    /**
+     * Set the configuration used to encrypt the RequestObject JWT.
+     * 
+     * @param config configuration used when encrypting RequestObject JWTs, or null
+     */
+    public void setRequestObjectEncryptionConfig(@Nullable final JWTEncryptionConfiguration config) {
+        requestObjectEncryptionConfig = config;
+    }
+    
     /**
      * Get the configuration used when decrypting UserInfo JWTs.
      * 
      * @return configuration used when decrypting UserInfo JWTs, or null
      */
-    @Nullable public net.shibboleth.oidc.security.DecryptionConfiguration getUserInfoJwtDecryptionConfiguration() {
+    @Nullable public net.shibboleth.oidc.security.JWTDecryptionConfiguration getUserInfoJwtDecryptionConfiguration() {
         return userInfoJwtDecryptConfig;
     }
 

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list