You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by co...@apache.org on 2020/02/12 11:29:26 UTC

[ws-wss4j] branch master updated: Extend automatic signature algorithm detection with support for EC keys (WSS-663) (#4)

This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git


The following commit(s) were added to refs/heads/master by this push:
     new 03b5ff5  Extend automatic signature algorithm detection with support for EC keys (WSS-663) (#4)
03b5ff5 is described below

commit 03b5ff5504c08240766aa5d1f281f4c2b7f98a50
Author: Thomas Papke <we...@thopap.de>
AuthorDate: Wed Feb 12 12:29:07 2020 +0100

    Extend automatic signature algorithm detection with support for EC keys (WSS-663) (#4)
    
    * Extend automatic signature algorithm detection with support for EC keys
    
    * WSS-663 Missing ECC key support
    * Adapt alogrithmSuiteValidator with support for EC keys
    
    * #4 Extend automatic signature algorithm detection with support for EC
    keys (WSS-663)
    * Apply review feedback regarding validity of the test key
    * Adding better default key length validation defaults for EC keys
---
 .../org/apache/wss4j/common/WSS4JConstants.java    |   8 ++++
 .../apache/wss4j/common/crypto/AlgorithmSuite.java |  18 ++++++++
 .../common/crypto/AlgorithmSuiteValidator.java     |  10 +++++
 .../src/test/resources/keys/wss40.jks              | Bin 7420 -> 8131 bytes
 .../apache/wss4j/dom/message/WSSecSignature.java   |   2 +
 .../wss4j/dom/message/SignatureKeyValueTest.java   |  38 +++++++++++++++++
 .../wss4j/dom/saml/SamlAlgorithmSuiteTest.java     |  47 +++++++++++++++++++++
 7 files changed, 123 insertions(+)

diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/WSS4JConstants.java b/ws-security-common/src/main/java/org/apache/wss4j/common/WSS4JConstants.java
index 82b7ac1..d3768b2 100644
--- a/ws-security-common/src/main/java/org/apache/wss4j/common/WSS4JConstants.java
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/WSS4JConstants.java
@@ -148,6 +148,14 @@ public class WSS4JConstants {
         "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512";
     public static final String HMAC_MD5 =
         "http://www.w3.org/2001/04/xmldsig-more#hmac-md5";
+    public static final String ECDSA_SHA1 =
+            "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1";
+    public static final String ECDSA_SHA384 =
+            "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384";
+    public static final String ECDSA_SHA256 =
+            "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256";
+    public static final String ECDSA_SHA512 =
+            "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512";
 
     public static final String MGF_SHA1 = "http://www.w3.org/2009/xmlenc11#mgf1sha1";
     public static final String MGF_SHA224 = "http://www.w3.org/2009/xmlenc11#mgf1sha224";
diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/AlgorithmSuite.java b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/AlgorithmSuite.java
index 75039e1..b854eed 100644
--- a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/AlgorithmSuite.java
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/AlgorithmSuite.java
@@ -44,6 +44,8 @@ public class AlgorithmSuite {
     private int minimumSymmetricKeyLength = 128;
     private int maximumAsymmetricKeyLength = 4096;
     private int minimumAsymmetricKeyLength = 1024;
+    private int maximumEllipticCurveKeyLength = 512;
+    private int minimumEllipticCurveKeyLength = 160;
 
     private int signatureDerivedKeyLength;
     private int encryptionDerivedKeyLength;
@@ -173,4 +175,20 @@ public class AlgorithmSuite {
         this.minimumSymmetricKeyLength = minimumSymmetricKeyLength;
     }
 
+    public int getMaximumEllipticCurveKeyLength() {
+        return maximumEllipticCurveKeyLength;
+    }
+
+    public void setMaximumEllipticCurveKeyLength(int maximumEllipticCurveKeyLength) {
+        this.maximumEllipticCurveKeyLength = maximumEllipticCurveKeyLength;
+    }
+
+    public int getMinimumEllipticCurveKeyLength() {
+        return minimumEllipticCurveKeyLength;
+    }
+
+    public void setMinimumEllipticCurveKeyLength(int minimumEllipticCurveKeyLength) {
+        this.minimumEllipticCurveKeyLength = minimumEllipticCurveKeyLength;
+    }
+
 }
\ No newline at end of file
diff --git a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/AlgorithmSuiteValidator.java b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/AlgorithmSuiteValidator.java
index 7b4ae29..714101f 100644
--- a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/AlgorithmSuiteValidator.java
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/AlgorithmSuiteValidator.java
@@ -22,6 +22,7 @@ package org.apache.wss4j.common.crypto;
 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.util.Set;
 
@@ -205,6 +206,15 @@ public class AlgorithmSuiteValidator {
                 );
                 throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
             }
+        } else if (publicKey instanceof ECPublicKey) {
+            final ECPublicKey ecpriv = (ECPublicKey) publicKey;
+            final java.security.spec.ECParameterSpec spec = ecpriv.getParams();
+            int length = spec.getOrder().bitLength();
+            if (length < algorithmSuite.getMinimumEllipticCurveKeyLength()
+                    || length > algorithmSuite.getMaximumEllipticCurveKeyLength()) {
+                LOG.warn("The elliptic curve key length does not match the requirement");
+                throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY);
+            }
         } else {
             LOG.warn(
                 "An unknown public key was provided"
diff --git a/ws-security-common/src/test/resources/keys/wss40.jks b/ws-security-common/src/test/resources/keys/wss40.jks
index 3cb01db..73ead31 100644
Binary files a/ws-security-common/src/test/resources/keys/wss40.jks and b/ws-security-common/src/test/resources/keys/wss40.jks differ
diff --git a/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecSignature.java b/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecSignature.java
index 9634ac8..60c1f25 100644
--- a/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecSignature.java
+++ b/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecSignature.java
@@ -905,6 +905,8 @@ public class WSSecSignature extends WSSecSignatureBase {
                     sigAlgo = WSConstants.DSA;
                 } else if (pubKeyAlgo.equalsIgnoreCase("RSA")) {
                     sigAlgo = WSConstants.RSA;
+                } else if (pubKeyAlgo.equalsIgnoreCase("EC")) {
+                    sigAlgo = WSConstants.ECDSA_SHA256;
                 } else {
                     throw new WSSecurityException(
                         WSSecurityException.ErrorCode.FAILURE,
diff --git a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureKeyValueTest.java b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureKeyValueTest.java
index 39d9aaa..d91fc10 100644
--- a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureKeyValueTest.java
+++ b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureKeyValueTest.java
@@ -181,5 +181,43 @@ public class SignatureKeyValueTest {
             ((PublicKeyPrincipal)principal).getPublicKey();
         assertTrue(publicKey instanceof java.security.interfaces.DSAPublicKey);
     }
+    
+    /**
+     * Successful ECKeyValue test.
+     */
+    @Test
+    public void testECKeyValue() throws Exception {
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader(doc);
+        secHeader.insertSecurityHeader();
+
+        WSSecSignature builder = new WSSecSignature(secHeader);
+        builder.setUserInfo("wss40ec", "security");
+        builder.setKeyIdentifierType(WSConstants.KEY_VALUE);
+        Document signedDoc = builder.build(crypto);
+
+        String outputString =
+            XMLUtils.prettyDocumentToString(signedDoc);
+        LOG.debug(outputString);
+        assertTrue(outputString.contains("ECKeyValue"));
+
+        WSSecurityEngine secEngine = new WSSecurityEngine();
+        RequestData data = new RequestData();
+        data.setSigVerCrypto(crypto);
+        data.setIgnoredBSPRules(Collections.singletonList(BSPRule.R5417));
+        final WSHandlerResult results =
+            secEngine.processSecurityHeader(signedDoc, data);
+
+        WSSecurityEngineResult actionResult =
+            results.getActionResults().get(WSConstants.SIGN).get(0);
+        assertNotNull(actionResult);
+
+        java.security.Principal principal =
+            (java.security.Principal)actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
+        assertTrue(principal instanceof PublicKeyPrincipal);
+        java.security.PublicKey publicKey =
+            ((PublicKeyPrincipal)principal).getPublicKey();
+        assertTrue(publicKey instanceof java.security.interfaces.ECPublicKey);
+    }
 
 }
\ No newline at end of file
diff --git a/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SamlAlgorithmSuiteTest.java b/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SamlAlgorithmSuiteTest.java
index df23033..0efdc08 100644
--- a/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SamlAlgorithmSuiteTest.java
+++ b/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SamlAlgorithmSuiteTest.java
@@ -19,6 +19,7 @@
 
 package org.apache.wss4j.dom.saml;
 
+import javax.xml.crypto.dsig.CanonicalizationMethod;
 import org.apache.wss4j.common.saml.SamlAssertionWrapper;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -195,6 +196,52 @@ public class SamlAlgorithmSuiteTest {
         verify(securityHeader, algorithmSuite, crypto);
     }
 
+    @Test
+    public void signWithEcdsaAlgorithm() throws Exception {
+        crypto = CryptoFactory.getInstance("wss40.properties");
+        SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
+        callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
+        callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
+        callbackHandler.setIssuer("www.example.com");
+
+        SAMLCallback samlCallback = new SAMLCallback();
+        SAMLUtil.doSAMLCallback(callbackHandler, samlCallback);
+        SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback);
+
+        samlAssertion.signAssertion(
+            "wss40ec", "security", crypto, false,
+            CanonicalizationMethod.EXCLUSIVE, WSConstants.ECDSA_SHA256);
+
+
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader(doc);
+        secHeader.insertSecurityHeader();
+
+        WSSecSAMLToken wsSign = new WSSecSAMLToken(secHeader);
+
+        Document signedDoc = wsSign.build(samlAssertion);
+
+        if (LOG.isDebugEnabled()) {
+            String outputString =
+                XMLUtils.prettyDocumentToString(signedDoc);
+            LOG.debug(outputString);
+        }
+
+        Element securityHeader = WSSecurityUtil.getSecurityHeader(signedDoc, null);
+        AlgorithmSuite algorithmSuite = createAlgorithmSuite();
+
+        try {
+            verify(securityHeader, algorithmSuite, crypto);
+            fail("Expected failure as C14n algorithm is not allowed");
+        } catch (WSSecurityException ex) {
+            assertTrue(ex.getErrorCode() == WSSecurityException.ErrorCode.INVALID_SECURITY);
+        }
+
+        algorithmSuite.addSignatureMethod(WSConstants.ECDSA_SHA1);
+
+        verify(securityHeader, algorithmSuite, crypto);
+    }
+
     private AlgorithmSuite createAlgorithmSuite() {
         AlgorithmSuite algorithmSuite = new AlgorithmSuite();
         algorithmSuite.addSignatureMethod(WSConstants.RSA_SHA1);