[java-oidc-common] 18/35: Add further criterion to JWT Decrypter

Phil Smart philip.smart at jisc.ac.uk
Tue Sep 20 14:19:18 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=dace601102043f38b52ef470a6e685f5211649d3

commit dace601102043f38b52ef470a6e685f5211649d3
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Fri Jul 15 14:48:25 2022 +0100

    Add further criterion to JWT Decrypter
    
    With differences between which criterion are build between the 'alg'
    header and the 'enc' header
---
 .../impl/JWKEncryptionCredentialContext.java       |  54 ----
 .../impl/LocalJOSEObjectCredentialResolver.java    |  48 ++++
 .../impl/StaticJOSEObjectCredentialResolver.java   |  50 ++++
 ...piringJWTSharedSecretCredentialFactoryBean.java |  35 +--
 .../oidc/security/impl/JWTDecrypter.java           | 277 ++++++++++++---------
 .../oidc/security/impl/JWTDecrypterTest.java       | 269 ++++++++++++++++++--
 6 files changed, 521 insertions(+), 212 deletions(-)

diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/JWKEncryptionCredentialContext.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/JWKEncryptionCredentialContext.java
deleted file mode 100644
index 05a355d..0000000
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/JWKEncryptionCredentialContext.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.credential.impl;
-
-import javax.annotation.Nonnull;
-
-import org.opensaml.security.credential.CredentialContext;
-
-import com.nimbusds.jose.EncryptionMethod;
-
-import net.shibboleth.utilities.java.support.logic.Constraint;
-
-/**
- * A {@link CredentialContext} that holds additional JWE information.
- */
-public class JWKEncryptionCredentialContext implements CredentialContext {
-    
-    /** The encryption algorithm associated with this credential.*/
-    @Nonnull private final EncryptionMethod encryptionAlgorithm;
-    
-    /**
-     * 
-     * Constructor.
-     *
-     * @param enc the encryption (enc) methods associated with this credential.
-     */
-    public JWKEncryptionCredentialContext(@Nonnull final EncryptionMethod enc) {
-        encryptionAlgorithm = Constraint.isNotNull(enc, "Encryption method can not be null");
-    }
-    
-    /**
-     * Get the encryption algorithm associated with this credential.
-     * 
-     * @return the encryption algorithm
-     */
-    public EncryptionMethod getEncryptionAlgorithm() {
-        return encryptionAlgorithm;
-    }
-}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java
new file mode 100644
index 0000000..a2cdd45
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/LocalJOSEObjectCredentialResolver.java
@@ -0,0 +1,48 @@
+package net.shibboleth.oidc.security.credential.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.CredentialResolver;
+import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider;
+
+import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+/**
+ * A simple specialization of {@link BasicJOSEObjectCredentialResolver}
+ * which is capable of using information from a {@link org.opensaml.xmlsec.signature.KeyInfo} to resolve
+ * local credentials from a supplied {@link CredentialResolver} which manages local credentials.
+ * 
+ * TODO: Finish
+ */
+public class LocalJOSEObjectCredentialResolver extends BasicJOSEObjectCredentialResolver {
+    
+    /** The resolver which is used to resolve local credentials. */
+    private final JOSEObjectCredentialResolver localCredResolver;
+    
+    /**
+     * Constructor.
+     *
+     * @param keyInfoProviders the list of {@link KeyInfoProvider}s to use in this resolver
+     * @param localCredentialResolver resolver of local credentials
+     */
+    public LocalJOSEObjectCredentialResolver(@Nonnull  
+            @ParameterName(name="localCredentialResolver") final JOSEObjectCredentialResolver localCredentialResolver) {
+        
+        localCredResolver = Constraint.isNotNull(localCredentialResolver, "Local credential resolver cannot be null");
+    }
+    
+    @Override
+    @Nonnull protected Iterable<Credential> resolveFromSource(@Nullable final CriteriaSet criteriaSet)
+            throws ResolverException {
+        
+        return localCredResolver.resolve(criteriaSet);
+        
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/StaticJOSEObjectCredentialResolver.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/StaticJOSEObjectCredentialResolver.java
new file mode 100644
index 0000000..8e42170
--- /dev/null
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/credential/impl/StaticJOSEObjectCredentialResolver.java
@@ -0,0 +1,50 @@
+package net.shibboleth.oidc.security.credential.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.security.credential.Credential;
+
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+
+//TODO finish. This should be a local one? This is temporary until it is all figured out
+public class StaticJOSEObjectCredentialResolver extends BasicJOSEObjectCredentialResolver {
+    
+    /** List of credentials held by this resolver. */
+    private final List<Credential> creds;
+    
+    /**
+     * Constructor.
+     *
+     * @param credentials collection of credentials to be held by this resolver
+     */
+    public StaticJOSEObjectCredentialResolver(@Nonnull @ParameterName(name="credentials") final List<Credential> credentials) {
+        Constraint.isNotNull(credentials, "Input credentials list cannot be null");
+        
+        creds = new ArrayList<>(credentials);
+    }
+    
+    /**
+     * Constructor.
+     *
+     * @param credential a single credential to be held by this resolver
+     */
+    public StaticJOSEObjectCredentialResolver(@Nonnull @ParameterName(name="credential") final Credential credential) {
+        Constraint.isNotNull(credential, "Input credential cannot be null");
+        
+        creds = new ArrayList<>();
+        creds.add(credential);
+    }
+
+    @Override
+    @Nonnull public Iterable<Credential> resolveFromSource(@Nullable final CriteriaSet criteria) throws ResolverException {
+        return creds;
+    }
+
+}
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicExpiringJWTSharedSecretCredentialFactoryBean.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicExpiringJWTSharedSecretCredentialFactoryBean.java
index 13dcb11..5929dd2 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicExpiringJWTSharedSecretCredentialFactoryBean.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/BasicExpiringJWTSharedSecretCredentialFactoryBean.java
@@ -22,22 +22,21 @@ import java.util.List;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
-import javax.crypto.spec.SecretKeySpec;
+import javax.crypto.SecretKey;
 
 import org.opensaml.security.credential.UsageType;
+import org.opensaml.security.crypto.KeySupport;
 
 import com.google.common.base.Enums;
 import com.nimbusds.jose.Algorithm;
-import com.nimbusds.jose.EncryptionMethod;
 
 import net.shibboleth.idp.profile.spring.factory.AbstractCredentialFactoryBean;
 import net.shibboleth.oidc.security.credential.BasicExpiringJWKCredential;
 import net.shibboleth.oidc.security.credential.BasicJWKCredential;
 import net.shibboleth.oidc.security.credential.ExpiringJWKCredential;
-import net.shibboleth.oidc.security.credential.impl.JWKEncryptionCredentialContext;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.primitive.StringSupport;
 
 /** A factory bean for creating a {@link BasicExpiringJWKCredential} from the static secret injected.*/
 public class BasicExpiringJWTSharedSecretCredentialFactoryBean extends AbstractCredentialFactoryBean<ExpiringJWKCredential> {
@@ -45,8 +44,8 @@ public class BasicExpiringJWTSharedSecretCredentialFactoryBean extends AbstractC
     /** The secret to use when creating a BasicJWKCredential.*/
     @Nullable private String secret;
     
-    /** If the usage type is ENCRYPTION, this is the encryption method this credential supports.*/
-    @Nullable private EncryptionMethod encMethod;
+    /** The JCA algorithm to set on the {@link SecretKey}. Defaults to AES.*/
+    @Nullable private String jcaAlg = "AES";
     
     /** The algorithm ('alg') this credential supports.*/
     @Nullable private Algorithm alg;
@@ -72,13 +71,14 @@ public class BasicExpiringJWTSharedSecretCredentialFactoryBean extends AbstractC
     }
     
     /**
-     * Set the encryption method associated with this credential. Can be {@literal null} if this
-     * credential does not support encryption, for example is only used for signing. 
+     * Set the JCA Algorithm to associate with this credential. 
      * 
-     * @param method the encryption method. Can be {@literal null}.
+     * @param alg the jca algorithm.
      */
-    public void setEncMethod(@Nullable @NonnullElements final String method) {
-        encMethod = EncryptionMethod.parse(method); 
+    public void setJcaAlg(@Nullable final String alg) {
+        if (StringSupport.trimOrNull(alg) != null) {
+            jcaAlg = alg; 
+        }
     }
     
     /**
@@ -103,7 +103,7 @@ public class BasicExpiringJWTSharedSecretCredentialFactoryBean extends AbstractC
     protected ExpiringJWKCredential doCreateInstance() throws Exception {
         
         final BasicExpiringJWKCredential jwkCredential = new BasicExpiringJWKCredential();
-        jwkCredential.setSecretKey(new SecretKeySpec(JWSAssemblyUtils.getSecretBytes(secret), "NONE"));
+        jwkCredential.setSecretKey(KeySupport.decodeSecretKey(JWSAssemblyUtils.getSecretBytes(secret), jcaAlg));
         jwkCredential.setCredentialExpiresAt(credentialExpiresAt);
         jwkCredential.setEntityId(getEntityID());
         jwkCredential.setAlgorithm(alg);
@@ -116,16 +116,7 @@ public class BasicExpiringJWTSharedSecretCredentialFactoryBean extends AbstractC
         if (keyNames != null) {
             jwkCredential.getKeyNames().addAll(keyNames);
         }
-        // Check if usage is encryption at least one algorithm has been set
-        if (UsageType.ENCRYPTION == jwkCredential.getUsageType() && encMethod == null){
-            throw new Exception("Can not create JWK encryption credential without an encryption method specified");
-        }
-        // Set the enc methods
-        if (encMethod != null) {
-            final JWKEncryptionCredentialContext encContext = new JWKEncryptionCredentialContext(encMethod);
-            jwkCredential.getCredentialContextSet().add(encContext);
-        }        
-        
+                
         return jwkCredential;
     }
 
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWTDecrypter.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWTDecrypter.java
index ddee296..c340611 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWTDecrypter.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/impl/JWTDecrypter.java
@@ -18,10 +18,9 @@
 package net.shibboleth.oidc.security.impl;
 
 import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.RSAPrivateKey;
 import java.text.ParseException;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -32,7 +31,6 @@ import org.opensaml.security.criteria.KeyAlgorithmCriterion;
 import org.opensaml.security.criteria.KeyLengthCriterion;
 import org.opensaml.security.criteria.UsageCriterion;
 import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
-import org.opensaml.xmlsec.encryption.EncryptedType;
 import org.opensaml.xmlsec.encryption.support.DecryptionException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -56,7 +54,6 @@ import org.slf4j.LoggerFactory;
 import com.google.common.base.Strings;
 import com.nimbusds.jose.EncryptionMethod;
 import com.nimbusds.jose.JOSEException;
-import com.nimbusds.jose.JOSEObject;
 import com.nimbusds.jose.JWEAlgorithm;
 import com.nimbusds.jose.JWEDecrypter;
 import com.nimbusds.jose.JWEObject.State;
@@ -71,7 +68,6 @@ import com.nimbusds.jwt.JWTParser;
 import net.shibboleth.oidc.security.JWTDecryptionParameters;
 import net.shibboleth.oidc.security.credential.JWKCredential;
 import net.shibboleth.oidc.security.credential.impl.EvaluableKeyIDCredentialCriterion;
-import net.shibboleth.oidc.security.credential.impl.JWKEncryptionCredentialContext;
 import net.shibboleth.oidc.security.criterion.JOSEObjectCriterion;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.primitive.StringSupport;
@@ -159,14 +155,14 @@ public class JWTDecrypter {
     
     /**
      * Build a criteria set using the additional criteria in the params, those supplied, and those
-     * that can be extracted from the encrypted JWT headers.
+     * that relating to the encrypted JWT.
      * 
      * @param encryptedObject the encrypted JWT to build criterion from
      * @param criteria criteria supplied, can be {@literal null}.
      * 
      * @return the build criteria set.
      */
-    private CriteriaSet buildCriteria(@Nonnull final EncryptedJWT encryptedObject, 
+    @Nonnull private CriteriaSet buildCriteria(@Nonnull final EncryptedJWT encryptedObject, 
             @Nullable final List<Criterion> criteria) {
         final CriteriaSet newCriteriaSet = new CriteriaSet();
         
@@ -180,77 +176,112 @@ public class JWTDecrypter {
         
         // Add the entire object so the resolver can access it
         newCriteriaSet.add(new JOSEObjectCriterion(encryptedObject));
-        
-        final Set<Criterion> keyCriteria = buildKeyCriteria(encryptedObject);
-        if (keyCriteria != null && !keyCriteria.isEmpty()) {
-            newCriteriaSet.addAll(keyCriteria);
+
+        // If 'kid' exists in the header, create an EvaluableKeyID criterion
+        if (encryptedObject.getHeader().getKeyID() != null) {
+            // FIXME: This is created directly as an EvaluableCriterion as I can not see a way to 
+            // add to the default mappings in EvaluableCredentialCriteriaRegistry without overriding the opensaml
+            // version
+            newCriteriaSet.add(new EvaluableKeyIDCredentialCriterion(encryptedObject.getHeader().getKeyID()));
         }
         
         return newCriteriaSet;
     }
     
     /**
-     * Build decryption key credential criteria according to information in the encrypted object.
+     * Optionally build decryption key 'alg' (key management algorithm) credential criteria according to 
+     * information in the encrypted object.
      * 
-     * @param encryptedObject the encrypted JWT from which to deduce decryption key criteria
+     * @param criteriaSet the criteria set to add built criteria too
+     * @param encryptedObject the encrypted JWT from which to deduce decryption key 'alg' criteria
      * @return a set of credential criteria pertaining to the decryption key
      */
-    @Nullable private Set<Criterion> buildKeyCriteria(@Nonnull final EncryptedJWT encryptedObject) {
-        final EncryptionMethod encMethod = encryptedObject.getHeader().getEncryptionMethod();        
-        if (encMethod == null) {
-            // This element is optional
-            return null;
+    @Nullable private void buildKeyManagementAlgorithmCriteria(@Nonnull final CriteriaSet criteriaSet,
+            @Nonnull final EncryptedJWT encryptedObject) {
+        
+        final JWEAlgorithm alg = encryptedObject.getHeader().getAlgorithm();
+        if (alg == null) {
+            // Is optionally built
+            return;
         }
-        final String encAlgorithmURI = StringSupport.trimOrNull(encMethod.getName());
-        if (encAlgorithmURI == null) {
-            return null;
+            
+        final String algAlgorithmURI = StringSupport.trimOrNull(alg.getName());        
+        if (algAlgorithmURI == null) {
+            // Is optionally built
+            return;
         }
 
-        final Set<Criterion> critSet = new HashSet<>(2);
-
-        final KeyAlgorithmCriterion algoCrit = buildKeyAlgorithmCriteria(encAlgorithmURI);
+        final KeyAlgorithmCriterion algoCrit = buildKeyAlgorithmCriteria(algAlgorithmURI);        
         if (algoCrit != null) {
-            critSet.add(algoCrit);
-            log.debug("Added decryption key algorithm criteria: {}", algoCrit.getKeyAlgorithm());
+            criteriaSet.add(algoCrit);
+            log.debug("Added decryption key algorithm  'alg' criteria: {}", algoCrit.getKeyAlgorithm());
         }
-
+        
+        // Add key size criteria if possible
+        final KeyLengthCriterion lengthCrit = buildKeyLengthCriteria(algAlgorithmURI);
+        if (lengthCrit != null) {
+            criteriaSet.add(lengthCrit);
+            log.debug("Added decryption key length criteria from EncryptionMethod algorithm URI: {}", lengthCrit
+                    .getKeyLength());
+        }
+    }
+    
+    /**
+     * Optionally build decryption key 'enc' (encryption key algorithm) credential criteria according to 
+     * information in the encrypted object.
+     * 
+     * @param encryptedObject the encrypted JWT from which to deduce decryption key 'enc' criteria
+     * @return a set of credential criteria pertaining to the decryption key
+     */
+    @Nullable private void buildContentEncryptionKeyAlgorithmCriteria(
+            @Nonnull final CriteriaSet criteriaSet, @Nonnull final EncryptedJWT encryptedObject) {
+        
+        final EncryptionMethod enc = encryptedObject.getHeader().getEncryptionMethod();
+        if (enc == null) {
+            // Is optionally built
+            return;
+        }
+            
+        final String encAlgorithmURI = StringSupport.trimOrNull(enc.getName());        
+        if (encAlgorithmURI == null) {
+            // Is optionally built
+            return;
+        }
+                    
+        final KeyAlgorithmCriterion algoCrit = buildKeyAlgorithmCriteria(encAlgorithmURI);        
+        if (algoCrit != null) {
+            criteriaSet.add(algoCrit);
+            log.debug("Added decryption key algorithm 'enc' criteria: {}", algoCrit.getKeyAlgorithm());
+        }
+        
+        // Add key size criteria if possible
         KeyLengthCriterion lengthCrit = buildKeyLengthCriteria(encAlgorithmURI);
         if (lengthCrit != null) {
-            critSet.add(lengthCrit);
+            criteriaSet.add(lengthCrit);
             log.debug("Added decryption key length criteria from EncryptionMethod algorithm URI: {}", lengthCrit
                     .getKeyLength());
         } else {
-            if (encMethod.cekBitLength() != 0) {
-                lengthCrit = new KeyLengthCriterion(encMethod.cekBitLength());
-                critSet.add(lengthCrit);
+            if (enc.cekBitLength() != 0) {
+                lengthCrit = new KeyLengthCriterion(enc.cekBitLength());
+                criteriaSet.add(lengthCrit);
                 log.debug("Added decryption key length criteria from EncryptionMethod/KeySize: {}", lengthCrit
                         .getKeyLength());
             }
         }
-        
-        // If 'kid' exists in the header, create an EvaluableKeyID criterion
-        if (encryptedObject.getHeader().getKeyID() != null) {
-            // FIXME: This is created directly as an EvaluableCriterion as I can not see a way to 
-            // add to the default mappings in EvaluableCredentialCriteriaRegistry without overriding the opensaml
-            // version
-            critSet.add(new EvaluableKeyIDCredentialCriterion(encryptedObject.getHeader().getKeyID()));
-        }
-
-        return critSet;
     }
     
     /**
      * Dynamically construct key algorithm credential criteria based on the specified algorithm URI.
      * 
-     * @param encAlgorithmURI the algorithm URI
+     * @param algURI the algorithm URI
      * @return a new key algorithm credential criteria instance, or null if criteria could not be determined
      */
-    @Nullable private KeyAlgorithmCriterion buildKeyAlgorithmCriteria(@Nullable final String encAlgorithmURI) {
-        if (Strings.isNullOrEmpty(encAlgorithmURI)) {
+    @Nullable private KeyAlgorithmCriterion buildKeyAlgorithmCriteria(@Nullable final String algorithmURI) {
+        if (Strings.isNullOrEmpty(algorithmURI)) {
             return null;
         }
 
-        final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(encAlgorithmURI);
+        final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(algorithmURI);
         if (!Strings.isNullOrEmpty(jcaKeyAlgorithm)) {
             return new KeyAlgorithmCriterion(jcaKeyAlgorithm);
         }
@@ -299,20 +330,17 @@ public class JWTDecrypter {
         
         final CriteriaSet criteria = 
                 buildCriteria(encryptedObject, List.of(new UsageCriterion(UsageType.ENCRYPTION)));
+        buildKeyManagementAlgorithmCriteria(criteria, encryptedObject);
         
         try {
             for (final Credential cred : params.getKEKCredentialResolver().resolve(criteria)) {
-                if (cred.getPrivateKey() instanceof ECPrivateKey) {
-                    try {
-                        validateKeyManagmentAlgorithm(encryptedObject, cred);
-                        final JWEDecrypter decrypter = new ECDHDecrypter((ECPrivateKey)cred.getPrivateKey());
-                        encryptedObject.decrypt(decrypter);
-                        return;
-                    } catch (final JOSEException | DecryptionException e) {
-                        log.debug("Failed to decrypt JWE using key '{}', continuing: {}", cred.getKeyNames(), e.getMessage());
-                    }
-                } else {
-                    log.debug("Key encryption key '{}' does not contain a private key, skipping", cred.getKeyNames());
+                try {
+                    validateKeyManagmentAlgorithm(encryptedObject, cred);
+                    final JWEDecrypter decrypter = new ECDHDecrypter((ECPrivateKey)cred.getPrivateKey());
+                    encryptedObject.decrypt(decrypter);
+                    return;
+                } catch (final JOSEException | DecryptionException e) {
+                    log.debug("Failed to decrypt JWE using key '{}', continuing: {}", cred.getKeyNames(), e.getMessage());
                 }
             }
         } catch (final ResolverException e) {
@@ -345,20 +373,17 @@ public class JWTDecrypter {
         
         final CriteriaSet criteria = 
                 buildCriteria(encryptedObject, List.of(new UsageCriterion(UsageType.ENCRYPTION)));
+        buildKeyManagementAlgorithmCriteria(criteria, encryptedObject);
         
         try {
             for (final Credential cred : params.getKEKCredentialResolver().resolve(criteria)) {
-                if (cred.getSecretKey() != null) {
-                    try {
-                        validateKeyManagmentAlgorithm(encryptedObject, cred);
-                        final JWEDecrypter decrypter = new AESDecrypter(cred.getSecretKey());
-                        encryptedObject.decrypt(decrypter);
-                        return;
-                    } catch (final JOSEException | DecryptionException e) {
-                        log.debug("Failed to decrypt JWE using key '{}', continuing: {}", cred.getKeyNames(), e.getMessage());
-                    }
-                } else {
-                    log.debug("Key encryption key '{}' does not contain a private key, skipping", cred.getKeyNames());
+                try {
+                    validateKeyManagmentAlgorithm(encryptedObject, cred);
+                    final JWEDecrypter decrypter = new AESDecrypter(cred.getSecretKey());
+                    encryptedObject.decrypt(decrypter);
+                    return;
+                } catch (final JOSEException | DecryptionException e) {
+                    log.debug("Failed to decrypt JWE using key '{}', continuing: {}", cred.getKeyNames(), e.getMessage());
                 }
             }
         } catch (final ResolverException e) {
@@ -391,21 +416,18 @@ public class JWTDecrypter {
         
         final CriteriaSet criteria = 
                 buildCriteria(encryptedObject, List.of(new UsageCriterion(UsageType.ENCRYPTION)));
+        buildKeyManagementAlgorithmCriteria(criteria, encryptedObject);
         
         try {
-            for (final Credential cred : params.getKEKCredentialResolver().resolve(criteria)) {
-                if (cred.getPrivateKey() != null) {
-                    try {
-                        validateKeyManagmentAlgorithm(encryptedObject, cred);
-                        final JWEDecrypter decrypter = new RSADecrypter(cred.getPrivateKey());
-                        encryptedObject.decrypt(decrypter);
-                        return;
-                    } catch (final JOSEException | DecryptionException e) {
-                        log.debug("Failed to decrypt JWE using key '{}', continuing: {}", cred.getKeyNames(), e.getMessage());
-                    }
-                } else {
-                    log.debug("Key encryption key '{}' does not contain a private key, skipping", cred.getKeyNames());
-                }
+            for (final Credential cred : params.getKEKCredentialResolver().resolve(criteria)) { 
+                try {
+                    validateKeyManagmentAlgorithm(encryptedObject, cred);
+                    final JWEDecrypter decrypter = new RSADecrypter(cred.getPrivateKey());
+                    encryptedObject.decrypt(decrypter);
+                    return;
+                } catch (final JOSEException | DecryptionException e) {
+                    log.debug("Failed to decrypt JWE using key '{}', continuing: {}", cred.getKeyNames(), e.getMessage());
+                }                
             }
         } catch (final ResolverException e) {
             log.warn("Unable to decrypt JWE with Key Encryption", e);
@@ -439,21 +461,20 @@ public class JWTDecrypter {
         final CriteriaSet criteria = 
                 buildCriteria(encryptedObject, List.of(new UsageCriterion(UsageType.ENCRYPTION)));
         
+        // As 'dir' type, we can add content encryption key criteria for the resolver to filter on
+        buildContentEncryptionKeyAlgorithmCriteria(criteria, encryptedObject);
+        
         try {
             for (final Credential cred : params.getContentEncryptionKeyCredentialResolver().resolve(criteria)) {
-                if (cred.getSecretKey() != null) {
-                    try {
-                        validateKeyManagmentAlgorithm(encryptedObject, cred);
-                        validateContentEncryptionAlgorithm(encryptedObject, cred);
-                        final JWEDecrypter decrypter = new DirectDecrypter(cred.getSecretKey());
-                        encryptedObject.decrypt(decrypter);
-                        return;
-                    } catch (final JOSEException | DecryptionException e) {
-                        log.debug("Content encryption key '{}' failed to decrypt JWE, continuing: {}", 
-                                cred.getKeyNames(), e.getMessage());
-                    }
-                } else {
-                    log.debug("Content encryption key '{}' does not contain a secret key, skipping", cred.getKeyNames());
+                try {
+                    validateKeyManagmentAlgorithm(encryptedObject, cred);
+                    validateContentEncryptionAlgorithm(encryptedObject, cred);
+                    final JWEDecrypter decrypter = new DirectDecrypter(cred.getSecretKey());
+                    encryptedObject.decrypt(decrypter);
+                    return;
+                } catch (final JOSEException | DecryptionException e) {
+                    log.debug("Content encryption key '{}' failed to decrypt JWE, continuing: {}", 
+                            cred.getKeyNames(), e.getMessage());
                 }
             }
         } catch (final ResolverException e) {
@@ -463,10 +484,12 @@ public class JWTDecrypter {
     }
     
     /**
-     * Validates the 'alg' algorithm in the header matches the algorithm specified for the credential.
+     * Validates the 'alg' algorithm in the header matches the algorithm specified for the credential, 
+     * validates against the include and exclude algorithm URI lists, and the credential contains the
+     * correct key type.
      * 
      * @param encryptedObject the JWE
-     * @param cred the credential to check algorithm compatibility
+     * @param cred the credential to validate against the 'alg' header
      * 
      * @throws DecryptionException if there is an algorithm mismatch.
      */
@@ -477,29 +500,43 @@ public class JWTDecrypter {
             throw new DecryptionException("JWE did not contain a JOSE header, is in an illegal state");
         }
         
-        validateAlgorithmURI(encryptedObject.getHeader().getAlgorithm().getName());
-        
+        final JWEAlgorithm headerAlg = encryptedObject.getHeader().getAlgorithm();
+        validateAlgorithmURI(headerAlg.getName());
+
         if (cred instanceof JWKCredential) {
             final JWKCredential jwkCred = (JWKCredential)cred;
-            if (jwkCred.getAlgorithm() != null && 
-                    encryptedObject.getHeader().getAlgorithm().equals(jwkCred.getAlgorithm())) {
-                // Matches
-                return;                
-            } else {
+            if (jwkCred.getAlgorithm() == null || !headerAlg.equals(jwkCred.getAlgorithm())) {
                 throw new DecryptionException("Credential algorithm '"+jwkCred.getAlgorithm()+"' "
                         + "was not a match for the "
                         + "algorithm '"+encryptedObject.getHeader().getAlgorithm()+"'");
+                             
             }
         }
-        throw new DecryptionException("Credential was not the correct type, expected a JWK Credential");      
+        // Now check key is of the correct type
+        if (JWEAlgorithm.Family.RSA.contains(headerAlg) && !(cred.getPrivateKey() instanceof RSAPrivateKey)) {
+            throw new DecryptionException("Credential did not contain an RSA private key");
+        }
+        if (JWEAlgorithm.Family.ECDH_ES.contains(headerAlg) && !(cred.getPrivateKey() instanceof ECPrivateKey)) {
+            throw new DecryptionException("Credential did not contain an EC private key");
+        }
+        if ((JWEAlgorithm.Family.AES_GCM_KW.contains(headerAlg) || JWEAlgorithm.Family.AES_KW.contains(headerAlg)) 
+                && (cred.getSecretKey() == null || !"AES".equals(cred.getSecretKey().getAlgorithm()))) {
+            throw new DecryptionException("Credential did not contain an AES secret key");
+        }
+        if (JWEAlgorithm.DIR.equals(headerAlg) && cred.getSecretKey() == null) {
+            throw new DecryptionException("Credential did not contain an direct encryption secret key");
+        }
+        
+        //All fine    
     }
     
     
     /**
-     * Validates the 'enc' algorithm in the header matches the encryption algorithm specified for the credential.
+     * Validates the 'enc' algorithm in the header matches the encryption algorithm specified for the credential, 
+     * and validates against the include and exclude algorithm URI lists.
      * 
      * @param encryptedObject the JWE
-     * @param cred the credential to check algorithm compatibility
+     * @param cred the credential to validate the 'enc' header
      * 
      * @throws DecryptionException if there is an algorithm mismatch.
      */
@@ -509,23 +546,27 @@ public class JWTDecrypter {
         if (encryptedObject.getHeader() == null) {
             throw new DecryptionException("JWE did not contain a JOSE header, is in an illegal state");
         }
-        validateAlgorithmURI(encryptedObject.getHeader().getEncryptionMethod().getName());
         
-        if (cred.getCredentialContextSet().contains(
-                        JWKEncryptionCredentialContext.class)) {
-            final EncryptionMethod encMethod = 
-                    cred.getCredentialContextSet().get(
-                            JWKEncryptionCredentialContext.class).getEncryptionAlgorithm();
+        final EncryptionMethod enc = encryptedObject.getHeader().getEncryptionMethod();
+        if (enc == null) {
+            throw new DecryptionException("JWE did not contain an 'enc' JOSE header, is in an illegal state");
+        }
             
-            if (!encryptedObject.getHeader().getEncryptionMethod().equals(encMethod)) {
-                throw new DecryptionException("JOSE Header 'enc' algorithm "
-                        +encryptedObject.getHeader().getEncryptionMethod().getName()+
-                        " does not match credential algorithm "+encMethod);
-            }
+        final String encAlgorithmURI = StringSupport.trimOrNull(enc.getName());
         
-        } else {
-            throw new DecryptionException("Credential did not specify which 'enc' algorithm it supports");
+        validateAlgorithmURI(encAlgorithmURI);
+        
+        final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(encAlgorithmURI);
+        
+        if (cred.getSecretKey() == null) {
+            throw new DecryptionException("Credential does not contain a content encryption secret key");
+        }
+            
+        if (!jcaKeyAlgorithm.equals(cred.getSecretKey().getAlgorithm())) {
+            throw new DecryptionException("JOSE Header 'enc' algorithm "
+                    +jcaKeyAlgorithm+" does not match credential algorithm "+cred.getSecretKey().getAlgorithm());
         }
+       
         // Otherwise, all fine.
     }
     
diff --git a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWTDecrypterTest.java b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWTDecrypterTest.java
index 9a0240b..015b06f 100644
--- a/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWTDecrypterTest.java
+++ b/oidc-common-crypto-impl/src/test/java/net/shibboleth/oidc/security/impl/JWTDecrypterTest.java
@@ -5,17 +5,20 @@ import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
 import java.nio.charset.StandardCharsets;
+import java.security.KeyException;
 import java.security.interfaces.RSAPublicKey;
 import java.text.ParseException;
 import java.time.Instant;
 import java.util.Date;
 import java.util.List;
 
-import javax.crypto.spec.SecretKeySpec;
-
+import org.opensaml.core.config.InitializationException;
 import org.opensaml.security.credential.Credential;
-import org.opensaml.security.credential.CredentialResolver;
+import org.opensaml.security.credential.impl.AbstractCriteriaFilteringCredentialResolver;
+import org.opensaml.security.crypto.KeySupport;
+import org.opensaml.xmlsec.config.GlobalAlgorithmRegistryInitializer;
 import org.opensaml.xmlsec.encryption.support.DecryptionException;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import com.nimbusds.jose.EncryptionMethod;
@@ -36,6 +39,7 @@ import com.nimbusds.jose.crypto.MACSigner;
 import com.nimbusds.jose.crypto.PasswordBasedEncrypter;
 import com.nimbusds.jose.crypto.RSAEncrypter;
 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;
@@ -48,7 +52,6 @@ import com.nimbusds.jwt.SignedJWT;
 import net.shibboleth.oidc.security.JWTDecryptionParameters;
 import net.shibboleth.oidc.security.credential.BasicJWKCredential;
 import net.shibboleth.oidc.security.credential.JOSEObjectCredentialResolver;
-import net.shibboleth.oidc.security.credential.impl.JWKEncryptionCredentialContext;
 import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
 import net.shibboleth.utilities.java.support.resolver.ResolverException;
 
@@ -75,18 +78,31 @@ public class JWTDecrypterTest {
     private SignedJWT createdSignedJWT() throws KeyLengthException, JOSEException {        
         final var header = new JWSHeader.Builder(JWSAlgorithm.HS256)
                 .type(JOSEObjectType.JWT)
+                .keyID("mock-key")
                 .build();       
         final var signedJWT = new SignedJWT(header,createClaims());
         signedJWT.sign(new MACSigner(CLIENT_SECRET));
         return signedJWT;
     }
     
+    @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();
+        }
+    }
+    
     @Test(expectedExceptions = DecryptionException.class)
     void testUnsupportedAlg() throws Exception {       
         
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.PBES2_HS256_A128KW, EncryptionMethod.A256GCM)
                 .contentType("JWT")
+                .keyID("mock-key")
                 .build(),
                 new Payload(createdSignedJWT()));
         jweObject.encrypt(new PasswordBasedEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8),8,1000));
@@ -102,6 +118,7 @@ public class JWTDecrypterTest {
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM)
                 .contentType("JWT")
+                .keyID("mock-key")
                 .build(),
                 new Payload(createdSignedJWT()));
         jweObject.encrypt(new AESEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8)));
@@ -115,8 +132,13 @@ public class JWTDecrypterTest {
                 final BasicJWKCredential jwkCredential = new BasicJWKCredential();
                 jwkCredential.setAlgorithm(JWEAlgorithm.A256KW);
                 jwkCredential.getKeyNames().add("mock-key");
-                jwkCredential.setSecretKey(new SecretKeySpec(
-                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "NONE"));          
+                jwkCredential.setKid("mock-key");
+                try {
+                    jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
+                            JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
+                } catch (final KeyException e) {
+                    throw new ResolverException(e);
+                }           
                 return jwkCredential;
             }
             
@@ -132,12 +154,34 @@ public class JWTDecrypterTest {
         assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");
     }
     
+    @Test
+    void testDecryptionByKeyWrapping_Using_EvaluableCriteriaFiltering() throws Exception {       
+        
+        final JWEObject jweObject = 
+                new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM)
+                .contentType("JWT")
+                .keyID("mock-key")
+                .build(),
+                new Payload(createdSignedJWT()));
+        jweObject.encrypt(new AESEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8)));
+        final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+        
+        final var params = new JWTDecryptionParameters();
+        params.setKEKCredentialResolver(new MockKeyWrapCriteriaFilteringCredentialResolver());
+        decrypter = new JWTDecrypter(params);
+        final JWT decryptedJWE = decrypter.decrypt(jwe);
+        assertTrue(jwe.getState() == State.DECRYPTED);
+        assertTrue(decryptedJWE instanceof SignedJWT);
+        assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");
+    }
+    
     @Test
     void testDecryptionByDirectEncryption() throws Exception {       
         
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
                 .contentType("JWT")
+                .keyID("mock-key")
                 .build(),
                 new Payload(createdSignedJWT()));
         jweObject.encrypt(new DirectEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8)));
@@ -150,11 +194,14 @@ public class JWTDecrypterTest {
             public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
                 final BasicJWKCredential jwkCredential = new BasicJWKCredential();
                 jwkCredential.setAlgorithm(JWEAlgorithm.DIR);
-                jwkCredential.getCredentialContextSet()
-                    .add(new JWKEncryptionCredentialContext(EncryptionMethod.A256GCM));
                 jwkCredential.getKeyNames().add("mock-key");
-                jwkCredential.setSecretKey(new SecretKeySpec(
-                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "NONE"));          
+                jwkCredential.setKid("mock-key");
+                try {
+                    jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
+                            JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
+                } catch (final KeyException e) {
+                    throw new ResolverException(e);
+                }          
                 return jwkCredential;
             }
             
@@ -170,12 +217,35 @@ public class JWTDecrypterTest {
         assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");
     }
     
+    
+    @Test
+    void testDecryptionByDirectEncryption_Using_EvaluableCriteriaFiltering() throws Exception {       
+        
+        final JWEObject jweObject = 
+                new JWEObject(new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
+                .contentType("JWT")
+                .keyID("mock-key")
+                .build(),
+                new Payload(createdSignedJWT()));
+        jweObject.encrypt(new DirectEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8)));
+        final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+        
+        final var params = new JWTDecryptionParameters();
+        params.setContentEncryptionKeyCredentialResolver(new MockDirCriteriaFilteringCredentialResolver());
+        decrypter = new JWTDecrypter(params);
+        final JWT decryptedJWE = decrypter.decrypt(jwe);
+        assertTrue(jwe.getState() == State.DECRYPTED);
+        assertTrue(decryptedJWE instanceof SignedJWT);
+        assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");
+    }
+    
     @Test
     void testDecryptionByDirectEncryption_AlgorithmExcluded() throws Exception {       
         
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
                 .contentType("JWT")
+                .keyID("mock-key")
                 .build(),
                 new Payload(createdSignedJWT()));
         jweObject.encrypt(new DirectEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8)));
@@ -188,11 +258,14 @@ public class JWTDecrypterTest {
             public Credential resolveSingle(final CriteriaSet criteria) throws ResolverException {
                 final BasicJWKCredential jwkCredential = new BasicJWKCredential();
                 jwkCredential.setAlgorithm(JWEAlgorithm.DIR);
-                jwkCredential.getCredentialContextSet()
-                    .add(new JWKEncryptionCredentialContext(EncryptionMethod.A256GCM));
                 jwkCredential.getKeyNames().add("mock-key");
-                jwkCredential.setSecretKey(new SecretKeySpec(
-                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "NONE"));          
+                jwkCredential.setKid("mock-key");
+                try {
+                    jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
+                            JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
+                } catch (final KeyException e) {
+                    throw new ResolverException(e);
+                }           
                 return jwkCredential;
             }
             
@@ -219,6 +292,7 @@ public class JWTDecrypterTest {
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.DIR, EncryptionMethod.A256GCM)
                 .contentType("JWT")
+                .keyID("mock-key")
                 .build(),
                 new Payload(createdSignedJWT()));
         jweObject.encrypt(new DirectEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8)));
@@ -233,8 +307,13 @@ public class JWTDecrypterTest {
                 final BasicJWKCredential jwkCredential = new BasicJWKCredential();
                 jwkCredential.setAlgorithm(JWEAlgorithm.A128KW);
                 jwkCredential.getKeyNames().add("mock-key");
-                jwkCredential.setSecretKey(new SecretKeySpec(
-                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "NONE"));          
+                jwkCredential.setKid("mock-key");
+                try {
+                    jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
+                            JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
+                } catch (final KeyException e) {
+                    throw new ResolverException(e);
+                }            
                 return jwkCredential;
             }
             
@@ -258,6 +337,7 @@ public class JWTDecrypterTest {
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.A256KW, EncryptionMethod.A256GCM)
                 .contentType("JWT")
+                .keyID("mock-key")
                 .build(),
                 new Payload(createdSignedJWT()));
         jweObject.encrypt(new AESEncrypter(CLIENT_SECRET.getBytes(StandardCharsets.UTF_8)));
@@ -271,8 +351,13 @@ public class JWTDecrypterTest {
                 final BasicJWKCredential jwkCredential = new BasicJWKCredential();
                 jwkCredential.setAlgorithm(JWEAlgorithm.A128KW);
                 jwkCredential.getKeyNames().add("mock-key");
-                jwkCredential.setSecretKey(new SecretKeySpec(
-                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "NONE"));          
+                jwkCredential.setKid("mock-key");
+                try {
+                    jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
+                            JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
+                } catch (final KeyException e) {
+                    throw new ResolverException(e);
+                }           
                 return jwkCredential;
             }
             
@@ -301,6 +386,7 @@ public class JWTDecrypterTest {
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM)
                 .contentType("JWT")
+                .keyID("mock-key")
                 .build(),
                 new Payload(createdSignedJWT()));
         jweObject.encrypt(new RSAEncrypter((RSAPublicKey) key.toPublicKey()));
@@ -313,6 +399,7 @@ public class JWTDecrypterTest {
                 final BasicJWKCredential jwkCredential = new BasicJWKCredential();
                 jwkCredential.setAlgorithm(JWEAlgorithm.RSA_OAEP_256);
                 jwkCredential.getKeyNames().add("mock-key");
+                jwkCredential.setKid("mock-key");
                 try {
                     jwkCredential.setPrivateKey(key.toPrivateKey());
                     jwkCredential.setPublicKey(key.toPublicKey());
@@ -335,6 +422,31 @@ public class JWTDecrypterTest {
         assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");    
     }
     
+    @Test
+    void testDecryptionByKeyEncryption_Using_EvaluableCriteriaFiltering() throws Exception  {       
+        
+        final RSAKey key = new RSAKeyGenerator(2048)
+                .keyID("1")
+                .keyUse(KeyUse.ENCRYPTION)
+                .generate();
+        
+        final JWEObject jweObject = 
+                new JWEObject(new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM)
+                .contentType("JWT")
+                .keyID("mock-key")
+                .build(),
+                new Payload(createdSignedJWT()));
+        jweObject.encrypt(new RSAEncrypter((RSAPublicKey) key.toPublicKey()));
+        final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+        final var params = new JWTDecryptionParameters();
+        params.setKEKCredentialResolver(new MockRSACriteriaFilteringCredentialResolver(key));
+        decrypter = new JWTDecrypter(params);
+        final JWT decryptedJWE = decrypter.decrypt(jwe);
+        assertTrue(jwe.getState() == State.DECRYPTED);
+        assertTrue(decryptedJWE instanceof SignedJWT);
+        assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");    
+    }
+    
     @Test
     void testDecryptionByKeyAgreement() throws Exception  {       
         
@@ -346,6 +458,7 @@ public class JWTDecrypterTest {
         final JWEObject jweObject = 
                 new JWEObject(new JWEHeader.Builder(JWEAlgorithm.ECDH_ES_A256KW, EncryptionMethod.A256GCM)
                 .contentType("JWT")
+                .keyID("mock-key")
                 .build(),
                 new Payload(createdSignedJWT()));
         jweObject.encrypt(new ECDHEncrypter(key.toECPublicKey()));
@@ -358,6 +471,7 @@ public class JWTDecrypterTest {
                 final BasicJWKCredential jwkCredential = new BasicJWKCredential();
                 jwkCredential.setAlgorithm(JWEAlgorithm.ECDH_ES_A256KW);
                 jwkCredential.getKeyNames().add("mock-key");
+                jwkCredential.setKid("mock-key");
                 try {
                     jwkCredential.setPrivateKey(key.toPrivateKey());
                     jwkCredential.setPublicKey(key.toPublicKey());
@@ -379,4 +493,123 @@ public class JWTDecrypterTest {
         assertTrue(decryptedJWE instanceof SignedJWT);
         assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");    
     }
+    
+    @Test
+    void testDecryptionByKeyAgreement_Using_EvaluableCriteriaFiltering() throws Exception  {       
+        
+        final var key = new ECKeyGenerator(Curve.P_256)
+                .keyUse(KeyUse.ENCRYPTION)
+                .keyID("1")
+                .generate();
+        
+        final JWEObject jweObject = 
+                new JWEObject(new JWEHeader.Builder(JWEAlgorithm.ECDH_ES_A256KW, EncryptionMethod.A256GCM)
+                .contentType("JWT")
+                .keyID("mock-key")
+                .build(),
+                new Payload(createdSignedJWT()));
+        jweObject.encrypt(new ECDHEncrypter(key.toECPublicKey()));
+        final EncryptedJWT jwe = EncryptedJWT.parse(jweObject.serialize());
+        final var params = new JWTDecryptionParameters();
+        params.setKEKCredentialResolver(new MockKeyAgreementCriteriaFilteringCredentialResolver(key));
+        decrypter = new JWTDecrypter(params);
+        final JWT decryptedJWE = decrypter.decrypt(jwe);
+        assertTrue(jwe.getState() == State.DECRYPTED);
+        assertTrue(decryptedJWE instanceof SignedJWT);
+        assertEquals(decryptedJWE.getJWTClaimsSet().getSubject(), "jdoe");    
+    }
+    
+    private static class MockRSACriteriaFilteringCredentialResolver extends AbstractCriteriaFilteringCredentialResolver
+        implements JOSEObjectCredentialResolver {
+        
+        private final RSAKey key;
+        
+        public MockRSACriteriaFilteringCredentialResolver(final RSAKey theKey) {
+            key = theKey;
+        }
+
+        @Override
+        protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
+            final BasicJWKCredential jwkCredential = new BasicJWKCredential();
+            jwkCredential.setAlgorithm(JWEAlgorithm.RSA_OAEP_256);
+            jwkCredential.getKeyNames().add("mock-key");
+            jwkCredential.setKid("mock-key");
+            try {
+                jwkCredential.setPrivateKey(key.toPrivateKey());
+                jwkCredential.setPublicKey(key.toPublicKey());
+            } catch (final JOSEException e) {
+                fail();
+            }
+            
+            return List.of(jwkCredential);
+        }
+        
+    }
+    
+    private static class MockDirCriteriaFilteringCredentialResolver extends AbstractCriteriaFilteringCredentialResolver
+        implements JOSEObjectCredentialResolver {
+    
+        @Override
+        protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
+            final BasicJWKCredential jwkCredential = new BasicJWKCredential();
+            jwkCredential.setAlgorithm(JWEAlgorithm.DIR);
+            jwkCredential.getKeyNames().add("mock-key");
+            jwkCredential.setKid("mock-key");
+            try {
+                jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
+                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
+            } catch (final KeyException e) {
+                throw new ResolverException(e);
+            }          
+            return List.of(jwkCredential);
+        }
+    
+    }
+    
+    private static class MockKeyWrapCriteriaFilteringCredentialResolver extends AbstractCriteriaFilteringCredentialResolver
+        implements JOSEObjectCredentialResolver {
+
+        @Override
+        protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
+            final BasicJWKCredential jwkCredential = new BasicJWKCredential();
+            jwkCredential.setAlgorithm(JWEAlgorithm.A256KW);
+            jwkCredential.getKeyNames().add("mock-key");
+            jwkCredential.setKid("mock-key");
+            try {
+                jwkCredential.setSecretKey(KeySupport.decodeSecretKey(
+                        JWSAssemblyUtils.getSecretBytes(CLIENT_SECRET), "AES"));
+            } catch (final KeyException e) {
+                throw new ResolverException(e);
+            }           
+            return List.of(jwkCredential);
+        }
+
+    }
+    
+    private static class MockKeyAgreementCriteriaFilteringCredentialResolver extends AbstractCriteriaFilteringCredentialResolver
+        implements JOSEObjectCredentialResolver {
+        
+        private final ECKey key;
+        
+        public MockKeyAgreementCriteriaFilteringCredentialResolver(final ECKey theKey) {
+            key = theKey;
+        }
+
+        @Override
+        protected Iterable<Credential> resolveFromSource(final CriteriaSet criteriaSet) throws ResolverException {
+            final BasicJWKCredential jwkCredential = new BasicJWKCredential();
+            jwkCredential.setAlgorithm(JWEAlgorithm.ECDH_ES_A256KW);
+            jwkCredential.getKeyNames().add("mock-key");
+            jwkCredential.setKid("mock-key");
+            try {
+                jwkCredential.setPrivateKey(key.toPrivateKey());
+                jwkCredential.setPublicKey(key.toPublicKey());
+            } catch (final JOSEException e) {
+                fail();
+            }
+                      
+            return List.of(jwkCredential);
+        }
+
+    }
 }

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


More information about the commits mailing list