[java-opensaml] 19/19: Additional tweaks and tests around general key agreement and ECDH.

Brent Putman putmanb at georgetown.edu
Mon Mar 1 05:56:56 UTC 2021


This is an automated email from the git hooks/post-receive script.

putmanb pushed a commit to branch dev/OSJ-82
in repository java-opensaml.

View the commit online:
http://git.shibboleth.net/view/?p=java-opensaml.git;a=commit;h=d4e4b86b6308a92ad3b43e8e59d4b301f36b406d

commit d4e4b86b6308a92ad3b43e8e59d4b301f36b406d
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Fri Feb 26 23:01:36 2021 -0500

    Additional tweaks and tests around general key agreement and ECDH.
---
 .../saml/common/testing/SAMLTestSupport.java       |   6 +-
 .../saml/saml2/encryption/tests/ECDHTest.java      | 369 +++++++++++++++++++++
 .../xmlsec/agreement/KeyAgreementSupport.java      |  33 ++
 .../AbstractDerivationKeyAgreementProcessor.java   |   3 +
 .../impl/ECDHKeyAgreementProcessorTest.java        |  14 +
 .../agreement/tests/KeyAgreementSupportTest.java   | 122 +++++++
 .../xmlsec/encryption/support/tests/ECDHTest.java  | 237 +++++++++++++
 .../xmlsec/testing/XMLSecurityTestingSupport.java  |   6 +-
 8 files changed, 788 insertions(+), 2 deletions(-)

diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/testing/SAMLTestSupport.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/testing/SAMLTestSupport.java
index 255209dea..64fe0e684 100644
--- a/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/testing/SAMLTestSupport.java
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/common/testing/SAMLTestSupport.java
@@ -43,12 +43,16 @@ public final class SAMLTestSupport {
      * @return a new KeyInfoCredentialResolver instance
      */
     public static KeyInfoCredentialResolver buildBasicInlineKeyInfoResolver() {
+        return new BasicProviderKeyInfoCredentialResolver(getBasicInlineKeyInfoProviders());
+    }
+    
+    public static List<KeyInfoProvider> getBasicInlineKeyInfoProviders() {
         List<KeyInfoProvider> providers = new ArrayList<>();
         providers.add( new RSAKeyValueProvider() );
         providers.add( new DSAKeyValueProvider() );
         providers.add( new ECKeyValueProvider() );
         providers.add( new InlineX509DataProvider() );
-        return new BasicProviderKeyInfoCredentialResolver(providers);
+        return providers;
     }
 
 }
