You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@santuario.apache.org by co...@apache.org on 2012/01/12 16:14:39 UTC
svn commit: r1230583 - in /santuario/xml-security-java/trunk: ./
src/main/java/org/apache/xml/security/encryption/
src/main/java/org/apache/xml/security/utils/
src/test/java/org/apache/xml/security/test/encryption/
Author: coheigea
Date: Thu Jan 12 15:14:39 2012
New Revision: 1230583
URL: http://svn.apache.org/viewvc?rev=1230583&view=rev
Log:
[SANTUARIO-293,SANTUARIO-282] - Support XML Encryption 1.1 Key Wrapping test-cases
- All of the Key Wrapping XML Encryption 1.1 test cases are now fully working
Modified:
santuario/xml-security-java/trunk/CHANGELOG.txt
santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java
santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/ElementProxy.java
santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java
santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLEncryption11Test.java
Modified: santuario/xml-security-java/trunk/CHANGELOG.txt
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/CHANGELOG.txt?rev=1230583&r1=1230582&r2=1230583&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/CHANGELOG.txt (original)
+++ santuario/xml-security-java/trunk/CHANGELOG.txt Thu Jan 12 15:14:39 2012
@@ -1,6 +1,7 @@
Changelog for "Apache xml-security" <http://santuario.apache.org/>
New in v1.5.0-SNAPSHOT
+ Fixed SANTUARIO-282: RSA-OAEP key transport is limited to SHA-1 digests.
Fixed SANTUARIO-293: Support XML Encryption 1.1 Key Wrapping test-cases.
Fixed SANTUARIO-292: Add the ability to access the dereferenced Elements after signature validation in the non-JSR-105 API.
Fixed SANTUARIO-290: Add a secure validation switch for signature processing
Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java?rev=1230583&r1=1230582&r2=1230583&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/encryption/XMLCipher.java Thu Jan 12 15:14:39 2012
@@ -242,6 +242,8 @@ public class XMLCipher {
private boolean secureValidation;
+ private String digestAlg;
+
/**
* Set the Serializer algorithm to use
*/
@@ -260,21 +262,22 @@ public class XMLCipher {
/**
* Creates a new <code>XMLCipher</code>.
*
- * @param transformation the name of the transformation, e.g.,
- * <code>XMLCipher.TRIPLEDES</code> which is
- * shorthand for
- * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
- * if null the XMLCipher can only be used for decrypt or
- * unwrap operations where the encryption method is
- * defined in the <code>EncryptionMethod</code> element.
+ * @param transformation the name of the transformation, e.g.,
+ * <code>XMLCipher.TRIPLEDES</code>. If null the XMLCipher can only
+ * be used for decrypt or unwrap operations where the encryption method
+ * is defined in the <code>EncryptionMethod</code> element.
* @param provider the JCE provider that supplies the transformation,
* if null use the default provider.
* @param canon the name of the c14n algorithm, if
- * <code>null</code> use standard serializer
- * @since 1.0.
+ * <code>null</code> use standard serializer
+ * @param digestMethod An optional digestMethod to use.
*/
- private XMLCipher(String transformation, String provider, String canon)
- throws XMLEncryptionException {
+ private XMLCipher(
+ String transformation,
+ String provider,
+ String canon,
+ String digestMethod
+ ) throws XMLEncryptionException {
if (log.isDebugEnabled()) {
log.debug("Constructing XMLCipher...");
}
@@ -283,6 +286,7 @@ public class XMLCipher {
algorithm = transformation;
requestedJCEProvider = provider;
+ digestAlg = digestMethod;
// Create a canonicalizer - used when serializing DOM to octets
// prior to encryption (and for the reverse)
@@ -303,27 +307,7 @@ public class XMLCipher {
serializer.setCanonicalizer(this.canon);
if (transformation != null) {
- try {
- String jceAlgorithm = JCEMapper.translateURItoJCEID(transformation);
- if (log.isDebugEnabled()) {
- log.debug("cipher.algorithm = " + jceAlgorithm);
- }
-
- if (provider == null) {
- contextCipher = Cipher.getInstance(jceAlgorithm);
- } else {
- if (log.isDebugEnabled()) {
- log.debug("provider.name = " + provider);
- }
- contextCipher = Cipher.getInstance(jceAlgorithm, provider);
- }
- } catch (NoSuchAlgorithmException nsae) {
- throw new XMLEncryptionException("empty", nsae);
- } catch (NoSuchProviderException nspre) {
- throw new XMLEncryptionException("empty", nspre);
- } catch (NoSuchPaddingException nspe) {
- throw new XMLEncryptionException("empty", nspe);
- }
+ contextCipher = constructCipher(transformation, digestMethod);
}
}
@@ -402,7 +386,7 @@ public class XMLCipher {
log.debug("Getting XMLCipher with transformation");
}
validateTransformation(transformation);
- return new XMLCipher(transformation, null, null);
+ return new XMLCipher(transformation, null, null, null);
}
/**
@@ -412,12 +396,9 @@ public class XMLCipher {
* encrypts the document.
* <p>
*
- * @param transformation the name of the transformation, e.g.,
- * <code>XMLCipher.TRIPLEDES</code> which is
- * shorthand for
- * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
- * @param canon the name of the c14n algorithm, if
- * <code>null</code> use standard serializer
+ * @param transformation the name of the transformation
+ * @param canon the name of the c14n algorithm, if <code>null</code> use
+ * standard serializer
* @return the XMLCipher
* @throws XMLEncryptionException
*/
@@ -427,16 +408,37 @@ public class XMLCipher {
log.debug("Getting XMLCipher with transformation and c14n algorithm");
}
validateTransformation(transformation);
- return new XMLCipher(transformation, null, canon);
+ return new XMLCipher(transformation, null, canon, null);
+ }
+
+ /**
+ * Returns an <code>XMLCipher</code> that implements the specified
+ * transformation, operates on the specified context document and serializes
+ * the document with the specified canonicalization algorithm before it
+ * encrypts the document.
+ * <p>
+ *
+ * @param transformation the name of the transformation
+ * @param canon the name of the c14n algorithm, if <code>null</code> use
+ * standard serializer
+ * @param digestMethod An optional digestMethod to use
+ * @return the XMLCipher
+ * @throws XMLEncryptionException
+ */
+ public static XMLCipher getInstance(String transformation, String canon, String digestMethod)
+ throws XMLEncryptionException {
+ if (log.isDebugEnabled()) {
+ log.debug("Getting XMLCipher with transformation and c14n algorithm");
+ }
+ validateTransformation(transformation);
+ return new XMLCipher(transformation, null, canon, digestMethod);
}
/**
* Returns an <code>XMLCipher</code> that implements the specified
* transformation and operates on the specified context document.
*
- * @param transformation the name of the transformation, e.g.,
- * <code>XMLCipher.TRIPLEDES</code> which is shorthand for
- * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
+ * @param transformation the name of the transformation
* @param provider the JCE provider that supplies the transformation
* @return the XMLCipher
* @throws XMLEncryptionException
@@ -450,7 +452,7 @@ public class XMLCipher {
throw new NullPointerException("Provider unexpectedly null..");
}
validateTransformation(transformation);
- return new XMLCipher(transformation, provider, null);
+ return new XMLCipher(transformation, provider, null, null);
}
/**
@@ -460,13 +462,10 @@ public class XMLCipher {
* encrypts the document.
* <p>
*
- * @param transformation the name of the transformation, e.g.,
- * <code>XMLCipher.TRIPLEDES</code> which is
- * shorthand for
- * "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"
+ * @param transformation the name of the transformation
* @param provider the JCE provider that supplies the transformation
- * @param canon the name of the c14n algorithm, if
- * <code>null</code> use standard serializer
+ * @param canon the name of the c14n algorithm, if <code>null</code> use standard
+ * serializer
* @return the XMLCipher
* @throws XMLEncryptionException
*/
@@ -480,7 +479,35 @@ public class XMLCipher {
throw new NullPointerException("Provider unexpectedly null..");
}
validateTransformation(transformation);
- return new XMLCipher(transformation, provider, canon);
+ return new XMLCipher(transformation, provider, canon, null);
+ }
+
+ /**
+ * Returns an <code>XMLCipher</code> that implements the specified
+ * transformation, operates on the specified context document and serializes
+ * the document with the specified canonicalization algorithm before it
+ * encrypts the document.
+ * <p>
+ *
+ * @param transformation the name of the transformation
+ * @param provider the JCE provider that supplies the transformation
+ * @param canon the name of the c14n algorithm, if <code>null</code> use standard
+ * serializer
+ * @param digestMethod An optional digestMethod to use
+ * @return the XMLCipher
+ * @throws XMLEncryptionException
+ */
+ public static XMLCipher getProviderInstance(
+ String transformation, String provider, String canon, String digestMethod
+ ) throws XMLEncryptionException {
+ if (log.isDebugEnabled()) {
+ log.debug("Getting XMLCipher with transformation, provider and c14n algorithm");
+ }
+ if (null == provider) {
+ throw new NullPointerException("Provider unexpectedly null..");
+ }
+ validateTransformation(transformation);
+ return new XMLCipher(transformation, provider, canon, digestMethod);
}
/**
@@ -496,7 +523,7 @@ public class XMLCipher {
if (log.isDebugEnabled()) {
log.debug("Getting XMLCipher with no arguments");
}
- return new XMLCipher(null, null, null);
+ return new XMLCipher(null, null, null, null);
}
/**
@@ -516,7 +543,7 @@ public class XMLCipher {
if (log.isDebugEnabled()) {
log.debug("Getting XMLCipher with provider");
}
- return new XMLCipher(null, provider, null);
+ return new XMLCipher(null, provider, null, null);
}
/**
@@ -1035,24 +1062,7 @@ public class XMLCipher {
// Now create the working cipher if none was created already
Cipher c;
if (contextCipher == null) {
- String jceAlgorithm = JCEMapper.translateURItoJCEID(algorithm);
- if (log.isDebugEnabled()) {
- log.debug("alg = " + jceAlgorithm);
- }
-
- try {
- if (requestedJCEProvider == null) {
- c = Cipher.getInstance(jceAlgorithm);
- } else {
- c = Cipher.getInstance(jceAlgorithm, requestedJCEProvider);
- }
- } catch (NoSuchAlgorithmException nsae) {
- throw new XMLEncryptionException("empty", nsae);
- } catch (NoSuchProviderException nspre) {
- throw new XMLEncryptionException("empty", nspre);
- } catch (NoSuchPaddingException nspae) {
- throw new XMLEncryptionException("empty", nspae);
- }
+ c = constructCipher(algorithm, null);
} else {
c = contextCipher;
}
@@ -1134,6 +1144,7 @@ public class XMLCipher {
}
EncryptionMethod method =
factory.newEncryptionMethod(new URI(algorithm).toString());
+ method.setDigestAlgorithm(digestAlg);
ed.setEncryptionMethod(method);
} catch (URISyntaxException ex) {
throw new XMLEncryptionException("empty", ex);
@@ -1218,7 +1229,7 @@ public class XMLCipher {
public EncryptedKey loadEncryptedKey(Element element) throws XMLEncryptionException {
return loadEncryptedKey(element.getOwnerDocument(), element);
}
-
+
/**
* Encrypts a key to an EncryptedKey structure
*
@@ -1229,6 +1240,26 @@ public class XMLCipher {
* @throws XMLEncryptionException
*/
public EncryptedKey encryptKey(Document doc, Key key) throws XMLEncryptionException {
+ return encryptKey(doc, key, null, null);
+ }
+
+ /**
+ * Encrypts a key to an EncryptedKey structure
+ *
+ * @param doc the Context document that will be used to general DOM
+ * @param key Key to encrypt (will use previously set KEK to
+ * perform encryption
+ * @param mgfAlgorithm The xenc11 MGF Algorithm to use
+ * @param oaepParams The OAEPParams to use
+ * @return the <code>EncryptedKey</code>
+ * @throws XMLEncryptionException
+ */
+ public EncryptedKey encryptKey(
+ Document doc,
+ Key key,
+ String mgfAlgorithm,
+ byte[] oaepParams
+ ) throws XMLEncryptionException {
if (log.isDebugEnabled()) {
log.debug("Encrypting key ...");
}
@@ -1248,33 +1279,9 @@ public class XMLCipher {
byte[] encryptedBytes = null;
Cipher c;
- OAEPParameterSpec oaepParameters = null;
if (contextCipher == null) {
// Now create the working cipher
-
- String jceAlgorithm = JCEMapper.translateURItoJCEID(algorithm);
- if (log.isDebugEnabled()) {
- log.debug("alg = " + jceAlgorithm);
- }
-
- try {
- if (requestedJCEProvider == null) {
- c = Cipher.getInstance(jceAlgorithm);
- } else {
- c = Cipher.getInstance(jceAlgorithm, requestedJCEProvider);
- }
- } catch (NoSuchAlgorithmException nsae) {
- throw new XMLEncryptionException("empty", nsae);
- } catch (NoSuchProviderException nspre) {
- throw new XMLEncryptionException("empty", nspre);
- } catch (NoSuchPaddingException nspae) {
- throw new XMLEncryptionException("empty", nspae);
- }
-
- if (XMLCipher.RSA_OAEP.equals(algorithm)) {
- oaepParameters =
- new OAEPParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
- }
+ c = constructCipher(algorithm, null);
} else {
c = contextCipher;
}
@@ -1283,6 +1290,10 @@ public class XMLCipher {
try {
// Should internally generate an IV
// todo - allow user to set an IV
+ OAEPParameterSpec oaepParameters =
+ constructOAEPParameters(
+ algorithm, digestAlg, mgfAlgorithm, oaepParams
+ );
if (oaepParameters == null) {
c.init(Cipher.WRAP_MODE, this.key);
} else {
@@ -1308,6 +1319,9 @@ public class XMLCipher {
try {
EncryptionMethod method = factory.newEncryptionMethod(new URI(algorithm).toString());
+ method.setDigestAlgorithm(digestAlg);
+ method.setMGFAlgorithm(mgfAlgorithm);
+ method.setOAEPparams(oaepParams);
ek.setEncryptionMethod(method);
} catch (URISyntaxException ex) {
throw new XMLEncryptionException("empty", ex);
@@ -1378,48 +1392,13 @@ public class XMLCipher {
}
Cipher c;
- OAEPParameterSpec oaepParameters = null;
if (contextCipher == null) {
// Now create the working cipher
-
- String jceAlgorithm =
- JCEMapper.translateURItoJCEID(encryptedKey.getEncryptionMethod().getAlgorithm());
- if (log.isDebugEnabled()) {
- log.debug("JCE Algorithm = " + jceAlgorithm);
- }
-
- try {
- if (requestedJCEProvider == null) {
- c = Cipher.getInstance(jceAlgorithm);
- } else {
- c = Cipher.getInstance(jceAlgorithm, requestedJCEProvider);
- }
- } catch (NoSuchAlgorithmException nsae) {
- // Check to see if an RSA OAEP MGF-1 with SHA-1 algorithm was requested
- // Some JDKs don't support RSA/ECB/OAEPPadding
- String digestMethod = encryptedKey.getEncryptionMethod().getDigestAlgorithm();
- if (XMLCipher.RSA_OAEP.equals(encryptedKey.getEncryptionMethod().getAlgorithm())
- && (digestMethod == null
- || MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA1.equals(digestMethod))) {
- try {
- if (requestedJCEProvider == null) {
- c = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
- } else {
- c = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding", requestedJCEProvider);
- }
- } catch (Exception ex) {
- throw new XMLEncryptionException("empty", ex);
- }
- } else {
- throw new XMLEncryptionException("empty", nsae);
- }
- } catch (NoSuchProviderException nspre) {
- throw new XMLEncryptionException("empty", nspre);
- } catch (NoSuchPaddingException nspae) {
- throw new XMLEncryptionException("empty", nspae);
- }
-
- oaepParameters = constructOAEPParameters(encryptedKey.getEncryptionMethod());
+ c =
+ constructCipher(
+ encryptedKey.getEncryptionMethod().getAlgorithm(),
+ encryptedKey.getEncryptionMethod().getDigestAlgorithm()
+ );
} else {
c = contextCipher;
}
@@ -1427,6 +1406,12 @@ public class XMLCipher {
Key ret;
try {
+ EncryptionMethod encMethod = encryptedKey.getEncryptionMethod();
+ OAEPParameterSpec oaepParameters =
+ constructOAEPParameters(
+ encMethod.getAlgorithm(), encMethod.getDigestAlgorithm(),
+ encMethod.getMGFAlgorithm(), encMethod.getOAEPparams()
+ );
if (oaepParameters == null) {
c.init(Cipher.UNWRAP_MODE, key);
} else {
@@ -1448,28 +1433,29 @@ public class XMLCipher {
}
/**
- * Construt an OAEPParameterSpec object from an EncryptionMethod
+ * Construct an OAEPParameterSpec object from the given parameters
*/
private OAEPParameterSpec constructOAEPParameters(
- EncryptionMethod encryptionMethod
+ String encryptionAlgorithm,
+ String digestAlgorithm,
+ String mgfAlgorithm,
+ byte[] oaepParams
) {
- if (XMLCipher.RSA_OAEP.equals(encryptionMethod.getAlgorithm())
- || XMLCipher.RSA_OAEP_11.equals(encryptionMethod.getAlgorithm())) {
+ if (XMLCipher.RSA_OAEP.equals(encryptionAlgorithm)
+ || XMLCipher.RSA_OAEP_11.equals(encryptionAlgorithm)) {
- String digestAlgorithm = encryptionMethod.getDigestAlgorithm();
String jceDigestAlgorithm = "SHA-1";
if (digestAlgorithm != null) {
jceDigestAlgorithm = JCEMapper.translateURItoJCEID(digestAlgorithm);
}
PSource.PSpecified pSource = PSource.PSpecified.DEFAULT;
- if (encryptionMethod.getOAEPparams() != null) {
- pSource = new PSource.PSpecified(encryptionMethod.getOAEPparams());
+ if (oaepParams != null) {
+ pSource = new PSource.PSpecified(oaepParams);
}
MGF1ParameterSpec mgfParameterSpec = new MGF1ParameterSpec("SHA-1");
- if (XMLCipher.RSA_OAEP_11.equals(encryptionMethod.getAlgorithm())) {
- String mgfAlgorithm = encryptionMethod.getMGFAlgorithm();
+ if (XMLCipher.RSA_OAEP_11.equals(encryptionAlgorithm)) {
if (EncryptionConstants.MGF1_SHA256.equals(mgfAlgorithm)) {
mgfParameterSpec = new MGF1ParameterSpec("SHA-256");
} else if (EncryptionConstants.MGF1_SHA384.equals(mgfAlgorithm)) {
@@ -1478,12 +1464,54 @@ public class XMLCipher {
mgfParameterSpec = new MGF1ParameterSpec("SHA-512");
}
}
-
return new OAEPParameterSpec(jceDigestAlgorithm, "MGF1", mgfParameterSpec, pSource);
}
return null;
}
+
+ /**
+ * Construct a Cipher object
+ */
+ private Cipher constructCipher(String algorithm, String digestAlgorithm) throws XMLEncryptionException {
+ String jceAlgorithm = JCEMapper.translateURItoJCEID(algorithm);
+ if (log.isDebugEnabled()) {
+ log.debug("JCE Algorithm = " + jceAlgorithm);
+ }
+
+ Cipher c;
+ try {
+ if (requestedJCEProvider == null) {
+ c = Cipher.getInstance(jceAlgorithm);
+ } else {
+ c = Cipher.getInstance(jceAlgorithm, requestedJCEProvider);
+ }
+ } catch (NoSuchAlgorithmException nsae) {
+ // Check to see if an RSA OAEP MGF-1 with SHA-1 algorithm was requested
+ // Some JDKs don't support RSA/ECB/OAEPPadding
+ if (XMLCipher.RSA_OAEP.equals(algorithm)
+ && (digestAlgorithm == null
+ || MessageDigestAlgorithm.ALGO_ID_DIGEST_SHA1.equals(digestAlgorithm))) {
+ try {
+ if (requestedJCEProvider == null) {
+ c = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
+ } else {
+ c = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding", requestedJCEProvider);
+ }
+ } catch (Exception ex) {
+ throw new XMLEncryptionException("empty", ex);
+ }
+ } else {
+ throw new XMLEncryptionException("empty", nsae);
+ }
+ } catch (NoSuchProviderException nspre) {
+ throw new XMLEncryptionException("empty", nspre);
+ } catch (NoSuchPaddingException nspae) {
+ throw new XMLEncryptionException("empty", nspae);
+ }
+
+ return c;
+ }
/**
* Decrypt a key from a passed in EncryptedKey structure. This version
@@ -3025,16 +3053,12 @@ public class XMLCipher {
).appendChild(contextDocument.createTextNode(String.valueOf(keySize))));
}
if (null != oaepParams) {
- try {
- result.appendChild(
- XMLUtils.createElementInEncryptionSpace(
- contextDocument, EncryptionConstants._TAG_OAEPPARAMS
- ).appendChild(contextDocument.createTextNode(
- new String(oaepParams, "UTF-8")
- )));
- } catch(UnsupportedEncodingException e) {
- throw new RuntimeException("UTF-8 not supported", e);
- }
+ Element oaepElement =
+ XMLUtils.createElementInEncryptionSpace(
+ contextDocument, EncryptionConstants._TAG_OAEPPARAMS
+ );
+ oaepElement.appendChild(contextDocument.createTextNode(Base64.encode(oaepParams)));
+ result.appendChild(oaepElement);
}
if (digestAlgorithm != null) {
Element digestElement =
@@ -3042,6 +3066,19 @@ public class XMLCipher {
digestElement.setAttributeNS(null, "Algorithm", digestAlgorithm);
result.appendChild(digestElement);
}
+ if (mgfAlgorithm != null) {
+ Element mgfElement =
+ XMLUtils.createElementInEncryption11Space(
+ contextDocument, EncryptionConstants._TAG_MGF
+ );
+ mgfElement.setAttributeNS(null, "Algorithm", mgfAlgorithm);
+ mgfElement.setAttributeNS(
+ Constants.NamespaceSpecNS,
+ "xmlns:" + ElementProxy.getDefaultPrefix(EncryptionConstants.EncryptionSpec11NS),
+ EncryptionConstants.EncryptionSpec11NS
+ );
+ result.appendChild(mgfElement);
+ }
Iterator<Element> itr = encryptionMethodInformation.iterator();
while (itr.hasNext()) {
result.appendChild(itr.next());
Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/ElementProxy.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/ElementProxy.java?rev=1230583&r1=1230582&r2=1230583&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/ElementProxy.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/ElementProxy.java Thu Jan 12 15:14:39 2012
@@ -490,6 +490,7 @@ public abstract class ElementProxy {
public static void registerDefaultPrefixes() throws XMLSecurityException {
setDefaultPrefix("http://www.w3.org/2000/09/xmldsig#", "ds");
setDefaultPrefix("http://www.w3.org/2001/04/xmlenc#", "xenc");
+ setDefaultPrefix("http://www.w3.org/2009/xmlenc11#", "xenc11");
setDefaultPrefix("http://www.xmlsecurity.org/experimental#", "experimental");
setDefaultPrefix("http://www.w3.org/2002/04/xmldsig-filter2", "dsig-xpath-old");
setDefaultPrefix("http://www.w3.org/2002/06/xmldsig-filter2", "dsig-xpath");
Modified: santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java?rev=1230583&r1=1230582&r2=1230583&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java (original)
+++ santuario/xml-security-java/trunk/src/main/java/org/apache/xml/security/utils/XMLUtils.java Thu Jan 12 15:14:39 2012
@@ -57,6 +57,7 @@ public class XMLUtils {
private static volatile String dsPrefix = "ds";
private static volatile String xencPrefix = "xenc";
+ private static volatile String xenc11Prefix = "xenc11";
/** {@link org.apache.commons.logging} logging facility */
private static final org.apache.commons.logging.Log log =
@@ -87,6 +88,14 @@ public class XMLUtils {
xencPrefix = prefix;
}
+ /**
+ * Set the prefix for the encryption namespace 1.1
+ * @param prefix the new prefix for the encryption namespace 1.1
+ */
+ public static void setXenc11Prefix(String prefix) {
+ xenc11Prefix = prefix;
+ }
+
public static Element getNextElement(Node el) {
while ((el != null) && (el.getNodeType() != Node.ELEMENT_NODE)) {
el = el.getNextSibling();
@@ -291,6 +300,27 @@ public class XMLUtils {
EncryptionConstants.EncryptionSpecNS, xencPrefix + ":" + elementName
);
}
+
+ /**
+ * Creates an Element in the XML Encryption 1.1 specification namespace.
+ *
+ * @param doc the factory Document
+ * @param elementName the local name of the Element
+ * @return the Element
+ */
+ public static Element createElementInEncryption11Space(Document doc, String elementName) {
+ if (doc == null) {
+ throw new RuntimeException("Document is null");
+ }
+
+ if ((xenc11Prefix == null) || (xenc11Prefix.length() == 0)) {
+ return doc.createElementNS(EncryptionConstants.EncryptionSpec11NS, elementName);
+ }
+ return
+ doc.createElementNS(
+ EncryptionConstants.EncryptionSpec11NS, xenc11Prefix + ":" + elementName
+ );
+ }
/**
* Returns true if the element is in XML Signature namespace and the local
@@ -326,6 +356,23 @@ public class XMLUtils {
return EncryptionConstants.EncryptionSpecNS.equals(element.getNamespaceURI())
&& element.getLocalName().equals(localName);
}
+
+ /**
+ * Returns true if the element is in XML Encryption 1.1 namespace and the local
+ * name equals the supplied one.
+ *
+ * @param element
+ * @param localName
+ * @return true if the element is in XML Encryption 1.1 namespace and the local name
+ * equals the supplied one
+ */
+ public static boolean elementIsInEncryption11Space(Element element, String localName) {
+ if (element == null){
+ return false;
+ }
+ return EncryptionConstants.EncryptionSpec11NS.equals(element.getNamespaceURI())
+ && element.getLocalName().equals(localName);
+ }
/**
* This method returns the owner document of a particular node.
Modified: santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLEncryption11Test.java
URL: http://svn.apache.org/viewvc/santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLEncryption11Test.java?rev=1230583&r1=1230582&r2=1230583&view=diff
==============================================================================
--- santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLEncryption11Test.java (original)
+++ santuario/xml-security-java/trunk/src/test/java/org/apache/xml/security/test/encryption/XMLEncryption11Test.java Thu Jan 12 15:14:39 2012
@@ -32,6 +32,7 @@ import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -48,6 +49,7 @@ import org.apache.xml.security.keys.KeyI
import org.apache.xml.security.keys.content.X509Data;
import org.apache.xml.security.keys.content.x509.XMLX509Certificate;
import org.apache.xml.security.test.DSNamespaceContext;
+import org.apache.xml.security.utils.Base64;
import org.apache.xml.security.utils.EncryptionConstants;
// import org.apache.xml.security.utils.XMLUtils;
import org.w3c.dom.Document;
@@ -184,6 +186,75 @@ public class XMLEncryption11Test extends
* rsa-oaep-mgf1p, Digest:SHA256, MGF:SHA1, PSource: None
*/
@org.junit.Test
+ public void testKeyWrappingRSA2048EncryptDecrypt() throws Exception {
+ if (haveISOPadding) {
+ String keystore =
+ "src/test/resources/org/w3c/www/interop/xmlenc-core-11/RSA-2048_SHA256WithRSA.jks";
+ String basedir = System.getProperty("basedir");
+ if (basedir != null && !"".equals(basedir)) {
+ keystore = basedir + "/" + keystore;
+ }
+
+ KeyStore keyStore = KeyStore.getInstance("jks");
+ keyStore.load(new java.io.FileInputStream(keystore), "passwd".toCharArray());
+
+ Certificate cert = keyStore.getCertificate("importkey");
+
+ KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
+ keyStore.getEntry("importkey", new KeyStore.PasswordProtection("passwd".toCharArray()));
+ PrivateKey rsaKey = pkEntry.getPrivateKey();
+
+ // Perform encryption
+ String filename = "src/test/resources/org/w3c/www/interop/xmlenc-core-11/plaintext.xml";
+ javax.xml.parsers.DocumentBuilderFactory dbf =
+ javax.xml.parsers.DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ dbf.setAttribute("http://xml.org/sax/features/namespaces", Boolean.TRUE);
+ if (basedir != null && !"".equals(basedir)) {
+ filename = basedir + "/" + filename;
+ }
+ File f = new File(filename);
+
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(new java.io.FileInputStream(f));
+
+ Key sessionKey = getSessionKey("http://www.w3.org/2009/xmlenc11#aes128-gcm");
+ EncryptedKey encryptedKey =
+ createEncryptedKey(
+ doc,
+ (X509Certificate)cert,
+ sessionKey,
+ "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p",
+ "http://www.w3.org/2000/09/xmldsig#sha1",
+ null,
+ null
+ );
+
+ doc =
+ encryptDocument(
+ doc,
+ encryptedKey,
+ sessionKey,
+ "http://www.w3.org/2009/xmlenc11#aes128-gcm"
+ );
+ // XMLUtils.outputDOM(doc.getFirstChild(), System.out);
+
+ // Perform decryption
+ Document dd = decryptElement(doc, rsaKey, (X509Certificate)cert);
+ // XMLUtils.outputDOM(dd.getFirstChild(), System.out);
+ checkDecryptedDoc(dd, true);
+ } else {
+ log.warn(
+ "Skipping testRSA2048 as necessary "
+ + "crypto algorithms are not available"
+ );
+ }
+ }
+
+ /**
+ * rsa-oaep-mgf1p, Digest:SHA256, MGF:SHA1, PSource: None
+ */
+ @org.junit.Test
public void testKeyWrappingRSA3072() throws Exception {
if (haveISOPadding) {
String keystore =
@@ -218,6 +289,75 @@ public class XMLEncryption11Test extends
}
/**
+ * rsa-oaep-mgf1p, Digest:SHA256, MGF:SHA1, PSource: None
+ */
+ @org.junit.Test
+ public void testKeyWrappingRSA3072EncryptDecrypt() throws Exception {
+ if (haveISOPadding) {
+ String keystore =
+ "src/test/resources/org/w3c/www/interop/xmlenc-core-11/RSA-3072_SHA256WithRSA.jks";
+ String basedir = System.getProperty("basedir");
+ if (basedir != null && !"".equals(basedir)) {
+ keystore = basedir + "/" + keystore;
+ }
+
+ KeyStore keyStore = KeyStore.getInstance("jks");
+ keyStore.load(new java.io.FileInputStream(keystore), "passwd".toCharArray());
+
+ Certificate cert = keyStore.getCertificate("importkey");
+
+ KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
+ keyStore.getEntry("importkey", new KeyStore.PasswordProtection("passwd".toCharArray()));
+ PrivateKey rsaKey = pkEntry.getPrivateKey();
+
+ // Perform encryption
+ String filename = "src/test/resources/org/w3c/www/interop/xmlenc-core-11/plaintext.xml";
+ javax.xml.parsers.DocumentBuilderFactory dbf =
+ javax.xml.parsers.DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ dbf.setAttribute("http://xml.org/sax/features/namespaces", Boolean.TRUE);
+ if (basedir != null && !"".equals(basedir)) {
+ filename = basedir + "/" + filename;
+ }
+ File f = new File(filename);
+
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(new java.io.FileInputStream(f));
+
+ Key sessionKey = getSessionKey("http://www.w3.org/2009/xmlenc11#aes192-gcm");
+ EncryptedKey encryptedKey =
+ createEncryptedKey(
+ doc,
+ (X509Certificate)cert,
+ sessionKey,
+ "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p",
+ "http://www.w3.org/2001/04/xmlenc#sha256",
+ null,
+ null
+ );
+
+ doc =
+ encryptDocument(
+ doc,
+ encryptedKey,
+ sessionKey,
+ "http://www.w3.org/2009/xmlenc11#aes192-gcm"
+ );
+ // XMLUtils.outputDOM(doc.getFirstChild(), System.out);
+
+ // Perform decryption
+ Document dd = decryptElement(doc, rsaKey, (X509Certificate)cert);
+ // XMLUtils.outputDOM(dd.getFirstChild(), System.out);
+ checkDecryptedDoc(dd, true);
+ } else {
+ log.warn(
+ "Skipping testRSA3072 as necessary "
+ + "crypto algorithms are not available"
+ );
+ }
+ }
+
+ /**
* rsa-oaep, Digest:SHA384, MGF:SHA1, PSource: None
*/
@org.junit.Test
@@ -255,6 +395,75 @@ public class XMLEncryption11Test extends
}
/**
+ * rsa-oaep, Digest:SHA384, MGF:SHA1, PSource: None
+ */
+ @org.junit.Test
+ public void testKeyWrappingRSA3072OAEPEncryptDecrypt() throws Exception {
+ if (haveISOPadding) {
+ String keystore =
+ "src/test/resources/org/w3c/www/interop/xmlenc-core-11/RSA-3072_SHA256WithRSA.jks";
+ String basedir = System.getProperty("basedir");
+ if (basedir != null && !"".equals(basedir)) {
+ keystore = basedir + "/" + keystore;
+ }
+
+ KeyStore keyStore = KeyStore.getInstance("jks");
+ keyStore.load(new java.io.FileInputStream(keystore), "passwd".toCharArray());
+
+ Certificate cert = keyStore.getCertificate("importkey");
+
+ KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
+ keyStore.getEntry("importkey", new KeyStore.PasswordProtection("passwd".toCharArray()));
+ PrivateKey rsaKey = pkEntry.getPrivateKey();
+
+ // Perform encryption
+ String filename = "src/test/resources/org/w3c/www/interop/xmlenc-core-11/plaintext.xml";
+ javax.xml.parsers.DocumentBuilderFactory dbf =
+ javax.xml.parsers.DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ dbf.setAttribute("http://xml.org/sax/features/namespaces", Boolean.TRUE);
+ if (basedir != null && !"".equals(basedir)) {
+ filename = basedir + "/" + filename;
+ }
+ File f = new File(filename);
+
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(new java.io.FileInputStream(f));
+
+ Key sessionKey = getSessionKey("http://www.w3.org/2009/xmlenc11#aes256-gcm");
+ EncryptedKey encryptedKey =
+ createEncryptedKey(
+ doc,
+ (X509Certificate)cert,
+ sessionKey,
+ "http://www.w3.org/2009/xmlenc11#rsa-oaep",
+ "http://www.w3.org/2001/04/xmldsig-more#sha384",
+ "http://www.w3.org/2009/xmlenc11#mgf1sha1",
+ null
+ );
+
+ doc =
+ encryptDocument(
+ doc,
+ encryptedKey,
+ sessionKey,
+ "http://www.w3.org/2009/xmlenc11#aes256-gcm"
+ );
+ // XMLUtils.outputDOM(doc.getFirstChild(), System.out);
+
+ // Perform decryption
+ Document dd = decryptElement(doc, rsaKey, (X509Certificate)cert);
+ // XMLUtils.outputDOM(dd.getFirstChild(), System.out);
+ checkDecryptedDoc(dd, true);
+ } else {
+ log.warn(
+ "Skipping testRSA2048 as necessary "
+ + "crypto algorithms are not available"
+ );
+ }
+ }
+
+ /**
* rsa-oaep, Digest:SHA512, MGF:SHA1, PSource: Specified 8 bytes
*/
@org.junit.Test
@@ -292,6 +501,75 @@ public class XMLEncryption11Test extends
}
/**
+ * rsa-oaep, Digest:SHA512, MGF:SHA1, PSource: Specified 8 bytes
+ */
+ @org.junit.Test
+ public void testKeyWrappingRSA4096EncryptDecrypt() throws Exception {
+ if (haveISOPadding) {
+ String keystore =
+ "src/test/resources/org/w3c/www/interop/xmlenc-core-11/RSA-4096_SHA256WithRSA.jks";
+ String basedir = System.getProperty("basedir");
+ if (basedir != null && !"".equals(basedir)) {
+ keystore = basedir + "/" + keystore;
+ }
+
+ KeyStore keyStore = KeyStore.getInstance("jks");
+ keyStore.load(new java.io.FileInputStream(keystore), "passwd".toCharArray());
+
+ Certificate cert = keyStore.getCertificate("importkey");
+
+ KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
+ keyStore.getEntry("importkey", new KeyStore.PasswordProtection("passwd".toCharArray()));
+ PrivateKey rsaKey = pkEntry.getPrivateKey();
+
+ // Perform encryption
+ String filename = "src/test/resources/org/w3c/www/interop/xmlenc-core-11/plaintext.xml";
+ javax.xml.parsers.DocumentBuilderFactory dbf =
+ javax.xml.parsers.DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ dbf.setAttribute("http://xml.org/sax/features/namespaces", Boolean.TRUE);
+ if (basedir != null && !"".equals(basedir)) {
+ filename = basedir + "/" + filename;
+ }
+ File f = new File(filename);
+
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(new java.io.FileInputStream(f));
+
+ Key sessionKey = getSessionKey("http://www.w3.org/2009/xmlenc11#aes256-gcm");
+ EncryptedKey encryptedKey =
+ createEncryptedKey(
+ doc,
+ (X509Certificate)cert,
+ sessionKey,
+ "http://www.w3.org/2009/xmlenc11#rsa-oaep",
+ "http://www.w3.org/2001/04/xmlenc#sha512",
+ "http://www.w3.org/2009/xmlenc11#mgf1sha1",
+ Base64.decode("ZHVtbXkxMjM=".getBytes("UTF-8"))
+ );
+
+ doc =
+ encryptDocument(
+ doc,
+ encryptedKey,
+ sessionKey,
+ "http://www.w3.org/2009/xmlenc11#aes256-gcm"
+ );
+ // XMLUtils.outputDOM(doc.getFirstChild(), System.out);
+
+ // Perform decryption
+ Document dd = decryptElement(doc, rsaKey, (X509Certificate)cert);
+ // XMLUtils.outputDOM(dd.getFirstChild(), System.out);
+ checkDecryptedDoc(dd, true);
+ } else {
+ log.warn(
+ "Skipping testRSA2048 as necessary "
+ + "crypto algorithms are not available"
+ );
+ }
+ }
+
+ /**
* Method decryptElement
*
* Take a key, encryption type and a file, find an encrypted element
@@ -301,10 +579,7 @@ public class XMLEncryption11Test extends
* @param key The Key to use for decryption
*/
private Document decryptElement(String filename, Key rsaKey, X509Certificate rsaCert) throws Exception {
- XMLCipher cipher;
-
// Parse the document in question
-
javax.xml.parsers.DocumentBuilderFactory dbf =
javax.xml.parsers.DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
@@ -317,9 +592,22 @@ public class XMLEncryption11Test extends
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new java.io.FileInputStream(f));
-
+
+ return decryptElement(doc, rsaKey, rsaCert);
+ }
+
+ /**
+ * Method decryptElement
+ *
+ * Take a key, encryption type and a document, find an encrypted element
+ * decrypt it and return the resulting document
+ *
+ * @param filename File to decrypt from
+ * @param key The Key to use for decryption
+ */
+ private Document decryptElement(Document doc, Key rsaKey, X509Certificate rsaCert) throws Exception {
// Create the XMLCipher element
- cipher = XMLCipher.getInstance();
+ XMLCipher cipher = XMLCipher.getInstance();
// Need to pre-load the Encrypted Data so we can get the key info
Element ee =
@@ -351,6 +639,80 @@ public class XMLEncryption11Test extends
}
/**
+ * Create an EncryptedKey object using the given parameters.
+ */
+ private EncryptedKey createEncryptedKey(
+ Document doc,
+ X509Certificate rsaCert,
+ Key sessionKey,
+ String encryptionMethod,
+ String digestMethod,
+ String mgfAlgorithm,
+ byte[] oaepParams
+ ) throws Exception {
+ // Create the XMLCipher element
+ XMLCipher cipher = XMLCipher.getInstance(encryptionMethod, null, digestMethod);
+
+ cipher.init(XMLCipher.WRAP_MODE, rsaCert.getPublicKey());
+ EncryptedKey encryptedKey = cipher.encryptKey(doc, sessionKey, mgfAlgorithm, oaepParams);
+
+ KeyInfo builderKeyInfo = encryptedKey.getKeyInfo();
+ if (builderKeyInfo == null) {
+ builderKeyInfo = new KeyInfo(doc);
+ encryptedKey.setKeyInfo(builderKeyInfo);
+ }
+
+ X509Data x509Data = new X509Data(doc);
+ x509Data.addCertificate(rsaCert);
+ builderKeyInfo.add(x509Data);
+
+ return encryptedKey;
+ }
+
+ /**
+ * Generate a session key using the given algorithm
+ */
+ private Key getSessionKey(String encryptionMethod) throws Exception {
+ // Generate a session key
+ KeyGenerator keyGen = KeyGenerator.getInstance("AES");
+ if (encryptionMethod.contains("128")) {
+ keyGen.init(128);
+ } else if (encryptionMethod.contains("192")) {
+ keyGen.init(192);
+ } else if (encryptionMethod.contains("256")) {
+ keyGen.init(256);
+ }
+ return keyGen.generateKey();
+ }
+
+ /**
+ * Encrypt a Document using the given parameters.
+ */
+ private Document encryptDocument(
+ Document doc,
+ EncryptedKey encryptedKey,
+ Key sessionKey,
+ String encryptionMethod
+ ) throws Exception {
+ // Create the XMLCipher element
+ XMLCipher cipher = XMLCipher.getInstance(encryptionMethod);
+
+ cipher.init(XMLCipher.ENCRYPT_MODE, sessionKey);
+ EncryptedData builder = cipher.getEncryptedData();
+
+ KeyInfo builderKeyInfo = builder.getKeyInfo();
+ if (builderKeyInfo == null) {
+ builderKeyInfo = new KeyInfo(doc);
+ builder.setKeyInfo(builderKeyInfo);
+ }
+
+ builderKeyInfo.add(encryptedKey);
+
+ return cipher.doFinal(doc, doc.getDocumentElement());
+ }
+
+
+ /**
* Method countNodes
*
* Recursively count the number of nodes in the document