[java-opensaml] 13/13: KeyDerivation API must account for algorithm URIs without key length.
Brent Putman
putmanb at georgetown.edu
Wed Jan 6 01:27:27 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=0b6c403a234765ea0e31752c30704b77589906ff
commit 0b6c403a234765ea0e31752c30704b77589906ff
Author: Brent Putman <putmanb at georgetown.edu>
AuthorDate: Tue Jan 5 18:16:42 2021 -0500
KeyDerivation API must account for algorithm URIs without key length.
---
.../xmlsec/agreement/KeyAgreementSupport.java | 29 ++++++-
.../opensaml/xmlsec/derivation/KeyDerivation.java | 12 ++-
.../xmlsec/derivation/KeyDerivationSupport.java | 92 ++++++++++++++++++++++
.../derivation/KeyDerivationSupportTest.java | 85 ++++++++++++++++++++
.../AbstractDerivationKeyAgreementProcessor.java | 4 +-
.../impl/KeyAgreementParametersParser.java | 7 ++
.../opensaml/xmlsec/agreement/impl/KeySize.java | 35 +++++---
.../opensaml/xmlsec/derivation/impl/ConcatKDF.java | 15 ++--
.../opensaml/xmlsec/derivation/impl/PBKDF2.java | 24 +++---
.../provider/AgreementMethodKeyInfoProvider.java | 11 ++-
.../impl/KeyAgreementParametersParserTest.java | 60 ++++++++++++++
.../xmlsec/derivation/impl/ConcatKDFTest.java | 24 +++++-
.../xmlsec/derivation/impl/MockKeyDerivation.java | 2 +-
.../xmlsec/derivation/impl/PBKDF2Test.java | 28 +++++--
14 files changed, 372 insertions(+), 56 deletions(-)
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 39a4c4a17..241ac63e6 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
@@ -17,9 +17,14 @@
package org.opensaml.xmlsec.agreement;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opensaml.core.config.ConfigurationService;
+import org.opensaml.xmlsec.encryption.AgreementMethod;
+import org.opensaml.xmlsec.encryption.EncryptedType;
+import org.opensaml.xmlsec.encryption.EncryptionMethod;
+import org.opensaml.xmlsec.encryption.KeySize;
/**
* Support for key agreement operations.
@@ -33,9 +38,31 @@ public final class KeyAgreementSupport {
/**
* Get the global {@link KeyAgreementProcessorRegistry} instance.
*
- * @return the global procesor registry, or null if nothing registered
+ * @return the global processor registry, or null if nothing registered
*/
@Nullable public static KeyAgreementProcessorRegistry getGlobalProcessorRegistry() {
return ConfigurationService.get(KeyAgreementProcessorRegistry.class);
}
+
+ /**
+ * Look for an explicit key size via an {@link AgreementMethod}'s grandparent's {@link EncryptionMethod}
+ * child's {@link KeySize} child element.
+ *
+ * @param agreementMethod the AgreementMethod to process
+ *
+ * @return the key size, or null if not present
+ */
+ @Nullable public static Integer getExplicitKeySize(@Nonnull final AgreementMethod agreementMethod) {
+ if (agreementMethod.getParent() == null || agreementMethod.getParent().getParent() == null
+ || ! EncryptedType.class.isInstance(agreementMethod.getParent().getParent())) {
+ return null;
+ }
+
+ final EncryptedType et = EncryptedType.class.cast(agreementMethod.getParent().getParent());
+ if (et.getEncryptionMethod() == null || et.getEncryptionMethod().getKeySize() == null) {
+ return null;
+ }
+
+ return et.getEncryptionMethod().getKeySize().getValue();
+ }
}
diff --git a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/derivation/KeyDerivation.java b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/derivation/KeyDerivation.java
index 411e2abda..a5063dd1f 100644
--- a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/derivation/KeyDerivation.java
+++ b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/derivation/KeyDerivation.java
@@ -17,9 +17,12 @@
package org.opensaml.xmlsec.derivation;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import javax.crypto.SecretKey;
import org.opensaml.xmlsec.agreement.KeyAgreementParameter;
+import org.opensaml.xmlsec.algorithm.KeyLengthSpecifiedAlgorithm;
/**
* Component which represents a specific key derivation algorithm, and supports deriving a new {@link SecretKey}
@@ -36,18 +39,23 @@ public interface KeyDerivation extends KeyAgreementParameter {
*
* @return the algorithm
*/
- public String getAlgorithm();
+ @Nonnull public String getAlgorithm();
/**
* Derive a {@link SecretKey} from the specified secret.
*
* @param secret the input secret from which to derive the key.
* @param keyAlgorithm the algorithm URI for which the derived key will be used
+ * @param keyLength the length of the derived key. This may be null if the keyAlgorithm URI
+ * implies a key length, for example if the URI represents a {@link KeyLengthSpecifiedAlgorithm}.
+ * However if the URI implies a key length and this parameter value does not match that length,
+ * that is an error and and exception will be thrown
*
* @return the derived key
*
* @throws KeyDerivationException
*/
- public SecretKey derive(byte[] secret, String keyAlgorithm) throws KeyDerivationException;
+ @Nonnull public SecretKey derive(@Nonnull final byte[] secret, @Nonnull final String keyAlgorithm,
+ @Nullable final Integer keyLength) throws KeyDerivationException;
}
diff --git a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/derivation/KeyDerivationSupport.java b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/derivation/KeyDerivationSupport.java
new file mode 100644
index 000000000..e19165156
--- /dev/null
+++ b/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/derivation/KeyDerivationSupport.java
@@ -0,0 +1,92 @@
+/*
+ * 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.derivation;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * Support key derivation operations.
+ */
+public final class KeyDerivationSupport {
+
+ /** Constructor. */
+ private KeyDerivationSupport() { }
+
+ /**
+ * Get the JCA key algorithm which corresponds to the specified algorithm URI.
+ *
+ * @param algorithmURI the algorithm URI with which the derived key will be user
+ *
+ * @return the JCA key algorithm
+ *
+ * @throws KeyDerivationException
+ */
+ @Nonnull public static String getJCAKeyAlgorithm(@Nonnull final String algorithmURI)
+ throws KeyDerivationException {
+ Constraint.isNotNull(algorithmURI, "Algorithm URI was null");
+
+ final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(algorithmURI);
+ if (jcaKeyAlgorithm == null) {
+ throw new KeyDerivationException("Could not determine JCA key algorithm from URI: " + algorithmURI);
+ }
+ return jcaKeyAlgorithm;
+ }
+
+ /**
+ * Get the effective key length based on the specified algorithm URI and the specified key length, if present.
+ *
+ * <p>
+ * If the algorithm URI implies a key length and the specified key length is non-null, the lengths must
+ * match or an exception will be thrown. If the algorithm URI does not imply a key length and the specified
+ * length is null, and exception will be thrown.
+ * </p>
+ *
+ * @param algorithmURI the algorithm URI with which the derived key will be used
+ * @param specifiedKeyLength an explicitly specified key length
+ *
+ * @return the effective key length
+ *
+ * @throws KeyDerivationException
+ */
+ @Nonnull public static Integer getEffectiveKeyLength(@Nonnull final String algorithmURI,
+ @Nullable final Integer specifiedKeyLength) throws KeyDerivationException {
+ Constraint.isNotNull(algorithmURI, "Algorithm URI was null");
+
+ final Integer algoKeyLength = AlgorithmSupport.getKeyLength(algorithmURI);
+ if (algoKeyLength == null) {
+ if (specifiedKeyLength == null) {
+ throw new KeyDerivationException(String.format("Could not determine algorithm key length from URI '%s'"
+ + "and no length was specified", algorithmURI));
+ }
+ return specifiedKeyLength;
+ }
+
+ if (specifiedKeyLength != null && ! specifiedKeyLength.equals(algoKeyLength)) {
+ throw new KeyDerivationException(String.format("Algorithm URI '%s' key length (%d) "
+ + "does not match specified (%d)", algorithmURI, algoKeyLength, specifiedKeyLength));
+ }
+
+ return algoKeyLength;
+ }
+
+}
diff --git a/opensaml-xmlsec-api/src/test/java/org/opensaml/xmlsec/derivation/KeyDerivationSupportTest.java b/opensaml-xmlsec-api/src/test/java/org/opensaml/xmlsec/derivation/KeyDerivationSupportTest.java
new file mode 100644
index 000000000..6aeb75711
--- /dev/null
+++ b/opensaml-xmlsec-api/src/test/java/org/opensaml/xmlsec/derivation/KeyDerivationSupportTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.derivation;
+
+import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
+import org.opensaml.security.crypto.JCAConstants;
+import org.opensaml.xmlsec.encryption.support.EncryptionConstants;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+/**
+ *
+ */
+public class KeyDerivationSupportTest extends OpenSAMLInitBaseTestCase {
+
+ @Test
+ public void getJCAKeyAlgorithm() throws Exception {
+ Assert.assertEquals(KeyDerivationSupport.getJCAKeyAlgorithm(
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM), JCAConstants.KEY_ALGO_AES);
+
+ Assert.assertEquals(KeyDerivationSupport.getJCAKeyAlgorithm(
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES), JCAConstants.KEY_ALGO_DESEDE);
+
+ Assert.assertEquals(KeyDerivationSupport.getJCAKeyAlgorithm(
+ EncryptionConstants.ALGO_ID_KEYWRAP_AES128), JCAConstants.KEY_ALGO_AES);
+
+ try {
+ KeyDerivationSupport.getJCAKeyAlgorithm("INVALID");
+ Assert.fail("Should have failed invalid URI");
+ } catch (KeyDerivationException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void getEffectiveKeyLength() throws Exception {
+ Assert.assertEquals(KeyDerivationSupport.getEffectiveKeyLength(
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, null).intValue(), 128);
+ Assert.assertEquals(KeyDerivationSupport.getEffectiveKeyLength(
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, 128).intValue(), 128);
+
+ Assert.assertEquals(KeyDerivationSupport.getEffectiveKeyLength(
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES, null).intValue(), 192);
+ Assert.assertEquals(KeyDerivationSupport.getEffectiveKeyLength(
+ EncryptionConstants.ALGO_ID_BLOCKCIPHER_TRIPLEDES, 192).intValue(), 192);
+
+ Assert.assertEquals(KeyDerivationSupport.getEffectiveKeyLength(
+ EncryptionConstants.ALGO_ID_KEYWRAP_AES128, null).intValue(), 128);
+ Assert.assertEquals(KeyDerivationSupport.getEffectiveKeyLength(
+ EncryptionConstants.ALGO_ID_KEYWRAP_AES128, 128).intValue(), 128);
+
+ // Non-length algorithm with non-null specified length should succeed as specified length
+ Assert.assertEquals(KeyDerivationSupport.getEffectiveKeyLength("SomeAlgo", 128).intValue(), 128);
+
+ try {
+ KeyDerivationSupport.getEffectiveKeyLength(EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, 256);
+ Assert.fail("Should have failed mismatched specified length");
+ } catch (KeyDerivationException e) {
+ // expected
+ }
+
+ try {
+ KeyDerivationSupport.getEffectiveKeyLength( "SomeAlgo", null);
+ Assert.fail("Should have failed non-length URI and null specified length");
+ } catch (KeyDerivationException e) {
+ //expected
+ }
+ }
+
+}
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 d079888bc..81a6f667c 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
@@ -46,8 +46,10 @@ public abstract class AbstractDerivationKeyAgreementProcessor extends AbstractKe
throw new KeyAgreementException("Required KeyDerivation parameter was not supplied");
}
+ final Integer keySize = parameters.contains(KeySize.class) ? parameters.get(KeySize.class).getSize() : null;
+
try {
- return keyDerivation.derive(secret, keyAlgorithm);
+ return keyDerivation.derive(secret, keyAlgorithm, keySize);
} catch (final KeyDerivationException e) {
throw new KeyAgreementException("Key derivation failed using supplied KeyDerivation parameter", e);
}
diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/KeyAgreementParametersParser.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/KeyAgreementParametersParser.java
index e74f5fb1a..01352340d 100644
--- a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/KeyAgreementParametersParser.java
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/KeyAgreementParametersParser.java
@@ -25,6 +25,7 @@ import javax.annotation.Nonnull;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.xmlsec.agreement.KeyAgreementException;
import org.opensaml.xmlsec.agreement.KeyAgreementParameters;
+import org.opensaml.xmlsec.agreement.KeyAgreementSupport;
import org.opensaml.xmlsec.encryption.AgreementMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -83,6 +84,12 @@ public class KeyAgreementParametersParser {
}
}
+ // The grandparent's EncryptionMethod KeySize element is an implicit parameter to the agreement operation
+ final Integer keySize = KeyAgreementSupport.getExplicitKeySize(agreementMethod);
+ if (keySize != null) {
+ parameters.add(new KeySize(keySize));
+ }
+
parameters.initializeAll();
return parameters;
diff --git a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementSupport.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/KeySize.java
similarity index 54%
copy from opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementSupport.java
copy to opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/KeySize.java
index 39a4c4a17..30e67d60a 100644
--- a/opensaml-xmlsec-api/src/main/java/org/opensaml/xmlsec/agreement/KeyAgreementSupport.java
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/agreement/impl/KeySize.java
@@ -15,27 +15,38 @@
* limitations under the License.
*/
-package org.opensaml.xmlsec.agreement;
+package org.opensaml.xmlsec.agreement.impl;
-import javax.annotation.Nullable;
+import javax.annotation.Nonnull;
-import org.opensaml.core.config.ConfigurationService;
+import org.opensaml.xmlsec.agreement.KeyAgreementParameter;
+
+import net.shibboleth.utilities.java.support.logic.Constraint;
/**
- * Support for key agreement operations.
+ * Key agreement parameter used to explicitly represent the size of the derived key.
*/
-public final class KeyAgreementSupport {
+public class KeySize implements KeyAgreementParameter {
- /** Constructor. */
- private KeyAgreementSupport() {}
-
+ /** Key size. */
+ @Nonnull private Integer size;
/**
- * Get the global {@link KeyAgreementProcessorRegistry} instance.
+ * Constructor.
+ *
+ * @param keySize the key size, in bits
+ */
+ public KeySize(@Nonnull final Integer keySize) {
+ size = Constraint.isNotNull(keySize, "Specified key size was null");
+ }
+
+ /**
+ * Get the key size, in bits.
*
- * @return the global procesor registry, or null if nothing registered
+ * @return the key size in bits
*/
- @Nullable public static KeyAgreementProcessorRegistry getGlobalProcessorRegistry() {
- return ConfigurationService.get(KeyAgreementProcessorRegistry.class);
+ @Nonnull public Integer getSize() {
+ return size;
}
+
}
diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/derivation/impl/ConcatKDF.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/derivation/impl/ConcatKDF.java
index 32d8d7ebb..4f746b8be 100644
--- a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/derivation/impl/ConcatKDF.java
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/derivation/impl/ConcatKDF.java
@@ -45,6 +45,7 @@ import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
import org.opensaml.xmlsec.algorithm.DigestAlgorithm;
import org.opensaml.xmlsec.derivation.KeyDerivation;
import org.opensaml.xmlsec.derivation.KeyDerivationException;
+import org.opensaml.xmlsec.derivation.KeyDerivationSupport;
import org.opensaml.xmlsec.encryption.ConcatKDFParams;
import org.opensaml.xmlsec.encryption.EncryptedType;
import org.opensaml.xmlsec.encryption.KeyDerivationMethod;
@@ -265,21 +266,15 @@ public class ConcatKDF extends AbstractInitializableComponent
}
/** {@inheritDoc} */
- public SecretKey derive(@Nonnull final byte[] secret, @Nonnull final String keyAlgorithm)
- throws KeyDerivationException {
+ public SecretKey derive(@Nonnull final byte[] secret, @Nonnull final String keyAlgorithm,
+ @Nullable final Integer keyLength) throws KeyDerivationException {
Constraint.isNotNull(secret, "Secret byte[] was null");
Constraint.isNotNull(keyAlgorithm, "Key algorithm was null");
ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
- final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(keyAlgorithm);
- if (jcaKeyAlgorithm == null) {
- throw new KeyDerivationException("Could not determine JCA key algorithm from URI: " + keyAlgorithm);
- }
+ final String jcaKeyAlgorithm = KeyDerivationSupport.getJCAKeyAlgorithm(keyAlgorithm);
- final Integer jcaKeyLength = AlgorithmSupport.getKeyLength(keyAlgorithm);
- if (jcaKeyLength == null) {
- throw new KeyDerivationException("Could not determine JCA key length from URI: " + keyAlgorithm);
- }
+ final Integer jcaKeyLength = KeyDerivationSupport.getEffectiveKeyLength(keyAlgorithm, keyLength);
final byte[] otherInfo = Bytes.concat(
decodeParam(algorithmID, "AlgorithmID"),
diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/derivation/impl/PBKDF2.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/derivation/impl/PBKDF2.java
index 2b9e5a293..43325a3cd 100644
--- a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/derivation/impl/PBKDF2.java
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/derivation/impl/PBKDF2.java
@@ -40,6 +40,7 @@ import org.opensaml.xmlsec.algorithm.AlgorithmSupport;
import org.opensaml.xmlsec.algorithm.MACAlgorithm;
import org.opensaml.xmlsec.derivation.KeyDerivation;
import org.opensaml.xmlsec.derivation.KeyDerivationException;
+import org.opensaml.xmlsec.derivation.KeyDerivationSupport;
import org.opensaml.xmlsec.encryption.IterationCount;
import org.opensaml.xmlsec.encryption.KeyDerivationMethod;
import org.opensaml.xmlsec.encryption.KeyLength;
@@ -276,20 +277,17 @@ public class PBKDF2 extends AbstractInitializableComponent
// Checkstyle: CyclomaticComplexity ON
/** {@inheritDoc} */
- public SecretKey derive(@Nonnull final byte[] secret, @Nonnull final String keyAlgorithm)
- throws KeyDerivationException {
+ public SecretKey derive(@Nonnull final byte[] secret, @Nonnull final String keyAlgorithm,
+ @Nullable final Integer specifiedKeyLength) throws KeyDerivationException {
Constraint.isNotNull(secret, "Secret byte[] was null");
Constraint.isNotNull(keyAlgorithm, "Key algorithm was null");
ComponentSupport.ifNotInitializedThrowUninitializedComponentException(this);
- final String jcaKeyAlgorithm = AlgorithmSupport.getKeyAlgorithm(keyAlgorithm);
- if (jcaKeyAlgorithm == null) {
- throw new KeyDerivationException("Could not determine JCA key algorithm from URI: " + keyAlgorithm);
- }
+ final String jcaKeyAlgorithm = KeyDerivationSupport.getJCAKeyAlgorithm(keyAlgorithm);
final byte[] saltBytes = getEffectiveSalt();
- final Integer length = getEffectiveKeyLength(keyAlgorithm);
+ final Integer length = getEffectiveKeyLength(keyAlgorithm, specifiedKeyLength);
final String jcaPRF = AlgorithmSupport.getAlgorithmID(prf);
@@ -338,17 +336,17 @@ public class PBKDF2 extends AbstractInitializableComponent
* Get the effective key length, in bits.
*
* @param keyAlgorithm the algorithm for which the derived key will be used
+ * @param specifiedKeyLength
*
* @return the effective key length, in bits
*
* @throws KeyDerivationException
*/
- protected Integer getEffectiveKeyLength(@Nonnull final String keyAlgorithm) throws KeyDerivationException {
- final Integer jcaKeyLength = AlgorithmSupport.getKeyLength(keyAlgorithm);
- if (jcaKeyLength == null) {
- throw new KeyDerivationException("Failed to determine key length for algorithm URI: " + keyAlgorithm);
- }
-
+ protected Integer getEffectiveKeyLength(@Nonnull final String keyAlgorithm,
+ @Nullable final Integer specifiedKeyLength) throws KeyDerivationException {
+
+ final Integer jcaKeyLength = KeyDerivationSupport.getEffectiveKeyLength(keyAlgorithm, specifiedKeyLength);
+
if (keyLength == null) {
// Usually the originator/encrypting case. We set it internally here so can emit in XML later.
keyLength = jcaKeyLength;
diff --git a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/keyinfo/impl/provider/AgreementMethodKeyInfoProvider.java b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/keyinfo/impl/provider/AgreementMethodKeyInfoProvider.java
index 9a77047d3..99ca9d92d 100644
--- a/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/keyinfo/impl/provider/AgreementMethodKeyInfoProvider.java
+++ b/opensaml-xmlsec-impl/src/main/java/org/opensaml/xmlsec/keyinfo/impl/provider/AgreementMethodKeyInfoProvider.java
@@ -36,6 +36,8 @@ import org.opensaml.xmlsec.agreement.impl.KeyAgreementParametersParser;
import org.opensaml.xmlsec.agreement.impl.PrivateCredential;
import org.opensaml.xmlsec.encryption.AgreementMethod;
import org.opensaml.xmlsec.encryption.EncryptedType;
+import org.opensaml.xmlsec.encryption.EncryptionMethod;
+import org.opensaml.xmlsec.encryption.KeySize;
import org.opensaml.xmlsec.encryption.OriginatorKeyInfo;
import org.opensaml.xmlsec.encryption.RecipientKeyInfo;
import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolutionMode;
@@ -113,7 +115,7 @@ public class AgreementMethodKeyInfoProvider extends AbstractKeyInfoProvider {
final KeyAgreementParameters parameters = parametersParser.parse(agreementMethod);
parameters.add(new PrivateCredential(recipientCredential));
- final String keyAlgorithm = resolveKeyAlgorithmAndSize(agreementMethod, parameters);
+ final String keyAlgorithm = resolveKeyAlgorithm(agreementMethod);
cred = processor.execute(originatorCredential, keyAlgorithm, parameters);
@@ -143,14 +145,13 @@ public class AgreementMethodKeyInfoProvider extends AbstractKeyInfoProvider {
* </p>
*
* @param agreementMethod the AgreementMethod to process
- * @param parameters the key agreement parameters
*
* @return the encryption algorithm URI
*
* @throws SecurityException if the algorithm URI can not be resolved
*/
- @Nonnull private String resolveKeyAlgorithmAndSize(@Nonnull final AgreementMethod agreementMethod,
- @Nonnull final KeyAgreementParameters parameters) throws SecurityException {
+ @Nonnull private String resolveKeyAlgorithm(@Nonnull final AgreementMethod agreementMethod)
+ throws SecurityException {
// This was already validated in handles(...)
final EncryptedType encrytpedType = EncryptedType.class.cast(agreementMethod.getParent().getParent());
@@ -159,8 +160,6 @@ public class AgreementMethodKeyInfoProvider extends AbstractKeyInfoProvider {
throw new SecurityException("EncryptedType contains no EncryptionMethod algorithm");
}
- //TODO handle KeySize when new KeySize param is ready; add it to parameters
-
return encrytpedType.getEncryptionMethod().getAlgorithm();
}
diff --git a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/KeyAgreementParametersParserTest.java b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/KeyAgreementParametersParserTest.java
index aa13f143b..fb15474fc 100644
--- a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/KeyAgreementParametersParserTest.java
+++ b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/agreement/impl/KeyAgreementParametersParserTest.java
@@ -24,6 +24,8 @@ import org.opensaml.xmlsec.derivation.impl.ConcatKDF;
import org.opensaml.xmlsec.derivation.impl.PBKDF2;
import org.opensaml.xmlsec.encryption.AgreementMethod;
import org.opensaml.xmlsec.encryption.ConcatKDFParams;
+import org.opensaml.xmlsec.encryption.EncryptedData;
+import org.opensaml.xmlsec.encryption.EncryptionMethod;
import org.opensaml.xmlsec.encryption.IterationCount;
import org.opensaml.xmlsec.encryption.KeyDerivationMethod;
import org.opensaml.xmlsec.encryption.KeyLength;
@@ -32,6 +34,7 @@ import org.opensaml.xmlsec.encryption.PRF;
import org.opensaml.xmlsec.encryption.Salt;
import org.opensaml.xmlsec.encryption.Specified;
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;
@@ -82,6 +85,63 @@ public class KeyAgreementParametersParserTest extends XMLObjectBaseTestCase {
Assert.assertEquals(kdf.getSuppPrivInfo(), "EE");
}
+ @Test
+ public void ECDHWithConcatKDFWithKeySize() throws KeyAgreementException {
+ org.opensaml.xmlsec.encryption.KeySize xmlKeySize = buildXMLObject(org.opensaml.xmlsec.encryption.KeySize.DEFAULT_ELEMENT_NAME);
+ xmlKeySize.setValue(80);
+
+ EncryptionMethod em = buildXMLObject(EncryptionMethod.DEFAULT_ELEMENT_NAME);
+ em.setKeySize(xmlKeySize);
+
+ EncryptedData ed = buildXMLObject(EncryptedData.DEFAULT_ELEMENT_NAME);
+ ed.setEncryptionMethod(em);
+
+ KeyInfo keyInfo = buildXMLObject(KeyInfo.DEFAULT_ELEMENT_NAME);
+ ed.setKeyInfo(keyInfo);
+
+ AgreementMethod agreementMethod = buildXMLObject(AgreementMethod.DEFAULT_ELEMENT_NAME);
+ agreementMethod.setAlgorithm(EncryptionConstants.ALGO_ID_KEYAGREEMENT_ECDH_ES);
+ keyInfo.getAgreementMethods().add(agreementMethod);
+
+ KeyDerivationMethod kdm = buildXMLObject(KeyDerivationMethod.DEFAULT_ELEMENT_NAME);
+ kdm.setAlgorithm(EncryptionConstants.ALGO_ID_KEYDERIVATION_CONCATKDF);
+
+ ConcatKDFParams xmlParams = buildXMLObject(ConcatKDFParams.DEFAULT_ELEMENT_NAME);
+ xmlParams.setAlgorithmID("00AA");
+ xmlParams.setPartyUInfo("00BB");
+ xmlParams.setPartyVInfo("00CC");
+ xmlParams.setSuppPubInfo("00DD");
+ xmlParams.setSuppPrivInfo("00EE");
+
+ org.opensaml.xmlsec.signature.DigestMethod digestMethod = buildXMLObject(org.opensaml.xmlsec.signature.DigestMethod.DEFAULT_ELEMENT_NAME);
+ digestMethod.setAlgorithm(SignatureConstants.ALGO_ID_DIGEST_SHA512);
+ xmlParams.setDigestMethod(digestMethod);
+
+ kdm.getUnknownXMLObjects().add(xmlParams);
+
+ agreementMethod.getUnknownXMLObjects().add(kdm);
+
+ KeyAgreementParametersParser parser = new KeyAgreementParametersParser();
+
+ KeyAgreementParameters parameters = parser.parse(agreementMethod);
+ Assert.assertNotNull(parameters);
+ Assert.assertEquals(parameters.size(), 2);
+
+ Assert.assertTrue(parameters.contains(ConcatKDF.class));
+
+ ConcatKDF kdf = parameters.get(ConcatKDF.class);
+ Assert.assertTrue(kdf.isInitialized());
+ Assert.assertEquals(kdf.getDigestMethod(), SignatureConstants.ALGO_ID_DIGEST_SHA512);
+ Assert.assertEquals(kdf.getAlgorithmID(), "AA");
+ Assert.assertEquals(kdf.getPartyUInfo(), "BB");
+ Assert.assertEquals(kdf.getPartyVInfo(), "CC");
+ Assert.assertEquals(kdf.getSuppPubInfo(), "DD");
+ Assert.assertEquals(kdf.getSuppPrivInfo(), "EE");
+
+ Assert.assertTrue(parameters.contains(KeySize.class));
+ Assert.assertEquals(parameters.get(KeySize.class).getSize().intValue(), 80);
+ }
+
@Test
public void ECDHWithPBKDF2() throws KeyAgreementException {
AgreementMethod agreementMethod = buildXMLObject(AgreementMethod.DEFAULT_ELEMENT_NAME);
diff --git a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/ConcatKDFTest.java b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/ConcatKDFTest.java
index 761a73f2f..85561c287 100644
--- a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/ConcatKDFTest.java
+++ b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/ConcatKDFTest.java
@@ -294,7 +294,7 @@ public class ConcatKDFTest extends XMLObjectBaseTestCase {
byte[] secret = Hex.decodeHex("DEADBEEF");
- SecretKey derivedKey = kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM);
+ SecretKey derivedKey = kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, null);
Assert.assertNotNull(derivedKey);
Assert.assertEquals(derivedKey.getAlgorithm(), "AES");
@@ -313,7 +313,7 @@ public class ConcatKDFTest extends XMLObjectBaseTestCase {
byte[] secret = Hex.decodeHex("DEADBEEF");
- SecretKey derivedKey = kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM);
+ SecretKey derivedKey = kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, null);
Assert.assertNotNull(derivedKey);
Assert.assertEquals(derivedKey.getAlgorithm(), "AES");
@@ -327,7 +327,7 @@ public class ConcatKDFTest extends XMLObjectBaseTestCase {
byte[] secret = Hex.decodeHex("DEADBEEF");
- kdf.derive(secret, "urn:test:InvalidKeyAlgorithm");
+ kdf.derive(secret, "urn:test:InvalidKeyAlgorithm", null);
}
@Test(expectedExceptions = KeyDerivationException.class)
@@ -338,7 +338,23 @@ public class ConcatKDFTest extends XMLObjectBaseTestCase {
byte[] secret = Hex.decodeHex("DEADBEEF");
// Just use this as a stand-in for something which is KeySpecifiedAlgorithm but not KeyLengthSpecifiedAlgorithm
- kdf.derive(secret, SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
+ kdf.derive(secret, SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, null);
+ }
+
+ @Test
+ public void nonKeyLengthAlgorithmWithSpecifiedLength() throws Exception {
+ ConcatKDF kdf = new ConcatKDF();
+ kdf.initialize();
+
+ byte[] secret = Hex.decodeHex("DEADBEEF");
+
+ // Just use this as a stand-in for something which is KeySpecifiedAlgorithm but not KeyLengthSpecifiedAlgorithm
+ SecretKey derivedKey = kdf.derive(secret, SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, 256);
+
+ // This is bogus obviously, but just need to test that a known algo URI that is non-key length works with specified key length
+ Assert.assertNotNull(derivedKey);
+ Assert.assertEquals(derivedKey.getAlgorithm(), "RSA");
+ Assert.assertEquals(derivedKey.getEncoded().length * 8, 256);
}
@Test
diff --git a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/MockKeyDerivation.java b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/MockKeyDerivation.java
index fb4acbd17..b17f90398 100644
--- a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/MockKeyDerivation.java
+++ b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/MockKeyDerivation.java
@@ -35,7 +35,7 @@ public class MockKeyDerivation implements KeyDerivation {
}
/** {@inheritDoc} */
- public SecretKey derive(byte[] secret, String keyAlgorithm) throws KeyDerivationException {
+ public SecretKey derive(byte[] secret, String keyAlgorithm, Integer keyLength) throws KeyDerivationException {
try {
String algo = AlgorithmSupport.getKeyAlgorithm(keyAlgorithm);
Integer length = AlgorithmSupport.getKeyLength(keyAlgorithm);
diff --git a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/PBKDF2Test.java b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/PBKDF2Test.java
index 70bdf4f33..aae1ef1d5 100644
--- a/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/PBKDF2Test.java
+++ b/opensaml-xmlsec-impl/src/test/java/org/opensaml/xmlsec/derivation/impl/PBKDF2Test.java
@@ -277,7 +277,7 @@ public class PBKDF2Test extends XMLObjectBaseTestCase {
byte[] secret = Hex.decodeHex("DEADBEEF");
- SecretKey derivedKey = kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM);
+ SecretKey derivedKey = kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, null);
Assert.assertNotNull(derivedKey);
Assert.assertEquals(derivedKey.getAlgorithm(), "AES");
@@ -303,7 +303,7 @@ public class PBKDF2Test extends XMLObjectBaseTestCase {
byte[] secret = Hex.decodeHex("DEADBEEF");
- SecretKey derivedKey = kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM);
+ SecretKey derivedKey = kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES256_GCM, null);
Assert.assertNotNull(derivedKey);
Assert.assertEquals(derivedKey.getAlgorithm(), "AES");
@@ -318,7 +318,7 @@ public class PBKDF2Test extends XMLObjectBaseTestCase {
byte[] secret = Hex.decodeHex("DEADBEEF");
- kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM);
+ kdf.derive(secret, EncryptionConstants.ALGO_ID_BLOCKCIPHER_AES128_GCM, null);
}
@Test(expectedExceptions = KeyDerivationException.class)
@@ -328,7 +328,7 @@ public class PBKDF2Test extends XMLObjectBaseTestCase {
byte[] secret = Hex.decodeHex("DEADBEEF");
- kdf.derive(secret, "urn:test:InvalidKeyAlgorithm");
+ kdf.derive(secret, "urn:test:InvalidKeyAlgorithm", null);
}
@Test(expectedExceptions = KeyDerivationException.class)
@@ -339,7 +339,23 @@ public class PBKDF2Test extends XMLObjectBaseTestCase {
byte[] secret = Hex.decodeHex("DEADBEEF");
// Just use this as a stand-in for something which is KeySpecifiedAlgorithm but not KeyLengthSpecifiedAlgorithm
- kdf.derive(secret, SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
+ kdf.derive(secret, SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, null);
+ }
+
+ @Test
+ public void nonKeyLengthAlgorithmWithSpecifiedLength() throws Exception {
+ PBKDF2 kdf = new PBKDF2();
+ kdf.initialize();
+
+ byte[] secret = Hex.decodeHex("DEADBEEF");
+
+ // Just use this as a stand-in for something which is KeySpecifiedAlgorithm but not KeyLengthSpecifiedAlgorithm
+ SecretKey derivedKey = kdf.derive(secret, SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, 256);
+
+ // This is bogus obviously, but just need to test that a known algo URI that is non-key length works with specified key length
+ Assert.assertNotNull(derivedKey);
+ Assert.assertEquals(derivedKey.getAlgorithm(), "RSA");
+ Assert.assertEquals(derivedKey.getEncoded().length * 8, 256);
}
@@ -529,7 +545,7 @@ public class PBKDF2Test extends XMLObjectBaseTestCase {
kdf.setSalt(salt);
kdf.initialize();
- SecretKey derivedKey = kdf.derive(secret, keyAlgorithm);
+ SecretKey derivedKey = kdf.derive(secret, keyAlgorithm, null);
Assert.assertNotNull(derivedKey);
Assert.assertEquals(derivedKey.getAlgorithm(), jcaKeyAlgorithm);
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list