You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2013/08/16 08:02:56 UTC
git commit: CAMEL-6640: Migrate XML Security key cipher algorithm
away from RSA v1.5. Thanks to Colm for the patch.
Updated Branches:
refs/heads/master 91622a51e -> 5d69e4658
CAMEL-6640: Migrate XML Security key cipher algorithm away from RSA v1.5. Thanks to Colm for the patch.
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/5d69e465
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/5d69e465
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/5d69e465
Branch: refs/heads/master
Commit: 5d69e4658e75370da2ad1ac08e7df94ffa51713c
Parents: 91622a5
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Aug 16 08:02:34 2013 +0200
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Aug 16 08:02:34 2013 +0200
----------------------------------------------------------------------
.../xmlsecurity/XMLSecurityDataFormat.java | 116 +++++++++++++++++--
.../xmlsecurity/XMLSecurityDataFormatTest.java | 83 +++++++++++++
2 files changed, 187 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/5d69e465/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java b/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
index 22437a6..dfc541c 100755
--- a/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
+++ b/components/camel-xmlsecurity/src/main/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormat.java
@@ -57,6 +57,8 @@ import org.apache.xml.security.encryption.EncryptedKey;
import org.apache.xml.security.encryption.XMLCipher;
import org.apache.xml.security.encryption.XMLEncryptionException;
import org.apache.xml.security.keys.KeyInfo;
+import org.apache.xml.security.utils.Constants;
+import org.apache.xml.security.utils.EncryptionConstants;
import org.apache.xml.security.utils.XMLUtils;
@@ -133,7 +135,6 @@ public class XMLSecurityDataFormat implements DataFormat, CamelContextAware {
private CamelContext camelContext;
private DefaultNamespaceContext nsContext = new DefaultNamespaceContext();
-
public XMLSecurityDataFormat() {
this.xmlCipherAlgorithm = XMLCipher.TRIPLEDES;
// set a default pass phrase as its required
@@ -465,7 +466,7 @@ public class XMLSecurityDataFormat implements DataFormat, CamelContextAware {
if (null != this.getKeyCipherAlgorithm()) {
keyCipher = XMLCipher.getInstance(this.getKeyCipherAlgorithm(), null, digestAlgorithm);
} else {
- keyCipher = XMLCipher.getInstance(XMLCipher.RSA_v1dot5, null, digestAlgorithm);
+ keyCipher = XMLCipher.getInstance(XMLCipher.RSA_OAEP, null, digestAlgorithm);
}
keyCipher.init(XMLCipher.WRAP_MODE, keyEncryptionKey);
encrypt(exchange, document, stream, dataEncryptionKey, keyCipher);
@@ -606,6 +607,7 @@ public class XMLSecurityDataFormat implements DataFormat, CamelContextAware {
xmlCipher.setKEK(keyEncryptionKey);
if (secureTag.equalsIgnoreCase("")) {
+ checkEncryptionAlgorithm(keyEncryptionKey, encodedDocument.getDocumentElement());
encodedDocument = xmlCipher.doFinal(encodedDocument, encodedDocument.getDocumentElement());
} else {
@@ -618,6 +620,7 @@ public class XMLSecurityDataFormat implements DataFormat, CamelContextAware {
Node node = nodeList.item(i);
encodedDocument = node.getOwnerDocument();
if (getSecureTagContents()) {
+ checkEncryptionAlgorithm(keyEncryptionKey, (Element)node);
Document temp = xmlCipher.doFinal(encodedDocument, (Element) node, true);
encodedDocument.importNode(temp.getDocumentElement().cloneNode(true), true);
} else {
@@ -625,6 +628,7 @@ public class XMLSecurityDataFormat implements DataFormat, CamelContextAware {
for (int j = 0; j < childNodes.getLength(); j++) {
Node childNode = childNodes.item(j);
if (childNode.getLocalName().equals("EncryptedData")) {
+ checkEncryptionAlgorithm(keyEncryptionKey, (Element) childNode);
Document temp = xmlCipher.doFinal(encodedDocument, (Element) childNode, false);
encodedDocument.importNode(temp.getDocumentElement().cloneNode(true), true);
}
@@ -676,16 +680,17 @@ public class XMLSecurityDataFormat implements DataFormat, CamelContextAware {
keyGenerator = KeyGenerator.getInstance("DESede");
} else {
keyGenerator = KeyGenerator.getInstance("AES");
- }
- if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_128)
- || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_128_GCM)) {
- keyGenerator.init(128);
- } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_192)
- || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_192_GCM)) {
- keyGenerator.init(192);
- } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_256)
- || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_256_GCM)) {
- keyGenerator.init(256);
+
+ if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_128)
+ || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_128_GCM)) {
+ keyGenerator.init(128);
+ } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_192)
+ || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_192_GCM)) {
+ keyGenerator.init(192);
+ } else if (xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_256)
+ || xmlCipherAlgorithm.equalsIgnoreCase(XMLCipher.AES_256_GCM)) {
+ keyGenerator.init(256);
+ }
}
return keyGenerator.generateKey();
}
@@ -727,6 +732,92 @@ public class XMLSecurityDataFormat implements DataFormat, CamelContextAware {
}
return alias;
}
+
+ // Check to see if the asymmetric key transport algorithm is allowed
+ private void checkEncryptionAlgorithm(Key keyEncryptionKey, Element parentElement) throws Exception {
+ if (XMLCipher.RSA_v1dot5.equals(keyCipherAlgorithm)
+ || keyCipherAlgorithm == null
+ || !(keyEncryptionKey instanceof PrivateKey)) {
+ // This only applies for Asymmetric Encryption
+ return;
+ }
+ Element encryptedElement = findEncryptedDataElement(parentElement);
+ if (encryptedElement == null) {
+ return;
+ }
+
+ // The EncryptedKey EncryptionMethod algorithm
+ String foundEncryptedKeyMethod = findEncryptedKeyMethod(encryptedElement);
+ if (XMLCipher.RSA_v1dot5.equals(foundEncryptedKeyMethod)) {
+ String errorMessage = "The found key transport encryption method is not allowed";
+ throw new XMLEncryptionException(errorMessage);
+ }
+ }
+
+ private Element findEncryptedDataElement(Element element) {
+ // First check the Element itself
+ if (EncryptionConstants._TAG_ENCRYPTEDDATA.equals(element.getLocalName())
+ && EncryptionConstants.EncryptionSpecNS.equals(element.getNamespaceURI())) {
+ return element;
+ }
+
+ // Now check the child nodes
+ Node child = element.getFirstChild();
+ while (child != null) {
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ Element childElement = (Element)child;
+ if (EncryptionConstants._TAG_ENCRYPTEDDATA.equals(childElement.getLocalName())
+ && EncryptionConstants.EncryptionSpecNS.equals(childElement.getNamespaceURI())) {
+ return childElement;
+ }
+ }
+ child = child.getNextSibling();
+ }
+
+ return null;
+ }
+
+ private String findEncryptionMethod(Element element) {
+ Node child = element.getFirstChild();
+ while (child != null) {
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ Element childElement = (Element)child;
+ if (EncryptionConstants._TAG_ENCRYPTIONMETHOD.equals(childElement.getLocalName())
+ && EncryptionConstants.EncryptionSpecNS.equals(childElement.getNamespaceURI())) {
+ return childElement.getAttributeNS(null, EncryptionConstants._ATT_ALGORITHM);
+ }
+ }
+ child = child.getNextSibling();
+ }
+
+ return null;
+ }
+
+ private String findEncryptedKeyMethod(Element element) {
+ Node child = element.getFirstChild();
+ while (child != null) {
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ Element childElement = (Element)child;
+ if (Constants._TAG_KEYINFO.equals(childElement.getLocalName())
+ && Constants.SignatureSpecNS.equals(childElement.getNamespaceURI())) {
+ Node keyInfoChild = child.getFirstChild();
+ while (keyInfoChild != null) {
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ childElement = (Element)keyInfoChild;
+ if (EncryptionConstants._TAG_ENCRYPTEDKEY.equals(childElement.getLocalName())
+ && EncryptionConstants.EncryptionSpecNS.equals(childElement.getNamespaceURI())) {
+ return findEncryptionMethod(childElement);
+ }
+ }
+ keyInfoChild = keyInfoChild.getNextSibling();
+ }
+ }
+ }
+ child = child.getNextSibling();
+ }
+
+ return null;
+ }
private DefaultNamespaceContext getNamespaceContext() {
return this.nsContext;
@@ -923,4 +1014,5 @@ public class XMLSecurityDataFormat implements DataFormat, CamelContextAware {
public void setMgfAlgorithm(String mgfAlgorithm) {
this.mgfAlgorithm = mgfAlgorithm;
}
+
}
http://git-wip-us.apache.org/repos/asf/camel/blob/5d69e465/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java
----------------------------------------------------------------------
diff --git a/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java b/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java
index 4e1c3cf..a1f0b83 100755
--- a/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java
+++ b/components/camel-xmlsecurity/src/test/java/org/apache/camel/dataformat/xmlsecurity/XMLSecurityDataFormatTest.java
@@ -372,4 +372,87 @@ public class XMLSecurityDataFormatTest extends CamelTestSupport {
xmlsecTestHelper.testDecryption(TestHelper.NS_XML_FRAGMENT, context);
}
+ @Test
+ public void testAsymmetricEncryptionAlgorithmFullPayload() throws Exception {
+
+ final KeyStoreParameters tsParameters = new KeyStoreParameters();
+ tsParameters.setPassword("password");
+ tsParameters.setResource("sender.ts");
+
+ final KeyStoreParameters ksParameters = new KeyStoreParameters();
+ ksParameters.setPassword("password");
+ ksParameters.setResource("recipient.ks");
+
+ // RSA v1.5 is not allowed unless explicitly configured
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .marshal().secureXML("", true, "recipient", testCypherAlgorithm, XMLCipher.RSA_v1dot5, tsParameters).to("mock:encrypted")
+ .unmarshal().secureXML("", true, "recipient", testCypherAlgorithm, XMLCipher.RSA_OAEP, ksParameters).to("mock:decrypted");
+ }
+ });
+
+ MockEndpoint resultEndpoint = context.getEndpoint("mock:decrypted", MockEndpoint.class);
+ resultEndpoint.setExpectedMessageCount(0);
+ // verify that the message was encrypted before checking that it is decrypted
+ xmlsecTestHelper.testEncryption(TestHelper.XML_FRAGMENT, context);
+
+ resultEndpoint.assertIsSatisfied(100);
+ }
+
+ @Test
+ public void testAsymmetricEncryptionAlgorithmPartialPayload() throws Exception {
+
+ final KeyStoreParameters tsParameters = new KeyStoreParameters();
+ tsParameters.setPassword("password");
+ tsParameters.setResource("sender.ts");
+
+ final KeyStoreParameters ksParameters = new KeyStoreParameters();
+ ksParameters.setPassword("password");
+ ksParameters.setResource("recipient.ks");
+
+ // RSA v1.5 is not allowed unless explicitly configured
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/italy", true, "recipient", testCypherAlgorithm, XMLCipher.RSA_v1dot5, tsParameters).to("mock:encrypted")
+ .unmarshal().secureXML("//cheesesites/italy", true, "recipient", testCypherAlgorithm, XMLCipher.RSA_OAEP, ksParameters).to("mock:decrypted");
+ }
+ });
+
+ MockEndpoint resultEndpoint = context.getEndpoint("mock:decrypted", MockEndpoint.class);
+ resultEndpoint.setExpectedMessageCount(0);
+ // verify that the message was encrypted before checking that it is decrypted
+ xmlsecTestHelper.testEncryption(TestHelper.XML_FRAGMENT, context);
+
+ resultEndpoint.assertIsSatisfied(100);
+ }
+
+ @Test
+ public void testAsymmetricEncryptionAlgorithmPartialPayloadElement() throws Exception {
+
+ final KeyStoreParameters tsParameters = new KeyStoreParameters();
+ tsParameters.setPassword("password");
+ tsParameters.setResource("sender.ts");
+
+ final KeyStoreParameters ksParameters = new KeyStoreParameters();
+ ksParameters.setPassword("password");
+ ksParameters.setResource("recipient.ks");
+
+ // RSA v1.5 is not allowed unless explicitly configured
+ context.addRoutes(new RouteBuilder() {
+ public void configure() {
+ from("direct:start")
+ .marshal().secureXML("//cheesesites/france/cheese", false, "recipient", testCypherAlgorithm, XMLCipher.RSA_v1dot5, tsParameters).to("mock:encrypted")
+ .unmarshal().secureXML("//cheesesites/france", false, "recipient", testCypherAlgorithm, XMLCipher.RSA_OAEP, ksParameters).to("mock:decrypted");
+ }
+ });
+
+ MockEndpoint resultEndpoint = context.getEndpoint("mock:decrypted", MockEndpoint.class);
+ resultEndpoint.setExpectedMessageCount(0);
+ // verify that the message was encrypted before checking that it is decrypted
+ xmlsecTestHelper.testEncryption(TestHelper.XML_FRAGMENT, context);
+
+ resultEndpoint.assertIsSatisfied(100);
+ }
}