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
-     *                  &quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
-     *                          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
-     *   				&quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
-     * @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
-     *   &quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
+     * @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
-     *   				&quot;http://www.w3.org/2001/04/xmlenc#tripledes-cbc&quot;
+     * @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