diff --git a/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/encryption/tests/ECDHTest.java b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/encryption/tests/ECDHTest.java
new file mode 100644
index 000000000..2cdb274c4
--- /dev/null
+++ b/opensaml-saml-impl/src/test/java/org/opensaml/saml/saml2/encryption/tests/ECDHTest.java
@@ -0,0 +1,369 @@
+/*
+ * 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 org.opensaml.saml.saml2.encryption.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.security.KeyPair;
+import java.security.PublicKey;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.ECGenParameterSpec;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opensaml.core.config.ConfigurationService;
+import org.opensaml.core.testing.XMLObjectBaseTestCase;
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.core.xml.util.XMLObjectSupport;
+import org.opensaml.saml.common.testing.SAMLTestSupport;
+import org.opensaml.saml.criterion.RoleDescriptorCriterion;
+import org.opensaml.saml.saml2.core.Assertion;
+import org.opensaml.saml.saml2.core.EncryptedAssertion;
+import org.opensaml.saml.saml2.encryption.Decrypter;
+import org.opensaml.saml.saml2.encryption.Encrypter;
+import org.opensaml.saml.saml2.encryption.Encrypter.KeyPlacement;
+import org.opensaml.saml.saml2.metadata.EncryptionMethod;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml.saml2.metadata.KeyDescriptor;
+import org.opensaml.saml.saml2.metadata.RoleDescriptor;
+import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml.security.SAMLMetadataKeyAgreementEncryptionConfiguration;
+import org.opensaml.saml.security.SAMLMetadataKeyAgreementEncryptionConfiguration.KeyWrap;
+import org.opensaml.saml.security.impl.MetadataCredentialResolver;
+import org.opensaml.saml.security.impl.SAMLMetadataEncryptionParametersResolver;
+import org.opensaml.security.credential.BasicCredential;
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.UsageType;
+import org.opensaml.security.credential.impl.CollectionCredentialResolver;
+import org.opensaml.security.crypto.KeySupport;
+import org.opensaml.xmlsec.DecryptionConfiguration;
+import org.opensaml.xmlsec.DecryptionParameters;
+import org.opensaml.xmlsec.DecryptionParametersResolver;
+import org.opensaml.xmlsec.EncryptionConfiguration;
+import org.opensaml.xmlsec.EncryptionParameters;
+import org.opensaml.xmlsec.EncryptionParametersResolver;
+import org.opensaml.xmlsec.criterion.DecryptionConfigurationCriterion;
+import org.opensaml.xmlsec.criterion.EncryptionConfigurationCriterion;
+import org.opensaml.xmlsec.derivation.impl.PBKDF2;
+import org.opensaml.xmlsec.encryption.EncryptedKey;
+import org.opensaml.xmlsec.encryption.KeyDerivationMethod;
+import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters;
+import org.opensaml.xmlsec.encryption.support.EncryptionConstants;
+import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters;
+import org.opensaml.xmlsec.impl.BasicDecryptionConfiguration;
+import org.opensaml.xmlsec.impl.BasicDecryptionParametersResolver;
+import org.opensaml.xmlsec.impl.BasicEncryptionConfiguration;
+import org.opensaml.xmlsec.keyinfo.KeyInfoSupport;
+import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider;
+import org.opensaml.xmlsec.keyinfo.impl.LocalKeyInfoCredentialResolver;
+import org.opensaml.xmlsec.keyinfo.impl.provider.AgreementMethodKeyInfoProvider;
+import org.opensaml.xmlsec.signature.KeyInfo;
+import org.opensaml.xmlsec.testing.XMLSecurityTestingSupport;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.w3c.dom.Element;
+
+import net.shibboleth.utilities.java.support.codec.EncodingException;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.xml.SerializeSupport;
+
+/**
+ *
+ */
+public class ECDHTest extends XMLObjectBaseTestCase {
+    
+    private String targetFile;
+    
+    private Credential recipientCredPrivate;
+    private Credential recipientCredPublic;
+    private String recipientCredKeyName = "RecipientCredName";
+    
+    private CollectionCredentialResolver localCredentialResolver;
+    private LocalKeyInfoCredentialResolver localKeyInfoResolver;
+    
+    private Encrypter encrypter;
+    private EncryptionParametersResolver encParamsResolver;
+    private CriteriaSet encCriteria;
+    private BasicEncryptionConfiguration encConfig;
+    
+    private DecryptionParametersResolver decryptParamsResolver;
+    private CriteriaSet decryptCriteria;
+    private BasicDecryptionConfiguration decryptConfig;
+    
+    private MetadataCredentialResolver mdCredResolver;
+    
+    private RoleDescriptorCriterion roleDescCriterion;
+    private RoleDescriptor roleDesc;
+    
+    private String targetEntityID = "urn:test:foo";
+    
+    
+    @BeforeClass
+    public void beforeClass() throws Exception {
+        targetFile = "/org/opensaml/saml/saml2/encryption/Assertion.xml";
+        
+        KeyPair kp = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
+        recipientCredPrivate = new BasicCredential(kp.getPublic(), kp.getPrivate());
+        recipientCredPublic = new BasicCredential(kp.getPublic());
+        
+        mdCredResolver = new MetadataCredentialResolver();
+        mdCredResolver.setKeyInfoCredentialResolver(SAMLTestSupport.buildBasicInlineKeyInfoResolver());
+        mdCredResolver.initialize();
+        
+        encParamsResolver = new SAMLMetadataEncryptionParametersResolver(mdCredResolver);
+        
+        decryptParamsResolver = new BasicDecryptionParametersResolver();
+        
+        localCredentialResolver = new CollectionCredentialResolver(Set.of(recipientCredPrivate));
+        
+        List<KeyInfoProvider> keyInfoProviders = new ArrayList<>(XMLSecurityTestingSupport.getBasicInlineKeyInfoProviders());
+        keyInfoProviders.add(new AgreementMethodKeyInfoProvider());
+        localKeyInfoResolver = new LocalKeyInfoCredentialResolver(keyInfoProviders, localCredentialResolver);
+    }
+    
+    @BeforeMethod
+    public void beforeMethod() throws Exception {
+        roleDesc = buildRoleDescriptorSkeleton();
+        roleDescCriterion = new RoleDescriptorCriterion(roleDesc);
+        
+        encConfig = new BasicEncryptionConfiguration();
+        EncryptionConfigurationCriterion encConfCrit = new EncryptionConfigurationCriterion(encConfig,
+                ConfigurationService.get(EncryptionConfiguration.class));
+        encCriteria = new CriteriaSet(encConfCrit, roleDescCriterion);
+        
+        decryptConfig = new BasicDecryptionConfiguration();
+        decryptConfig.setDataKeyInfoCredentialResolver(localKeyInfoResolver);
+        decryptConfig.setKEKKeyInfoCredentialResolver(localKeyInfoResolver);
+        
+        decryptCriteria = new CriteriaSet(new DecryptionConfigurationCriterion(decryptConfig,
+                ConfigurationService.get(DecryptionConfiguration.class)));
+    }
+    
+    @Test
+    public void roundtripDirectDataEncryption() throws Exception {
+        KeyDescriptor kd = buildKeyDescriptor(recipientCredKeyName, UsageType.ENCRYPTION, recipientCredPublic.getPublicKey());
+        roleDesc.getKeyDescriptors().add(kd);
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128, null);
+    }
+
+    @Test
+    public void roundtripDirectDataEncryptionWithEncryptionMethod() throws Exception {
+        KeyDescriptor kd = buildKeyDescriptor(recipientCredKeyName, UsageType.ENCRYPTION, recipientCredPublic.getPublicKey());
+        kd.getEncryptionMethods().add(buildEncryptionMethod(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM));
+        roleDesc.getKeyDescriptors().add(kd);
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM, null);
+    }
+
+    @Test
+    public void roundtripWithKeyWrapAlways() throws Exception {
+        KeyDescriptor kd = buildKeyDescriptor(recipientCredKeyName, UsageType.ENCRYPTION, recipientCredPublic.getPublicKey());
+        roleDesc.getKeyDescriptors().add(kd);
+        
+        SAMLMetadataKeyAgreementEncryptionConfiguration kaConfig = new SAMLMetadataKeyAgreementEncryptionConfiguration();
+        kaConfig.setMetadataUseKeyWrap(KeyWrap.Always);
+        encConfig.setKeyAgreementConfigurations(Map.of("EC", kaConfig));
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128, EncryptionConstants.ALGO_ID_KEYWRAP_AES128);
+    }
+
+    @Test
+    public void roundtripWithKeyWrapAndEncryptionMethods() throws Exception {
+        KeyDescriptor kd = buildKeyDescriptor(recipientCredKeyName, UsageType.ENCRYPTION, recipientCredPublic.getPublicKey());
+        kd.getEncryptionMethods().add(buildEncryptionMethod(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM));
+        kd.getEncryptionMethods().add(buildEncryptionMethod(EncryptionConstants.ALGO_ID_KEYWRAP_AES256));
+        roleDesc.getKeyDescriptors().add(kd);
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, EncryptionConstants.ALGO_ID_KEYWRAP_AES256);
+    }
+
+    @Test
+    public void roundtripWithPBKDF2() throws Exception {
+        KeyDescriptor kd = buildKeyDescriptor(recipientCredKeyName, UsageType.ENCRYPTION, recipientCredPublic.getPublicKey());
+        roleDesc.getKeyDescriptors().add(kd);
+        
+        SAMLMetadataKeyAgreementEncryptionConfiguration kaConfig = new SAMLMetadataKeyAgreementEncryptionConfiguration();
+        PBKDF2 kdf = new PBKDF2();
+        kdf.initialize();
+        kaConfig.setParameters(Set.of(kdf));
+        encConfig.setKeyAgreementConfigurations(Map.of("EC", kaConfig));
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128, null, EncryptionConstants.ALGO_ID_KEYDERIVATION_PBKDF2);
+    }
+
+    @Test
+    public void roundtripWithKeyPlacementPeer() throws Exception {
+        KeyDescriptor kd = buildKeyDescriptor(recipientCredKeyName, UsageType.ENCRYPTION, recipientCredPublic.getPublicKey());
+        kd.getEncryptionMethods().add(buildEncryptionMethod(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM));
+        kd.getEncryptionMethods().add(buildEncryptionMethod(EncryptionConstants.ALGO_ID_KEYWRAP_AES256));
+        roleDesc.getKeyDescriptors().add(kd);
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM, EncryptionConstants.ALGO_ID_KEYWRAP_AES256, KeyPlacement.PEER);
+    }
+    
+    
+    
+    //
+    // Helpers
+    //
+
+    private void testRoundtrip(String expectedDataAlgo, String expectedKEKAlgo, Encrypter.KeyPlacement keyPlacement) throws Exception {
+        testRoundtrip(expectedDataAlgo, expectedKEKAlgo, null, keyPlacement);
+    }
+    
+    private void testRoundtrip(String expectedDataAlgo, String expectedKEKAlgo) throws Exception {
+        testRoundtrip(expectedDataAlgo, expectedKEKAlgo, null, KeyPlacement.INLINE);
+    }
+    
+    private void testRoundtrip(String expectedDataAlgo, String expectedKEKAlgo, String expectedKDFAlgo) throws Exception {
+        testRoundtrip(expectedDataAlgo, expectedKEKAlgo, expectedKEKAlgo, KeyPlacement.INLINE);
+    }
+    
+    private void testRoundtrip(String expectedDataAlgo, String expectedKEKAlgo, String expectedKDFAlgo, Encrypter.KeyPlacement keyPlacement) throws Exception {
+        // Encrypt
+        Assertion assertionOrig = (Assertion) unmarshallElement(targetFile);
+        
+        EncryptionParameters encParams = encParamsResolver.resolveSingle(encCriteria);
+        Assert.assertNotNull(encParams);
+        
+        DataEncryptionParameters dataEncParams = new DataEncryptionParameters(encParams);
+        List<KeyEncryptionParameters> kekParams = encParams.getKeyTransportEncryptionCredential() != null ?
+                List.of(new KeyEncryptionParameters(encParams, null)) : Collections.emptyList();
+                
+        encrypter = new Encrypter(dataEncParams, kekParams);
+        encrypter.setKeyPlacement(keyPlacement);
+        
+        EncryptedAssertion encryptedAssertionOrig = encrypter.encrypt(assertionOrig);
+        Assert.assertNotNull(encryptedAssertionOrig);
+        Assert.assertNotNull(encryptedAssertionOrig.getEncryptedData().getKeyInfo());
+        
+        if (expectedDataAlgo != null) {
+            Assert.assertEquals(encryptedAssertionOrig.getEncryptedData().getEncryptionMethod().getAlgorithm(), expectedDataAlgo);
+        }
+        
+        EncryptedKey encryptedKey = null;
+        switch(keyPlacement) {
+            case INLINE:
+                encryptedKey = !encryptedAssertionOrig.getEncryptedData().getKeyInfo().getEncryptedKeys().isEmpty()
+                    ? encryptedAssertionOrig.getEncryptedData().getKeyInfo().getEncryptedKeys().get(0) : null;
+                break;
+            case PEER:
+                encryptedKey = !encryptedAssertionOrig.getEncryptedKeys().isEmpty()
+                    ? encryptedAssertionOrig.getEncryptedKeys().get(0) : null;
+                break;
+        };
+            
+        if (expectedKEKAlgo != null) {
+            Assert.assertNotNull(encryptedKey);
+            Assert.assertEquals(encryptedKey.getEncryptionMethod().getAlgorithm(), expectedKEKAlgo);
+        }
+        
+        if (expectedKDFAlgo != null) {
+            KeyDerivationMethod kdm = null;
+            if (encryptedKey != null) {
+                kdm = (KeyDerivationMethod) encryptedKey.getKeyInfo().getAgreementMethods().get(0).getUnknownXMLObjects(KeyDerivationMethod.DEFAULT_ELEMENT_NAME).get(0); 
+            } else {
+                kdm = (KeyDerivationMethod) encryptedAssertionOrig.getEncryptedData().getKeyInfo().getAgreementMethods().get(0).getUnknownXMLObjects(KeyDerivationMethod.DEFAULT_ELEMENT_NAME).get(0);
+            }
+            Assert.assertNotNull(kdm);
+            Assert.assertEquals(kdm.getAlgorithm(), expectedKDFAlgo);
+        }
+        
+        // Serialize out and back in
+        Element domEncrypted = XMLObjectSupport.marshall(encryptedAssertionOrig);
+        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        SerializeSupport.writeNode(domEncrypted, baos);
+        baos.flush();
+        byte[] bytesEncrypted = baos.toByteArray();
+        
+        ByteArrayInputStream bais = new ByteArrayInputStream(bytesEncrypted);
+        EncryptedAssertion encryptedAssertion = (EncryptedAssertion) XMLObjectSupport.unmarshallFromInputStream(
+                XMLObjectProviderRegistrySupport.getParserPool(), bais);
+        Assert.assertNotNull(encryptedAssertion);
+        
+        // Decrypt
+        DecryptionParameters decryptParams = decryptParamsResolver.resolveSingle(decryptCriteria);
+        
+        Decrypter decrypter = new Decrypter(decryptParams);
+        
+        Assertion decryptedAssertion = decrypter.decrypt(encryptedAssertion);
+        Assert.assertNotNull(decryptedAssertion);
+        
+        assertXMLEquals(assertionOrig.getDOM().getOwnerDocument(), decryptedAssertion);
+    }
+    
+    private RoleDescriptor buildRoleDescriptorSkeleton() {
+        EntityDescriptor entityDesc = buildXMLObject(EntityDescriptor.DEFAULT_ELEMENT_NAME);
+        entityDesc.setEntityID(targetEntityID);
+        
+        SPSSODescriptor spSSODesc = buildXMLObject(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+        spSSODesc.setParent(entityDesc);
+        
+        return spSSODesc;
+    }
+    
+    private KeyDescriptor buildKeyDescriptor(String keyName, UsageType use, Object ... contentItems) {
+        KeyDescriptor keyDesc = buildXMLObject(KeyDescriptor.DEFAULT_ELEMENT_NAME);
+        KeyInfo keyInfo = buildXMLObject(KeyInfo.DEFAULT_ELEMENT_NAME);
+        
+        for (Object contentItem : contentItems) {
+            if (contentItem instanceof PublicKey) {
+                try {
+                    KeyInfoSupport.addPublicKey(keyInfo, (PublicKey) contentItem);
+                } catch (EncodingException e) {
+                    throw new RuntimeException("EncodingException adding public key to KeyInfo", e);
+                }
+            } else if (contentItem instanceof X509Certificate) {
+                try {
+                    KeyInfoSupport.addCertificate(keyInfo, (X509Certificate) contentItem);
+                } catch (CertificateEncodingException e) {
+                    throw new RuntimeException("CertificateEncodingException ading cert to KeyInfo", e);
+                }
+            } else {
+                throw new RuntimeException("Saw unknown KeyInfo content type: " + contentItem.getClass().getName());
+            }
+        }
+        
+        if (keyName != null) {
+            KeyInfoSupport.addKeyName(keyInfo, keyName);
+        }
+        
+        keyDesc.setKeyInfo(keyInfo);
+        
+        if (use != null) {
+            keyDesc.setUse(use);
+        }
+        
+        return keyDesc;
+    }
+    
+    private EncryptionMethod buildEncryptionMethod(String algorithm) {
+       EncryptionMethod encMethod = buildXMLObject(EncryptionMethod.DEFAULT_ELEMENT_NAME); 
+       encMethod.setAlgorithm(algorithm);
+       return encMethod;
+    }
+
+}
diff --git a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementSupport.java b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementSupport.java
index a8db46532..f42925508 100644
--- a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementSupport.java
+++ b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementSupport.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 import org.opensaml.core.config.ConfigurationService;
 import org.opensaml.security.credential.Credential;
 import org.opensaml.security.crypto.JCAConstants;
