[java-opensaml] 05/13: Key agreement components must account for both encryption and decryption

Brent Putman putmanb at georgetown.edu
Wed Jan 6 01:27:19 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=bc01c2e21f6efdd3931e33441b49674488fcf2c0

commit bc01c2e21f6efdd3931e33441b49674488fcf2c0
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Sat Dec 19 19:51:24 2020 -0500

    Key agreement components must account for both encryption and decryption
    
    Terminology of "recipient" and "originator" are reversed in the 2 cases,
    so instead use "public" and "private" since that doesn't really change.
    
    For decryption case, need to pass in the recipient/private credential
    via KeyAgreementParameters.
    
    In the KeyAgreementCredential production this means that have to
    populate the recipientCredential and originatorCredential properties
    based on which case it is.
---
 .../org/opensaml/security/crypto/ec/ECSupport.java | 14 ++---
 .../opensaml/security/crypto/ec/ECSupportTest.java | 11 ++--
 .../xmlsec/agreement/KeyAgreementProcessor.java    |  8 ++-
 .../impl/AbstractKeyAgreementProcessor.java        | 64 ++++++++++++++-------
 .../agreement/impl/ECDHKeyAgreementProcessor.java  | 47 +++++++++------
 .../xmlsec/agreement/impl/PrivateCredential.java   | 60 ++++++++++++++++++++
 .../xmlsec/agreement/impl/StaticStaticMode.java    | 33 +++++++++++
 .../impl/ECDHKeyAgreementProcessorTest.java        | 66 +++++++++++++++++++---
 .../agreement/impl/PrivateCredentialTest.java      | 55 ++++++++++++++++++
 9 files changed, 298 insertions(+), 60 deletions(-)

