Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for the ECDH KeyAgreement method algorithm #264

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
Expand Down Expand Up @@ -48,7 +49,7 @@
<wsdl4j.version>1.6.3</wsdl4j.version>
<woodstox.version>6.5.1</woodstox.version>
<xz.version>1.9</xz.version>
<xmlsec.version>4.0.1</xmlsec.version>
<xmlsec.version>4.0.2-SNAPSHOT</xmlsec.version>
<xmlunit.version>2.9.1</xmlunit.version>
<!-- OSGi related properties -->
<wss4j.osgi.import />
Expand Down Expand Up @@ -107,6 +108,11 @@
<artifactId>junit-jupiter-engine</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
Expand Down
3 changes: 2 additions & 1 deletion policy/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public int hashCode() {
}

protected void parseNestedSymmetricAsymmetricBindingBasePolicy(
Policy nestedPolicy, AbstractSymmetricAsymmetricBinding asymmetricBindingBase
Policy nestedPolicy, AbstractSymmetricAsymmetricBinding asymmetricBindingBase
) {
Iterator<List<Assertion>> alternatives = nestedPolicy.getAlternatives();
//we just process the first alternative
Expand Down
3 changes: 2 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
specific language governing permissions and limitations
under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>org.apache.wss4j</groupId>
Expand Down
5 changes: 5 additions & 0 deletions ws-security-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-reload4j</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,21 @@ protected ConfigurationConstants() {
*/
public static final String ENC_KEY_TRANSPORT = "encryptionKeyTransportAlgorithm";

/**
* Defines the Agreement method algorithm to derive encryption key.
* The default algorithm is:
* "http://www.w3.org/2009/xmlenc11#ECDH-ES"
*
* <p/>
* The application may set this parameter using the following method:
* <pre>
* call.setProperty(ConfigurationConstants.ENC_KEY_AGREEMENT_METHOD,
* WSConstants.AGREEMENT_METHOD_ECDH_ES);
* </pre>
*
*/
public static final String ENC_KEY_AGREEMENT_METHOD = "encryptionKeyAgreementMethod";

/**
* Parameter to define which parts of the request shall be encrypted.
* <p/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class EncryptionActionToken extends SignatureEncryptionActionToken {
private boolean encSymmetricEncryptionKey = true;
private String mgfAlgorithm;
private String symmetricAlgorithm;
private String keyAgreementMethodAlgorithm;
private String keyTransportAlgorithm;
private boolean getSymmetricKeyFromCallbackHandler;

Expand Down Expand Up @@ -54,6 +55,12 @@ public String getKeyTransportAlgorithm() {
public void setKeyTransportAlgorithm(String keyTransportAlgorithm) {
this.keyTransportAlgorithm = keyTransportAlgorithm;
}
public String getKeyAgreementMethodAlgorithm() {
return keyAgreementMethodAlgorithm;
}
public void setKeyAgreementMethodAlgorithm(String keyAgreementMethodAlgorithm) {
this.keyAgreementMethodAlgorithm = keyAgreementMethodAlgorithm;
}
public boolean isGetSymmetricKeyFromCallbackHandler() {
return getSymmetricKeyFromCallbackHandler;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,18 @@ protected WSS4JConstants() {
"http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p";
public static final String KEYTRANSPORT_RSAOAEP_XENC11 =
"http://www.w3.org/2009/xmlenc11#rsa-oaep";
public static final String KEYWRAP_AES128 =
"http://www.w3.org/2001/04/xmlenc#kw-aes128";
public static final String KEYWRAP_AES192 =
"http://www.w3.org/2001/04/xmlenc#kw-aes192";
public static final String KEYWRAP_AES256 =
"http://www.w3.org/2001/04/xmlenc#kw-aes256";
public static final String KEYWRAP_TRIPLEDES =
"http://www.w3.org/2001/04/xmlenc#kw-tripledes";
public static final String KDF_CONCAT =
"http://www.w3.org/2009/xmlenc11#ConcatKDF";
public static final String AGREEMENT_METHOD_ECDH_ES =
"http://www.w3.org/2009/xmlenc11#ECDH-ES";
public static final String TRIPLE_DES =
"http://www.w3.org/2001/04/xmlenc#tripledes-cbc";
public static final String AES_128 =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class AlgorithmSuite {

private Set<String> encryptionMethods = Collections.emptySet();
private Set<String> keyWrapAlgorithms = Collections.emptySet();

private Set<String> keyAgreementAlgorithms = Collections.emptySet();
private Set<String> derivedKeyAlgorithms = Collections.emptySet();

private int maximumSymmetricKeyLength = 256;
Expand Down Expand Up @@ -116,6 +116,17 @@ public Set<String> getKeyWrapAlgorithms() {
return keyWrapAlgorithms;
}

public void addKeyAgreementMethodAlgorithm(String keyAgreementAlgorithm) {
if (keyAgreementAlgorithms.isEmpty()) {
keyAgreementAlgorithms = new HashSet<>();
}
keyAgreementAlgorithms.add(keyAgreementAlgorithm);
}

public Set<String> getKeyAgreementMethodAlgorithms() {
return keyAgreementAlgorithms;
}

public void addDerivedKeyAlgorithm(String derivedKeyAlgorithm) {
if (derivedKeyAlgorithms.isEmpty()) {
derivedKeyAlgorithms = new HashSet<>();
Expand Down Expand Up @@ -191,4 +202,4 @@ public void setMinimumEllipticCurveKeyLength(int minimumEllipticCurveKeyLength)
this.minimumEllipticCurveKeyLength = minimumEllipticCurveKeyLength;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@

import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.*;
import java.util.Set;

import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;

import org.apache.wss4j.common.ext.WSSecurityException;
import org.apache.xml.security.exceptions.DERDecodingException;
import org.apache.xml.security.utils.DERDecoderUtils;
import org.apache.xml.security.utils.KeyUtils;

/**
* Validate signature/encryption/etc. algorithms against an AlgorithmSuite policy.
Expand Down Expand Up @@ -138,6 +139,19 @@ public void checkEncryptionKeyWrapAlgorithm(
}
}

public void checkKeyAgreementMethodAlgorithm(
String keyAgreementMethodAlgorithm
) throws WSSecurityException {
Set<String> keyAgreementMethodAlgorithms = algorithmSuite.getKeyAgreementMethodAlgorithms();
if (!keyAgreementMethodAlgorithms.isEmpty()
&& !keyAgreementMethodAlgorithms.contains(keyAgreementMethodAlgorithm)) {
LOG.warn(
"The Key agreement method does not match the requirement"
);
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
}
}

public void checkSymmetricEncryptionAlgorithm(
String symmetricAlgorithm
) throws WSSecurityException {
Expand Down Expand Up @@ -216,11 +230,50 @@ public void checkAsymmetricKeyLength(
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
}
} else {
LOG.warn(
"An unknown public key was provided"
);
// Try with last supported key types EdEC and XDH
int keySize = getEdECndXDHKeyLength(publicKey);
if (keySize < algorithmSuite.getMinimumEllipticCurveKeyLength()
|| keySize > algorithmSuite.getMaximumEllipticCurveKeyLength()) {
LOG.warn(
"The asymmetric key length does not match the requirement"
);
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
}
}
}

/**
* A generic method to determinate key length for keys x25519, x448, ed25519 and ed448 keys. Method does not rely on
* any specific implementation of the key, but uses OID to determine the key type.
*
* @param publicKey the public key to check the key length
* @return the key length in bits
* @throws WSSecurityException if the key is not EdEC or XDH or if length can not be determined
*/
private int getEdECndXDHKeyLength(PublicKey publicKey) throws WSSecurityException {
String keyAlgorithmOId;
try {
keyAlgorithmOId = DERDecoderUtils.getAlgorithmIdFromPublicKey(publicKey);
} catch (DERDecodingException e) {
LOG.warn("Can not parse the public key to determine key size!", e);
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
}
KeyUtils.KeyType keyType = KeyUtils.KeyType.getByOid(keyAlgorithmOId);
if (keyType == null) {
LOG.warn("An unknown public key was provided");
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
}

return switch (keyType) {
case ED25519, X25519 -> 256;
case ED448, X448 -> 456;
default -> {
LOG.warn(
"An unknown public key was provided"
);
throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
}
};
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@ private String getIdentifier(X509Certificate cert, KeyStore store)

Certificate[] certs = store.getCertificateChain(alias);
if (certs == null || certs.length == 0) {
// no cert chain, so lets check if getCertificate gives us a result.
// no cert chain, so lets check if getCertificate gives us a result.
Certificate retrievedCert = store.getCertificate(alias);
if (retrievedCert != null) {
certs = new Certificate[]{retrievedCert};
Expand All @@ -1479,7 +1479,7 @@ private String getIdentifier(PublicKey publicKey, KeyStore store)

Certificate[] certs = store.getCertificateChain(alias);
if (certs == null || certs.length == 0) {
// no cert chain, so lets check if getCertificate gives us a result.
// no cert chain, so lets check if getCertificate gives us a result.
Certificate retrievedCert = store.getCertificate(alias);
if (retrievedCert != null) {
certs = new Certificate[]{retrievedCert};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public static synchronized void cleanUp() {
* Set the value of the internal addJceProviders flag. This flag
* turns on (or off) automatic registration of known JCE providers
* that provide necessary cryptographic algorithms for use with WSS4J.
* By default, this flag is true. You may wish (or need) to initialize
* By default, this flag is true. You may wish (or need) to initialize
* the JCE manually, e.g., in some JVMs.
*/
public static void setAddJceProviders(boolean value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public static XMLObject fromDom(Element root) throws WSSecurityException {
* Convert a SAML Assertion from a XMLObject to a DOM Element
*
* @param xmlObject of type XMLObject
* @param doc of type Document
* @param doc of type Document
* @return Element
* @throws WSSecurityException
*/
Expand All @@ -181,7 +181,7 @@ public static Element toDom(
* Convert a SAML Assertion from a XMLObject to a DOM Element
*
* @param xmlObject of type XMLObject
* @param doc of type Document
* @param doc of type Document
* @param signObject whether to sign the XMLObject during marshalling
* @return Element
* @throws WSSecurityException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public SamlAssertionWrapper(Element element) throws WSSecurityException {

/**
* Constructor SamlAssertionWrapper creates a new SamlAssertionWrapper instance.
* This is the primary constructor. All other constructor calls should
* This is the primary constructor. All other constructor calls should
* be routed to this method to ensure that the wrapper is initialized
* correctly.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
/*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
Expand Down Expand Up @@ -56,7 +56,7 @@ public final class InetAddressUtils {
+ "(([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})?)$"); // 0-6 hex fields

/*
* The above pattern is not totally rigorous as it allows for more than 7 hex fields in total
* The above pattern is not totally rigorous as it allows for more than 7 hex fields in total
*/
private static final char COLON_CHAR = ':';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@

/**
* The abstraction this class provides is a push down stack of variable
* length frames of prefix to namespace mappings. Used for keeping track
* length frames of prefix to namespace mappings. Used for keeping track
* of what namespaces are active at any given point as an XML document is
* traversed or produced.
* <p/>
* From a performance point of view, this data will both be modified frequently
* (at a minimum, there will be one push and pop per XML element processed),
* and scanned frequently (many of the "good" mappings will be at the bottom
* of the stack). The one saving grace is that the expected maximum
* of the stack). The one saving grace is that the expected maximum
* cardinalities of the number of frames and the number of total mappings
* is only in the dozens, representing the nesting depth of an XML document
* and the number of active namespaces at any point in the processing.
Expand Down Expand Up @@ -113,8 +113,8 @@ private void clearFrame() {

/**
* Reset the embedded iterator in this class to the top of the current
* (i.e., last) frame. Note that this is not threadsafe, nor does it
* provide multiple iterators, so don't use this recursively. Nor
* (i.e., last) frame. Note that this is not threadsafe, nor does it
* provide multiple iterators, so don't use this recursively. Nor
* should you modify the stack while iterating over it.
*/
public Mapping topOfFrame() {
Expand All @@ -139,7 +139,7 @@ public Mapping next() {

/**
* Add a mapping for a namespaceURI to the specified prefix to the top
* frame in the stack. If the prefix is already mapped in that frame,
* frame in the stack. If the prefix is already mapped in that frame,
* remap it to the (possibly different) namespaceURI.
*/
public void add(String namespaceURI, String prefix) {
Expand All @@ -166,10 +166,10 @@ public void add(String namespaceURI, String prefix) {
}

/**
* Return an active prefix for the given namespaceURI. NOTE : This
* Return an active prefix for the given namespaceURI. NOTE : This
* may return null even if the namespaceURI was actually mapped further
* up the stack IF the prefix which was used has been repeated further
* down the stack. I.e.:
* down the stack. I.e.:
* <p/>
* <pre:outer xmlns:pre="namespace">
* <pre:inner xmlns:pre="otherNamespace">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ private XMLUtils() {
* Gets a direct child with specified localname and namespace. <p/>
*
* @param parentNode the node where to start the search
* @param localName local name of the child to get
* @param namespace the namespace of the child to get
* @param localName local name of the child to get
* @param namespace the namespace of the child to get
* @return the node or <code>null</code> if not such node found
*/
public static Element getDirectChildElement(Node parentNode, String localName, String namespace) {
Expand Down
Loading