+import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
 import org.opensaml.xmlsec.encryption.AgreementMethod;
 import org.opensaml.xmlsec.encryption.EncryptedType;
 import org.opensaml.xmlsec.encryption.EncryptionMethod;
@@ -101,6 +102,38 @@ public final class KeyAgreementSupport {
         return et.getEncryptionMethod().getKeySize().getValue();
     }
     
+    /** 
+     * Validate the specified algorithm URI and key length for consistency.
+     * 
+     * <p>
+     * If the algorithm URI does not imply a key length, then the specified key length must be non-null.
+     * If the algorithm URI does imply a key length and the optional specified key length is non-null, 
+     * they must be the same length. 
+     * </p>
+     *
+     *  
+     * @param algorithmURI the algorithm URI
+     * @param specifiedKeyLength the optional specified key length
+     * 
+     * @throws KeyAgreementException if algorithm and specified key lengths are not consistent
+     */
+    public static void validateKeyAlgorithmAndSize(@Nonnull final String algorithmURI,
+            @Nullable final Integer specifiedKeyLength) throws KeyAgreementException {
+        
+        final Integer algoKeyLength = AlgorithmSupport.getKeyLength(algorithmURI);
+        
+        if (algoKeyLength == null && specifiedKeyLength == null) {
+            throw new KeyAgreementException("Key length was not specified and key algorithm does not imply a length: "
+                    + algorithmURI);
+        }
+        
+        if (algoKeyLength != null && specifiedKeyLength != null && ! algoKeyLength.equals(specifiedKeyLength)) {
+            throw new KeyAgreementException(String.format("Algorithm URI '%s' key length (%d) "
+                    + "does not match specified (%d)", algorithmURI, algoKeyLength, specifiedKeyLength));
+        }
+        
+    }
+    
     /**
      * Evaluate whether the specified credential contains a public key which supports key agreement.
      * 
diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/AbstractDerivationKeyAgreementProcessor.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/AbstractDerivationKeyAgreementProcessor.java
index 81a6f667c..94bfcfde4 100644
--- a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/AbstractDerivationKeyAgreementProcessor.java
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/AbstractDerivationKeyAgreementProcessor.java
@@ -24,6 +24,7 @@ import javax.crypto.SecretKey;
 import org.opensaml.xmlsec.agreement.KeyAgreementException;
 import org.opensaml.xmlsec.agreement.KeyAgreementParameters;
 import org.opensaml.xmlsec.agreement.KeyAgreementProcessor;
+import org.opensaml.xmlsec.agreement.KeyAgreementSupport;
 import org.opensaml.xmlsec.derivation.KeyDerivation;
 import org.opensaml.xmlsec.derivation.KeyDerivationException;
 
@@ -48,6 +49,8 @@ public abstract class AbstractDerivationKeyAgreementProcessor extends AbstractKe
         
         final Integer keySize = parameters.contains(KeySize.class) ? parameters.get(KeySize.class).getSize() : null;
         
+        KeyAgreementSupport.validateKeyAlgorithmAndSize(keyAlgorithm, keySize);
+        
         try {
             return keyDerivation.derive(secret, keyAlgorithm, keySize);
         } catch (final KeyDerivationException e) {
diff --git a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/ECDHKeyAgreementProcessorTest.java b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/ECDHKeyAgreementProcessorTest.java
index 4b9dc0e3d..0a909e659 100644
--- a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/ECDHKeyAgreementProcessorTest.java
+++ b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/ECDHKeyAgreementProcessorTest.java
@@ -177,6 +177,20 @@ public class ECDHKeyAgreementProcessorTest extends OpenSAMLInitBaseTestCase {
                 params);
     }
     
+    @Test(expectedExceptions = KeyAgreementException.class)
+    public void specifiedKeySizeMismatch() throws Exception {
+        KeyPair kp = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
+        Credential publicCredential = CredentialSupport.getSimpleCredential(kp.getPublic(), null);
+        
+        KeyAgreementParameters params = new KeyAgreementParameters();
+        params.add(new MockKeyDerivation()); 
+        params.add(new KeySize(256));
+        
+        processor.execute(publicCredential,
+                EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128,
+                params);
+    }
+    
     private Collection<KeyAgreementParameter> getMockParams() {
         ArrayList<KeyAgreementParameter> params = new ArrayList<>();
         KANonce nonce = new KANonce();
diff --git a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/tests/KeyAgreementSupportTest.java b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/tests/KeyAgreementSupportTest.java
new file mode 100644
index 000000000..2dd8f270b
--- /dev/null
+++ b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/tests/KeyAgreementSupportTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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 org.opensaml.xmlsec.agreement.tests;
+
+import java.security.KeyPair;
+import java.security.spec.ECGenParameterSpec;
+
+import org.opensaml.core.testing.XMLObjectBaseTestCase;
+import org.opensaml.security.credential.CredentialSupport;
+import org.opensaml.security.crypto.JCAConstants;
+import org.opensaml.security.crypto.KeySupport;
+import org.opensaml.xmlsec.agreement.KeyAgreementException;
+import org.opensaml.xmlsec.agreement.KeyAgreementSupport;
+import org.opensaml.xmlsec.agreement.impl.ECDHKeyAgreementProcessor;
+import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
+import org.opensaml.xmlsec.encryption.AgreementMethod;
+import org.opensaml.xmlsec.encryption.EncryptedData;
+import org.opensaml.xmlsec.encryption.EncryptionMethod;
+import org.opensaml.xmlsec.encryption.KeySize;
+import org.opensaml.xmlsec.encryption.support.EncryptionConstants;
+import org.opensaml.xmlsec.signature.KeyInfo;
+import org.opensaml.xmlsec.signature.support.SignatureConstants;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ *
+ */
+public class KeyAgreementSupportTest extends XMLObjectBaseTestCase {
+    
+    @Test
+    public void getGlobalProcessorRegistry() throws Exception {
+        Assert.assertNotNull(KeyAgreementSupport.getGlobalProcessorRegistry());
+    }
+    
+    @Test
+    public void getProcessor() throws Exception {
+        Assert.assertNotNull(KeyAgreementSupport.getProcessor(EncryptionConstants.ALGO_ID_KEYAGREEMENT_ECDH_ES));
+        Assert.assertTrue(ECDHKeyAgreementProcessor.class.isInstance(
+                KeyAgreementSupport.getProcessor(EncryptionConstants.ALGO_ID_KEYAGREEMENT_ECDH_ES)));
+    }
+
+    @Test
+    public void getExplicitKeySize() throws Exception {
+        AgreementMethod agreementMethod = buildXMLObject(AgreementMethod.DEFAULT_ELEMENT_NAME);
+        Assert.assertNull(KeyAgreementSupport.getExplicitKeySize(agreementMethod));
+        
+        KeyInfo keyInfo = buildXMLObject(KeyInfo.DEFAULT_ELEMENT_NAME);
+        keyInfo.getAgreementMethods().add(agreementMethod);
+        Assert.assertNull(KeyAgreementSupport.getExplicitKeySize(agreementMethod));
+        
+        EncryptedData encryptedData = buildXMLObject(EncryptedData.DEFAULT_ELEMENT_NAME);
+        encryptedData.setKeyInfo(keyInfo);
+        Assert.assertNull(KeyAgreementSupport.getExplicitKeySize(agreementMethod));
+        
+        EncryptionMethod encryptionMethod = buildXMLObject(EncryptionMethod.DEFAULT_ELEMENT_NAME);
+        encryptedData.setEncryptionMethod(encryptionMethod);
+        Assert.assertNull(KeyAgreementSupport.getExplicitKeySize(agreementMethod));
+        
+        KeySize keySize = buildXMLObject(KeySize.DEFAULT_ELEMENT_NAME);
+        keySize.setValue(128);
+        encryptionMethod.setKeySize(keySize);
+        Assert.assertEquals(KeyAgreementSupport.getExplicitKeySize(agreementMethod), Integer.valueOf(128));
+    }
+    
+    @Test
+    public void supportsKeyAgreement() throws Exception {
+        KeyPair ecKeyPair = KeySupport.generateKeyPair(JCAConstants.KEY_ALGO_EC, new ECGenParameterSpec("secp256r1"), null);
+        Assert.assertTrue(KeyAgreementSupport.supportsKeyAgreement(
+                CredentialSupport.getSimpleCredential(ecKeyPair.getPublic(), null)));
+        
+        Assert.assertFalse(KeyAgreementSupport.supportsKeyAgreement(
+                AlgorithmSupport.generateKeyPairAndCredential(EncryptionConstants.ALGO_ID_KEYTRANSPORT_RSAOAEP11, 2048, false)));
+        Assert.assertFalse(KeyAgreementSupport.supportsKeyAgreement(
+                AlgorithmSupport.generateKeyPairAndCredential(SignatureConstants.ALGO_ID_SIGNATURE_DSA_SHA256, 1024, false)));
+    }
+    
+    @Test
+    public void validateKeyAlgorithmAndSize() throws Exception {
+        KeyAgreementSupport.validateKeyAlgorithmAndSize(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, null);
+        KeyAgreementSupport.validateKeyAlgorithmAndSize(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, 128);
+        
+        KeyAgreementSupport.validateKeyAlgorithmAndSize(EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES, null);
+        KeyAgreementSupport.validateKeyAlgorithmAndSize(EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES, 192);
+        
+        KeyAgreementSupport.validateKeyAlgorithmAndSize(EncryptionConstants.ALGO_ID_KEYWRAP_AES128, null);
+        KeyAgreementSupport.validateKeyAlgorithmAndSize(EncryptionConstants.ALGO_ID_KEYWRAP_AES128, 128);
+        
+        // Non-length algorithm with non-null specified length should succeed
+        KeyAgreementSupport.validateKeyAlgorithmAndSize("SomeAlgo", 128);
+        
+        try {
+            KeyAgreementSupport.validateKeyAlgorithmAndSize(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128, 256);
+            Assert.fail("Should have failed mismatched specified length");
+        } catch (KeyAgreementException e) {
+            // expected
+        }
+        
+        try {
+            KeyAgreementSupport.validateKeyAlgorithmAndSize("SomeAlgo", null);
+            Assert.fail("Should have failed non-length URI and null specified length");
+        } catch (KeyAgreementException e) {
+            // expected
+        }
+    }
+    
+}
diff --git a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/encryption/support/tests/ECDHTest.java b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/encryption/support/tests/ECDHTest.java
new file mode 100644
index 000000000..f102eeafd
--- /dev/null
+++ b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/encryption/support/tests/ECDHTest.java
@@ -0,0 +1,237 @@
+/*
+ * 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 org.opensaml.xmlsec.encryption.support.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.security.KeyPair;
+import java.security.spec.ECGenParameterSpec;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opensaml.core.config.ConfigurationService;
+import org.opensaml.core.testing.XMLObjectBaseTestCase;
+import org.opensaml.core.xml.XMLObject;
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.core.xml.util.XMLObjectSupport;
+import org.opensaml.security.credential.BasicCredential;
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.credential.impl.CollectionCredentialResolver;
+import org.opensaml.security.crypto.KeySupport;
+import org.opensaml.xmlsec.DecryptionConfiguration;
+import org.opensaml.xmlsec.DecryptionParameters;
+import org.opensaml.xmlsec.DecryptionParametersResolver;
+import org.opensaml.xmlsec.EncryptionConfiguration;
+import org.opensaml.xmlsec.EncryptionParameters;
+import org.opensaml.xmlsec.EncryptionParametersResolver;
+import org.opensaml.xmlsec.criterion.DecryptionConfigurationCriterion;
+import org.opensaml.xmlsec.criterion.EncryptionConfigurationCriterion;
+import org.opensaml.xmlsec.derivation.impl.PBKDF2;
+import org.opensaml.xmlsec.encryption.EncryptedData;
+import org.opensaml.xmlsec.encryption.KeyDerivationMethod;
+import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters;
+import org.opensaml.xmlsec.encryption.support.Decrypter;
+import org.opensaml.xmlsec.encryption.support.Encrypter;
+import org.opensaml.xmlsec.encryption.support.EncryptionConstants;
+import org.opensaml.xmlsec.encryption.support.KeyAgreementEncryptionConfiguration;
+import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters;
+import org.opensaml.xmlsec.impl.BasicDecryptionConfiguration;
+import org.opensaml.xmlsec.impl.BasicDecryptionParametersResolver;
+import org.opensaml.xmlsec.impl.BasicEncryptionConfiguration;
+import org.opensaml.xmlsec.impl.BasicEncryptionParametersResolver;
+import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider;
+import org.opensaml.xmlsec.keyinfo.impl.LocalKeyInfoCredentialResolver;
+import org.opensaml.xmlsec.keyinfo.impl.provider.AgreementMethodKeyInfoProvider;
+import org.opensaml.xmlsec.mock.SignableSimpleXMLObject;
+import org.opensaml.xmlsec.testing.XMLSecurityTestingSupport;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.w3c.dom.Element;
+
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.xml.SerializeSupport;
+
+/**
+ *
+ */
+public class ECDHTest extends XMLObjectBaseTestCase {
+    
+    private String targetFile;
+    
+    private Credential recipientCredPrivate;
+    private Credential recipientCredPublic;
+    private CollectionCredentialResolver localCredentialResolver;
+    private LocalKeyInfoCredentialResolver localKeyInfoResolver;
+    
+    private Encrypter encrypter;
+    private EncryptionParametersResolver encParamsResolver;
+    private CriteriaSet encCriteria;
+    private BasicEncryptionConfiguration encConfig;
+    
+    private DecryptionParametersResolver decryptParamsResolver;
+    private CriteriaSet decryptCriteria;
+    private BasicDecryptionConfiguration decryptConfig;
+    
+    @BeforeClass
+    public void beforeClass() throws Exception {
+        targetFile = "/org/opensaml/xmlsec/encryption/support/SimpleEncryptionTest.xml";
+        
+        KeyPair kp = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
+        recipientCredPrivate = new BasicCredential(kp.getPublic(), kp.getPrivate());
+        recipientCredPublic = new BasicCredential(kp.getPublic());
+        
+        encrypter = new Encrypter();
+        encParamsResolver = new BasicEncryptionParametersResolver();
+        
+        decryptParamsResolver = new BasicDecryptionParametersResolver();
+        
+        localCredentialResolver = new CollectionCredentialResolver(Set.of(recipientCredPrivate));
+        
+        List<KeyInfoProvider> keyInfoProviders = new ArrayList<>(XMLSecurityTestingSupport.getBasicInlineKeyInfoProviders());
+        keyInfoProviders.add(new AgreementMethodKeyInfoProvider());
+        localKeyInfoResolver = new LocalKeyInfoCredentialResolver(keyInfoProviders, localCredentialResolver);
+    }
+    
+    @BeforeMethod
+    public void beforeMethod() throws Exception {
+        encConfig = new BasicEncryptionConfiguration();
+        encCriteria = new CriteriaSet(new EncryptionConfigurationCriterion(encConfig,
+                ConfigurationService.get(EncryptionConfiguration.class)));
+        
+        decryptConfig = new BasicDecryptionConfiguration();
+        decryptConfig.setDataKeyInfoCredentialResolver(localKeyInfoResolver);
+        decryptConfig.setKEKKeyInfoCredentialResolver(localKeyInfoResolver);
+        
+        decryptCriteria = new CriteriaSet(new DecryptionConfigurationCriterion(decryptConfig,
+                ConfigurationService.get(DecryptionConfiguration.class)));
+    }
+    
+    @Test
+    public void roundtripDirectDataEncryption() throws Exception {
+        encConfig.setDataEncryptionCredentials(List.of(recipientCredPublic));
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128, null);
+    }
+
+    @Test
+    public void roundtripDirectDataEncryptionWithAlgorithmOverrides() throws Exception {
+        encConfig.setDataEncryptionCredentials(List.of(recipientCredPublic));
+        encConfig.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM));
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, null);
+    }
+
+    @Test
+    public void roundtripWithKeyWrap() throws Exception {
+        encConfig.setKeyTransportEncryptionCredentials(List.of(recipientCredPublic));
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128, EncryptionConstants.ALGO_ID_KEYWRAP_AES128);
+    }
+
+    @Test
+    public void roundtripWithKeyWrapAndAlgorithmOverrides() throws Exception {
+        encConfig.setKeyTransportEncryptionCredentials(List.of(recipientCredPublic));
+        encConfig.setKeyTransportEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_KEYWRAP_AES256));
+        encConfig.setDataEncryptionAlgorithms(List.of(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM));
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, EncryptionConstants.ALGO_ID_KEYWRAP_AES256);
+    }
+
+    @Test
+    public void roundtripWithPBKDF2() throws Exception {
+        encConfig.setDataEncryptionCredentials(List.of(recipientCredPublic));
+        
+        KeyAgreementEncryptionConfiguration kaConfig = new KeyAgreementEncryptionConfiguration();
+        PBKDF2 kdf = new PBKDF2();
+        kdf.initialize();
+        kaConfig.setParameters(Set.of(kdf));
+        encConfig.setKeyAgreementConfigurations(Map.of("EC", kaConfig));
+        
+        testRoundtrip(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128, null, EncryptionConstants.ALGO_ID_KEYDERIVATION_PBKDF2);
+    }
+
+    private void testRoundtrip(String expectedDataAlgo, String expectedKEKAlgo) throws Exception {
+        testRoundtrip(expectedDataAlgo, expectedKEKAlgo, null);
+    }
+    
+    private void testRoundtrip(String expectedDataAlgo, String expectedKEKAlgo, String expectedKDFAlgo) throws Exception {
+        // Encrypt
+        SignableSimpleXMLObject sxoOrig = (SignableSimpleXMLObject) unmarshallElement(targetFile);
+        
+        EncryptionParameters encParams = encParamsResolver.resolveSingle(encCriteria);
+        Assert.assertNotNull(encParams);
+        
+        DataEncryptionParameters dataEncParams = new DataEncryptionParameters(encParams);
+        List<KeyEncryptionParameters> kekParams = encParams.getKeyTransportEncryptionCredential() != null ?
+                List.of(new KeyEncryptionParameters(encParams, null)) : Collections.emptyList();
+        
+        EncryptedData encryptedDataOrig = encrypter.encryptElement(sxoOrig, dataEncParams, kekParams);
+        Assert.assertNotNull(encryptedDataOrig);
+        Assert.assertNotNull(encryptedDataOrig.getKeyInfo());
+        
+        if (expectedDataAlgo != null) {
+            Assert.assertEquals(encryptedDataOrig.getEncryptionMethod().getAlgorithm(), expectedDataAlgo);
+        }
+        
+        if (expectedKEKAlgo != null) {
+            Assert.assertNotNull(encryptedDataOrig.getKeyInfo().getEncryptedKeys().get(0));
+            Assert.assertEquals(encryptedDataOrig.getKeyInfo().getEncryptedKeys().get(0).getEncryptionMethod().getAlgorithm(), expectedKEKAlgo);
+        }
+        
+        if (expectedKDFAlgo != null) {
+            KeyDerivationMethod kdm = null;
+           if (!encryptedDataOrig.getKeyInfo().getEncryptedKeys().isEmpty())  {
+               kdm = (KeyDerivationMethod) encryptedDataOrig.getKeyInfo().getEncryptedKeys().get(0).getKeyInfo().getAgreementMethods().get(0).getUnknownXMLObjects(KeyDerivationMethod.DEFAULT_ELEMENT_NAME).get(0); 
+           } else {
+               kdm = (KeyDerivationMethod) encryptedDataOrig.getKeyInfo().getAgreementMethods().get(0).getUnknownXMLObjects(KeyDerivationMethod.DEFAULT_ELEMENT_NAME).get(0);
+           }
+           Assert.assertNotNull(kdm);
+           Assert.assertEquals(kdm.getAlgorithm(), expectedKDFAlgo);
+        }
+        
+        // Serialize out and back in
+        Element domEncrypted = XMLObjectSupport.marshall(encryptedDataOrig);
+        
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        SerializeSupport.writeNode(domEncrypted, baos);
+        baos.flush();
+        byte[] bytesEncrypted = baos.toByteArray();
+        
+        ByteArrayInputStream bais = new ByteArrayInputStream(bytesEncrypted);
+        EncryptedData encryptedData = (EncryptedData) XMLObjectSupport.unmarshallFromInputStream(
+                XMLObjectProviderRegistrySupport.getParserPool(), bais);
+        Assert.assertNotNull(encryptedData);
+        
+        // Decrypt
+        DecryptionParameters decryptParams = decryptParamsResolver.resolveSingle(decryptCriteria);
+        
+        Decrypter decrypter = new Decrypter(decryptParams);
+        
+        XMLObject decryptedXMLObject = decrypter.decryptData(encryptedData);
+        Assert.assertNotNull(decryptedXMLObject);
+        Assert.assertTrue(decryptedXMLObject instanceof SignableSimpleXMLObject);
+        
+        assertXMLEquals(sxoOrig.getDOM().getOwnerDocument(), decryptedXMLObject);
+    }
+
+}
diff --git a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/testing/XMLSecurityTestingSupport.java b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/testing/XMLSecurityTestingSupport.java
index 20f1ae487..1ae4500a7 100644
--- a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/testing/XMLSecurityTestingSupport.java
+++ b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/testing/XMLSecurityTestingSupport.java
@@ -42,12 +42,16 @@ public final class XMLSecurityTestingSupport {
      * @return a new KeyInfoCredentialResolver instance
      */
     public static KeyInfoCredentialResolver buildBasicInlineKeyInfoResolver() {
+        return new BasicProviderKeyInfoCredentialResolver(getBasicInlineKeyInfoProviders());
+    }
+    
+    public static List<KeyInfoProvider> getBasicInlineKeyInfoProviders() {
         List<KeyInfoProvider> providers = new ArrayList<>();
         providers.add( new RSAKeyValueProvider() );
         providers.add( new DSAKeyValueProvider() );
         providers.add( new ECKeyValueProvider() );
         providers.add( new InlineX509DataProvider() );
-        return new BasicProviderKeyInfoCredentialResolver(providers);
+        return providers;
     }
 
 }
\ No newline at end of file

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


More information about the commits mailing list