diff --git a/opensaml-security-api/src/main/java/org/opensaml/security/crypto/ec/ECSupport.java b/opensaml-security-api/src/main/java/org/opensaml/security/crypto/ec/ECSupport.java
index d1ed7a34a..4121f72ba 100644
--- a/opensaml-security-api/src/main/java/org/opensaml/security/crypto/ec/ECSupport.java
+++ b/opensaml-security-api/src/main/java/org/opensaml/security/crypto/ec/ECSupport.java
@@ -41,10 +41,10 @@ public final class ECSupport {
     private ECSupport() { }
     
     /**
-     * Perform ECDH key agreement between the given originator and recipient keys.
+     * Perform ECDH key agreement between the given public and private keys.
      * 
-     * @param recipientKey the recipient's public key
-     * @param originatorKey the originator's private key
+     * @param publicKeyKey the public key
+     * @param privateKey the private key
      * @param provider the optional security provider to use
      * 
      * @return the secret produced by key agreement
@@ -53,8 +53,8 @@ public final class ECSupport {
      * @throws NoSuchProviderException
      * @throws InvalidKeyException
      */
-    public static byte[] performKeyAgreement(@Nonnull final ECPublicKey recipientKey,
-            @Nonnull final ECPrivateKey originatorKey, @Nullable final String provider)
+    public static byte[] performKeyAgreement(@Nonnull final ECPublicKey publicKeyKey,
+            @Nonnull final ECPrivateKey privateKey, @Nullable final String provider)
                     throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException {
         
         KeyAgreement keyAgreement = null;
@@ -64,8 +64,8 @@ public final class ECSupport {
             keyAgreement = KeyAgreement.getInstance(JCAConstants.KEY_AGREEMENT_ECDH);
         }
         
-        keyAgreement.init(originatorKey);
-        keyAgreement.doPhase(recipientKey, true);
+        keyAgreement.init(privateKey);
+        keyAgreement.doPhase(publicKeyKey, true);
         return keyAgreement.generateSecret();
     }
 
diff --git a/opensaml-security-api/src/test/java/org/opensaml/security/crypto/ec/ECSupportTest.java b/opensaml-security-api/src/test/java/org/opensaml/security/crypto/ec/ECSupportTest.java
index ca0d6c5a0..bcff2cbb4 100644
--- a/opensaml-security-api/src/test/java/org/opensaml/security/crypto/ec/ECSupportTest.java
+++ b/opensaml-security-api/src/test/java/org/opensaml/security/crypto/ec/ECSupportTest.java
@@ -62,13 +62,14 @@ public class ECSupportTest {
     public void performKeyAgreement(String namedCurve) throws Exception {
         final KeyPairGenerator kpGenerator = KeyPairGenerator.getInstance(JCAConstants.KEY_ALGO_EC);
         kpGenerator.initialize(new ECGenParameterSpec(namedCurve));
-        final KeyPair recipientKeyPair = kpGenerator.generateKeyPair();
-        ECPublicKey recipientPublicKey = ECPublicKey.class.cast(recipientKeyPair.getPublic());
+        final KeyPair publicKeyPair = kpGenerator.generateKeyPair();
+        ECPublicKey publicKey = ECPublicKey.class.cast(publicKeyPair.getPublic());
         
-        final KeyPair originatorKeyPair = ECSupport.generateCompatibleKeyPair(recipientPublicKey, null);
-        final ECPrivateKey originatorPrivateKey = ECPrivateKey.class.cast(originatorKeyPair.getPrivate());
+        final KeyPair privateKeyPair = ECSupport.generateCompatibleKeyPair(publicKey, null);
         
-        byte[] secret = ECSupport.performKeyAgreement(recipientPublicKey, originatorPrivateKey, null);
+        final ECPrivateKey privateKey = ECPrivateKey.class.cast(privateKeyPair.getPrivate());
+        
+        byte[] secret = ECSupport.performKeyAgreement(publicKey, privateKey, null);
         Assert.assertNotNull(secret);
     }
 
diff --git a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementProcessor.java b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementProcessor.java
index ee51d920d..eaccabc0b 100644
--- a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementProcessor.java
+++ b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementProcessor.java
@@ -36,16 +36,18 @@ public interface KeyAgreementProcessor {
     /**
      * Perform the key agreement operation and return a new credential representing the results.
      * 
-     * @param recipientCredential the recipient credential
+     * @param publicCredential the public credential, which will belong either to the recipient or originator party,
+     *                         depending on whether encryption or decryption is being performed, respectively
      * @param keyAlgorithm the JCA key algorithm for the derived key
      * @param keyLength the key length for the derived key
-     * @param parameters parameters to the agreement operation
+     * @param parameters parameters to the agreement operation. Internally a copy will be created so this input instance
+     *                   will not be modified.
      * 
      * @return the agreement credential
      * 
      * @throws KeyAgreementException
      */
-    @Nonnull public KeyAgreementCredential execute(@Nonnull final Credential recipientCredential,
+    @Nonnull public KeyAgreementCredential execute(@Nonnull final Credential publicCredential,
             @Nonnull final String keyAlgorithm, @Nonnull final Integer keyLength,
             @Nonnull final KeyAgreementParameters parameters) throws KeyAgreementException;
 
diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/AbstractKeyAgreementProcessor.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/AbstractKeyAgreementProcessor.java
index 526881daa..0539a4bd3 100644
--- a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/AbstractKeyAgreementProcessor.java
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/AbstractKeyAgreementProcessor.java
@@ -25,53 +25,66 @@ import org.opensaml.xmlsec.agreement.KeyAgreementCredential;
 import org.opensaml.xmlsec.agreement.KeyAgreementException;
 import org.opensaml.xmlsec.agreement.KeyAgreementParameters;
 import org.opensaml.xmlsec.agreement.KeyAgreementProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Abstract base class for {@link KeyAgreementProcessor} implementations.
  */
 public abstract class AbstractKeyAgreementProcessor implements KeyAgreementProcessor {
+    
+    /** Logger. */
+    private final Logger log = LoggerFactory.getLogger(AbstractKeyAgreementProcessor.class);
 
     /** {@inheritDoc} */
-    @Nonnull public KeyAgreementCredential execute(@Nonnull final Credential recipientCredential,
+    @Nonnull public KeyAgreementCredential execute(@Nonnull final Credential publicCredential,
             @Nonnull final String keyAlgorithm, @Nonnull final Integer keyLength,
             @Nonnull final KeyAgreementParameters parameters) throws KeyAgreementException {
         
-        final Credential originatorCredential = obtainOriginatorCredential(recipientCredential, parameters);
+        final Credential privateCredential = obtainPrivateCredential(publicCredential, parameters);
         
-        final byte[] secret = generateAgreementSecret(recipientCredential, originatorCredential, parameters);
+        final byte[] secret = generateAgreementSecret(publicCredential, privateCredential, parameters);
         
         final SecretKey derivedKey = deriveSecretKey(secret, keyAlgorithm, keyLength, parameters);
         
-        return buildKeyAgreementCredential(derivedKey, recipientCredential, originatorCredential, parameters);
+        return buildKeyAgreementCredential(derivedKey, publicCredential, privateCredential, parameters);
     }
     
     /**
-     * Obtain an originator credential which is compatible with the given recipient credential.
+     * Obtain the private credential which is compatible with the given public credential.
      * 
-     * @param recipientCredential the recipient credential
+     * @param publicCredential the public credential
      * @param parameters the key agreement parameters
      * 
-     * @return the obtained originator credential
+     * @return the obtained private credential
      * 
      * @throws KeyAgreementException
      */
-    @Nonnull protected abstract Credential obtainOriginatorCredential(@Nonnull final Credential recipientCredential,
-            @Nonnull final KeyAgreementParameters parameters) throws KeyAgreementException;
+    @Nonnull protected Credential obtainPrivateCredential(@Nonnull final Credential publicCredential,
+            @Nonnull final KeyAgreementParameters parameters) throws KeyAgreementException {
+        
+        if (parameters.contains(PrivateCredential.class)) {
+            log.debug("Found supplied PrivateCredential in KeyAgreementParameters");
+            return parameters.get(PrivateCredential.class).getCredential();
+        }
+        return null;
+        
+    }
     
     /**
      * Generate the agreement secret according to the key algorithm and using the supplied
-     * originator and recipient credentials.
+     * public and private credentials.
      * 
-     * @param recipientCredential the recipient credential
-     * @param originatorCredential the originator credential
+     * @param publicCredential the public credential
+     * @param privateCredential the private credential
      * @param parameters the key agreement parameters
      * 
-     * @return the obtained originator credential
+     * @return the secret produced by the key agreement operation
      * 
      * @throws KeyAgreementException
      */
-    @Nonnull protected abstract byte[] generateAgreementSecret(@Nonnull final Credential recipientCredential,
-            @Nonnull final Credential originatorCredential, @Nonnull final KeyAgreementParameters parameters)
+    @Nonnull protected abstract byte[] generateAgreementSecret(@Nonnull final Credential publicCredential,
+            @Nonnull final Credential privateCredential, @Nonnull final KeyAgreementParameters parameters)
                 throws KeyAgreementException;
     
     /**
@@ -94,8 +107,8 @@ public abstract class AbstractKeyAgreementProcessor implements KeyAgreementProce
      * Build the final {@link KeyAgreementCredential} from the given inputs.
      * 
      * @param derivedKey the derived secret key
-     * @param recipientCredential the recipient credential
-     * @param originatorCredential the originator credential
+     * @param publicCredential the public credential
+     * @param privateCredential the private credential
      * @param parameters the key agreement parameters
      * 
      * @return the new key agreement credential
@@ -103,11 +116,24 @@ public abstract class AbstractKeyAgreementProcessor implements KeyAgreementProce
      * @throws KeyAgreementException
      */
     @Nonnull protected KeyAgreementCredential buildKeyAgreementCredential(@Nonnull final SecretKey derivedKey,
-            @Nonnull final Credential recipientCredential, @Nonnull final Credential originatorCredential,
+            @Nonnull final Credential publicCredential, @Nonnull final Credential privateCredential,
             @Nonnull final KeyAgreementParameters parameters) throws KeyAgreementException {
         
+        Credential recipient = null;
+        Credential originator = null;
+        
+        if (parameters.contains(PrivateCredential.class) && ! parameters.contains(StaticStaticMode.class)) {
+            // Decrypting party case
+            recipient = privateCredential;
+            originator = publicCredential;
+        } else {
+            // Encrypting party case
+            recipient = publicCredential;
+            originator = privateCredential;
+        }
+        
         final KeyAgreementCredential cred = new BasicKeyAgreementCredential(derivedKey, getAlgorithm(),
-                originatorCredential, recipientCredential);
+                originator, recipient);
         cred.getParameters().addAll(parameters);
         
         return cred;
diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/ECDHKeyAgreementProcessor.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/ECDHKeyAgreementProcessor.java
index 6cfb0d51a..ba2ef0286 100644
--- a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/ECDHKeyAgreementProcessor.java
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/ECDHKeyAgreementProcessor.java
@@ -34,12 +34,17 @@ import org.opensaml.xmlsec.agreement.KeyAgreementException;
 import org.opensaml.xmlsec.agreement.KeyAgreementParameters;
 import org.opensaml.xmlsec.agreement.KeyAgreementProcessor;
 import org.opensaml.xmlsec.encryption.support.EncryptionConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Implementation of {@link KeyAgreementProcessor} which performs Elliptic Curve Diffie-Hellman (ECDH)
  * Ephemeral-Static Mode key agreement as defined in XML Encryption 1.1.
  */
 public class ECDHKeyAgreementProcessor extends AbstractDerivationKeyAgreementProcessor {
+    
+    /** Logger. */
+    private final Logger log = LoggerFactory.getLogger(ECDHKeyAgreementProcessor.class);
 
     /** {@inheritDoc} */
     public String getAlgorithm() {
@@ -47,42 +52,50 @@ public class ECDHKeyAgreementProcessor extends AbstractDerivationKeyAgreementPro
     }
 
     /** {@inheritDoc} */
-    protected Credential obtainOriginatorCredential(@Nonnull final Credential recipientCredential,
+    protected Credential obtainPrivateCredential(@Nonnull final Credential publicCredential,
             @Nonnull final KeyAgreementParameters parameters) throws KeyAgreementException {
         
-        if (!ECPublicKey.class.isInstance(recipientCredential.getPublicKey())) {
-            throw new KeyAgreementException("Recipient credential's public key is not an instance of ECPublicKey");
+        final Credential suppliedCredential = super.obtainPrivateCredential(publicCredential, parameters);
+        if (suppliedCredential != null) {
+            return suppliedCredential;
         }
         
-        final ECPublicKey recipientPublicKey = ECPublicKey.class.cast(recipientCredential.getPublicKey());
+        log.debug("Found no supplied PrivateCredential in KeyAgreementParameters, generating ephemeral key pair");
+        
+        
+        if (!ECPublicKey.class.isInstance(publicCredential.getPublicKey())) {
+            throw new KeyAgreementException("Public credential's public key is not an instance of ECPublicKey");
+        }
+        
+        final ECPublicKey publicKey = ECPublicKey.class.cast(publicCredential.getPublicKey());
         
         try {
-            final KeyPair originatorKeyPair = ECSupport.generateCompatibleKeyPair(recipientPublicKey, null);
-            return new BasicCredential(originatorKeyPair.getPublic(), originatorKeyPair.getPrivate());
+            final KeyPair privateKeyPair = ECSupport.generateCompatibleKeyPair(publicKey, null);
+            return new BasicCredential(privateKeyPair.getPublic(), privateKeyPair.getPrivate());
         } catch (final NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
-            throw new KeyAgreementException("Error generating originator KeyPair from recipient EC public key", e);
+            throw new KeyAgreementException("Error generating private KeyPair from EC public key", e);
         }
     }
 
     /** {@inheritDoc} */
-    protected byte[] generateAgreementSecret(@Nonnull final Credential recipientCredential,
-            @Nonnull final Credential originatorCredential, @Nonnull final KeyAgreementParameters parameters)
+    protected byte[] generateAgreementSecret(@Nonnull final Credential publicCredential,
+            @Nonnull final Credential privateCredential, @Nonnull final KeyAgreementParameters parameters)
                     throws KeyAgreementException {
         
-        if (!ECPublicKey.class.isInstance(recipientCredential.getPublicKey())) {
-            throw new KeyAgreementException("Recipient credential's public key is not an instance of ECPublicKey");
+        if (!ECPublicKey.class.isInstance(publicCredential.getPublicKey())) {
+            throw new KeyAgreementException("Public credential's public key is not an instance of ECPublicKey");
         }
-        if (!ECPrivateKey.class.isInstance(originatorCredential.getPrivateKey())) {
-            throw new KeyAgreementException("Originator credential's private key is not an instance of ECPublicKey");
+        if (!ECPrivateKey.class.isInstance(privateCredential.getPrivateKey())) {
+            throw new KeyAgreementException("Private credential's private key is not an instance of ECPublicKey");
         }
         
-        final ECPublicKey recipient = ECPublicKey.class.cast(recipientCredential.getPublicKey());
-        final ECPrivateKey originator = ECPrivateKey.class.cast(originatorCredential.getPrivateKey());
+        final ECPublicKey publicKey = ECPublicKey.class.cast(publicCredential.getPublicKey());
+        final ECPrivateKey privateKey = ECPrivateKey.class.cast(privateCredential.getPrivateKey());
         
         try {
-            return ECSupport.performKeyAgreement(recipient, originator, null);
+            return ECSupport.performKeyAgreement(publicKey, privateKey, null);
         } catch (final InvalidKeyException | NoSuchAlgorithmException | NoSuchProviderException e) {
-            throw new KeyAgreementException("Error generating secret from recipient and originator EC keys", e);
+            throw new KeyAgreementException("Error generating secret from public and private EC keys", e);
         }
     }
 
diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/PrivateCredential.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/PrivateCredential.java
new file mode 100644
index 000000000..203f51211
--- /dev/null
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/PrivateCredential.java
@@ -0,0 +1,60 @@
+/*
+ * 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.impl;
+
+import java.security.PrivateKey;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.security.credential.Credential;
+import org.opensaml.xmlsec.agreement.KeyAgreementParameter;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Key agreement parameter used to pass a Credential holding a required private key.
+ * 
+ * <p>
+ * This is typically used in the decryption case to pass in the recipient's private credential.
+ * </p>
+ */
+public class PrivateCredential implements KeyAgreementParameter {
+    
+    /** The wrapped Credential. */
+    private Credential credential;
+
+    /**
+     * Constructor.
+     *
+     * @param newCredential the private credential, containing a {@link PrivateKey}
+     */
+    public PrivateCredential(@Nonnull final Credential newCredential) {
+        credential = Constraint.isNotNull(newCredential, "Private Credential was null");
+        Constraint.isNotNull(credential.getPrivateKey(), "Credential did not contain required PrivateKey");
+    }
+    
+    /**
+     * Get the wrapped credential.
+     * 
+     * @return the credential
+     */
+    @Nonnull public Credential getCredential() {
+        return credential;
+    }
+
+}
diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/StaticStaticMode.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/StaticStaticMode.java
new file mode 100644
index 000000000..1a9509d07
--- /dev/null
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/StaticStaticMode.java
@@ -0,0 +1,33 @@
+/*
+ * 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.impl;
+
+import org.opensaml.xmlsec.agreement.KeyAgreementParameter;
+
+/**
+ * Key agreement parameter whose presence indicates Static-Static mode is being used.
+ * 
+ * <p>
+ * This is typically used in the encryption case for Static-Static mode, along with passing the originator's
+ * (encrypting party's) credential via {@link PrivateCredential}.
+ * </p>
+ */
+public class StaticStaticMode implements KeyAgreementParameter {
+    
+
+}
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 1d8f51daf..c5d28d405 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
@@ -46,9 +46,9 @@ public class ECDHKeyAgreementProcessorTest {
     }
     
     @Test
-    public void basic() throws Exception {
-        KeyPair kp = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
-        Credential recipientCredential = CredentialSupport.getSimpleCredential(kp.getPublic(), null);
+    public void encryptingCase() throws Exception {
+        KeyPair recipientKeyPair = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
+        Credential recipientCredential = CredentialSupport.getSimpleCredential(recipientKeyPair.getPublic(), null);
         
         KeyAgreementParameters params = new KeyAgreementParameters();
         params.add(new MockKeyDerivation()); 
@@ -70,6 +70,7 @@ public class ECDHKeyAgreementProcessorTest {
         
         Assert.assertNotNull(keyAgreementCredential.getRecipientCredential());
         Assert.assertNotNull(keyAgreementCredential.getRecipientCredential().getPublicKey());
+        Assert.assertNull(keyAgreementCredential.getRecipientCredential().getPrivateKey());
         Assert.assertNull(keyAgreementCredential.getRecipientCredential().getSecretKey());
         
         Assert.assertNotNull(keyAgreementCredential.getOriginatorCredential());
@@ -85,17 +86,64 @@ public class ECDHKeyAgreementProcessorTest {
         Assert.assertEquals(keyAgreementCredential.getParameters().get(KANonce.class).getValue(), "someBase64");
         
     }
+    
+    @Test
+    public void decryptingCase() throws Exception {
+        KeyPair originatorKeyPair = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
+        Credential originatorCredential = CredentialSupport.getSimpleCredential(originatorKeyPair.getPublic(), null);
+        
+        KeyPair recipientKeyPair = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
+        Credential recipientCredential = CredentialSupport.getSimpleCredential(recipientKeyPair.getPublic(), recipientKeyPair.getPrivate());
+        
+        KeyAgreementParameters params = new KeyAgreementParameters();
+        params.add(new PrivateCredential(recipientCredential));
+        params.add(new MockKeyDerivation()); 
+        params.add(new KANonce("someBase64")); 
+        
+        KeyAgreementCredential keyAgreementCredential = processor.execute(originatorCredential,
+                JCAConstants.KEY_ALGO_AES,
+                128,
+                params);
+        
+        Assert.assertNotNull(keyAgreementCredential);
+        
+        Assert.assertNotNull(keyAgreementCredential.getSecretKey());
+        Assert.assertEquals(keyAgreementCredential.getSecretKey().getAlgorithm(), JCAConstants.KEY_ALGO_AES);
+        Assert.assertEquals(KeySupport.getKeyLength(keyAgreementCredential.getSecretKey()), Integer.valueOf(128));
+        
+        Assert.assertNull(keyAgreementCredential.getPublicKey());
+        Assert.assertNull(keyAgreementCredential.getPrivateKey());
+        
+        Assert.assertNotNull(keyAgreementCredential.getRecipientCredential());
+        Assert.assertNotNull(keyAgreementCredential.getRecipientCredential().getPublicKey());
+        Assert.assertNotNull(keyAgreementCredential.getRecipientCredential().getPrivateKey());
+        Assert.assertNull(keyAgreementCredential.getRecipientCredential().getSecretKey());
+        
+        Assert.assertNotNull(keyAgreementCredential.getOriginatorCredential());
+        Assert.assertNotNull(keyAgreementCredential.getOriginatorCredential().getPublicKey());
+        Assert.assertNull(keyAgreementCredential.getOriginatorCredential().getPrivateKey());
+        Assert.assertNull(keyAgreementCredential.getOriginatorCredential().getSecretKey());
+        
+        Assert.assertEquals(keyAgreementCredential.getAlgorithm(), EncryptionConstants.ALGO_ID_KEYAGREEMENT_ECDH_ES);
+        
+        Assert.assertEquals(keyAgreementCredential.getParameters().size(), 3);
+        Assert.assertTrue(keyAgreementCredential.getParameters().contains(PrivateCredential.class));
+        Assert.assertTrue(keyAgreementCredential.getParameters().contains(MockKeyDerivation.class));
+        Assert.assertTrue(keyAgreementCredential.getParameters().contains(KANonce.class));
+        Assert.assertEquals(keyAgreementCredential.getParameters().get(KANonce.class).getValue(), "someBase64");
+        
+    }
 
     @Test(expectedExceptions = KeyAgreementException.class)
     public void nonECCred() throws Exception {
         KeyPair kp = KeySupport.generateKeyPair("RSA", 2048, null);
-        Credential recipientCredential = CredentialSupport.getSimpleCredential(kp.getPublic(), null);
+        Credential publicCredential = CredentialSupport.getSimpleCredential(kp.getPublic(), null);
         
         KeyAgreementParameters params = new KeyAgreementParameters();
         params.add(new MockKeyDerivation()); 
         params.add(new KANonce("someBase64")); 
         
-        processor.execute(recipientCredential,
+        processor.execute(publicCredential,
                 JCAConstants.KEY_ALGO_AES,
                 128,
                 params);
@@ -104,13 +152,13 @@ public class ECDHKeyAgreementProcessorTest {
     @Test(expectedExceptions = KeyAgreementException.class)
     public void keyDerivationError() throws Exception {
         KeyPair kp = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
-        Credential recipientCredential = CredentialSupport.getSimpleCredential(kp.getPublic(), null);
+        Credential publicCredential = CredentialSupport.getSimpleCredential(kp.getPublic(), null);
         
         KeyAgreementParameters params = new KeyAgreementParameters();
         params.add(new MockKeyDerivation()); 
         params.add(new KANonce("someBase64")); 
         
-        processor.execute(recipientCredential,
+        processor.execute(publicCredential,
                 "INVALID",
                 128,
                 params);
@@ -119,12 +167,12 @@ public class ECDHKeyAgreementProcessorTest {
     @Test(expectedExceptions = KeyAgreementException.class)
     public void missingKeyDerivationParam() throws Exception {
         KeyPair kp = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
-        Credential recipientCredential = CredentialSupport.getSimpleCredential(kp.getPublic(), null);
+        Credential publicCredential = CredentialSupport.getSimpleCredential(kp.getPublic(), null);
         
         KeyAgreementParameters params = new KeyAgreementParameters();
         params.add(new KANonce("someBase64")); 
         
-        processor.execute(recipientCredential,
+        processor.execute(publicCredential,
                 JCAConstants.KEY_ALGO_AES,
                 128,
                 params);
diff --git a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/PrivateCredentialTest.java b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/PrivateCredentialTest.java
new file mode 100644
index 000000000..e772d772c
--- /dev/null
+++ b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/PrivateCredentialTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.impl;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.spec.ECGenParameterSpec;
+
+import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
+import org.opensaml.security.credential.CredentialSupport;
+import org.opensaml.security.crypto.KeySupport;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import net.shibboleth.utilities.java.support.logic.ConstraintViolationException;
+
+/**
+ *
+ */
+public class PrivateCredentialTest extends OpenSAMLInitBaseTestCase  {
+    
+    @Test
+    public void basic() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
+        KeyPair kp = KeySupport.generateKeyPair("EC", new ECGenParameterSpec("secp256r1"), null);
+        
+        PrivateCredential privateCredential = new PrivateCredential(CredentialSupport.getSimpleCredential(kp.getPublic(), kp.getPrivate()));
+        Assert.assertNotNull(privateCredential.getCredential());
+        
+        
+        try {
+            privateCredential = new PrivateCredential(CredentialSupport.getSimpleCredential(kp.getPublic(), null));
+            Assert.fail("PrivateCredential accepted Credential without PrivateKey");
+        } catch (ConstraintViolationException e) {
+            // expected, do nothing
+        }
+    }
+    
+}

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


More information about the commits mailing list