This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch 2_2_x-fixes in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git
The following commit(s) were added to refs/heads/2_2_x-fixes by this push: new e970b48 Extend automatic signature algorithm detection with support for EC keys (WSS-663) (#4) e970b48 is described below commit e970b486dbf35405a3327c3ec2fbaebf3cf0f790 Author: Thomas Papke <w...@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 aca953a..29e7370 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.debug( "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 6d4e74e..efa4212 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 @@ -895,6 +895,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 a5231f8..10bb34b 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 @@ -176,5 +176,43 @@ public class SignatureKeyValueTest extends org.junit.Assert { ((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); + } } 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 3156406..75f54cb 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; @@ -191,6 +192,52 @@ public class SamlAlgorithmSuiteTest extends org.junit.Assert { 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);