JDK-8019379 : ResourceResolverException is throwed in complex XMLSignatures with JRE 1.7.0_25
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.crypto
  • Affected Version: 7u25
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_8
  • Submitted: 2013-06-28
  • Updated: 2013-06-28
  • Resolved: 2013-06-28
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
java version  " 1.7.0_25 " 
Java(TM) SE Runtime Environment (build 1.7.0_25-b17)
Java HotSpot(TM) Client VM (build 23.25-b01, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 8 Pro
Microsoft Windows 8
Microsoft Windows 7
Microsoft Windows XP Version 2002 Service Pack 3
Mac OS X 10.8.4

A DESCRIPTION OF THE PROBLEM :
Introduction
--------------
With 1.7.0_25 version, advanced XML signatures that uses javax.xml.crypto.dsig package can fail. Knowledge of XML DSig is required for understand the problem.

Advanced XML signatures formats (like XAdES) includes predefined <ds:objects> as a set of extensions for XML-DSig format.

In this formats, the Reference (to be signed) not corresponds with with the whole <ds:object>, only subelements of <ds:objects> will be signed.

For example, in XAdES we have a signature like this:
...
<Reference URI= " #XAdES-SignedProperties " >
...
<ds:Object>
     <xades:QualifyingProperties xmlns:xades= " http://uri.etsi.org/01903/v1.2.2# " >
<xades:SignedProperties Id= " XAdES-SignedProperties " >
             .....

The Reference to be signed is the subelement  " xades:SignedProperties "  with Id  " XAdES-SignedProperties " .

Problem
----------

The problem is that after 1.7.0_25 update, the method  " sign "  of XMLSignature is failing because the next exception is threw:

com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID XAdES-SignedProperties
com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(ResolverFragment.java:90)

Downgrading to 1.7.0_21 is fixing the problem, so it seems to be a backward compatibility error.

Cause of the problem
---------------------------

Why ResolverFragment cant find the element?

Because its source code has change in version 25 (for include the  " secure validation "  features).

1.7.0_21 -> ResolverFragment.java:92
       selectedElem = IdResolver.getElementById(doc, id);
1.7.0_25 -> ResolverFragment.java:87
       selectedElem = doc.getElementById(id);

As SignedProperties is not a  " headed "  element of the signature, its Id is not loaded as a identifer of the Document during marshaling phase.

The util IdResolver could find the subelement Id because it tries several ways, but getElementById cant do it.

Testing
---------

If you change the format of the signature to this:
...
<Reference URI= " #XAdES-SignedProperties " >
...
<ds:Object Id= " XAdES-SignedProperties " >
     <xades:QualifyingProperties xmlns:xades= " http://uri.etsi.org/01903/v1.2.2# " >
<xades:SignedProperties>

Then, marshaling phase sets Id as a identifier and doc.getElementByID can find the Reference.

But this example is not a workaround because its needed that exists both signed and unsigned properties.

Also, you can  " patch "  the ResolverFragment.java 1.7.0_25 version changing only  " doc.getElementById(id) "  by  " IdResolver.getElementById(doc, id) "  and then it works.

REGRESSION.  Last worked in version 7u25

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use 1.7.0_25 version

Create a javax.xml.crypto.dsig.XMLObject with this schema:
   <elem1>
      <elem2tobesigned Id= " elem2tobesignedID " />
   </elem1>

Create a javax.xml.crypto.dsig.Reference for #elem2tobesignedID

Create a javax.xml.crypto.dsig.XMLSignature with all of them.

Create a javax.xml.crypto.dsig.XMLSignContext with any XML and any PrivateKey.

Sign the XMLSignContext with  " sign "  method of  XMLSignature and wait for the exception.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
An XML signature that includes a signed Reference for elem2tobesigned
ACTUAL -
Exception in thread  " main "  javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID elem2tobesignedID

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread  " main "  javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID elem2tobesignedID
at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:412)
at org.jcp.xml.dsig.internal.dom.DOMReference.digest(DOMReference.java:338)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.digestReference(DOMXMLSignature.java:471)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:367)
at jre7_25signatureXAdESError.main(jre7_25signatureXAdESError.java:96)
Caused by: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID elem2tobesignedID
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:124)
at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:404)
... 4 more
Caused by: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID elem2tobesignedID
at com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(ResolverFragment.java:90)
at com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(ResourceResolver.java:283)
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:117)
... 5 more
javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID elem2tobesignedID
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:124)
at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:404)
at org.jcp.xml.dsig.internal.dom.DOMReference.digest(DOMReference.java:338)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.digestReference(DOMXMLSignature.java:471)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(DOMXMLSignature.java:367)
at jre7_25signatureXAdESError.main(jre7_25signatureXAdESError.java:96)
Caused by: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID elem2tobesignedID
at com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(ResolverFragment.java:90)
at com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(ResourceResolver.java:283)
at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(DOMURIDereferencer.java:117)
... 5 more


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.List;

import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLObject;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;

import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;

public class jre7_25signatureXAdESError {

public static void main(final String args[]) throws Exception {

final byte[] pfx = getPFX();

final KeyStore ks = KeyStore.getInstance( " pkcs12 " );
ks.load(new ByteArrayInputStream(pfx), getPFXPass());

final PrivateKey privKey = (PrivateKey) ks.getKey(ks.aliases().nextElement(), getPFXPass());

final XMLSignatureFactory dsf = XMLSignatureFactory.getInstance( " DOM " );
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);

final String string2sign =  " <xmltosign><test>hello</test></xmltosign> " ;
final String stringxades =  " <QualifyingProperties Target='#Signature'><SignedProperties Id='XAdES-SignedProperties'><SignedSignatureProperties><SigningTime>2013-06-27T13:16:02+02:00</SigningTime></SignedSignatureProperties></SignedProperties><UnsignedProperties></UnsignedProperties></QualifyingProperties> " ;

final Document doc2sign = dbf.newDocumentBuilder().parse(new InputSource(new StringReader(string2sign)));

final ArrayList<Transform> transformList = new ArrayList<Transform>();
final TransformParameterSpec tps = null;
final Transform envelopedTransform = dsf.newTransform(Transform.ENVELOPED, tps);
final Transform c14NTransform = dsf.newTransform( " http://www.w3.org/TR/2001/REC-xml-c14n-20010315 " , tps);

transformList.add(envelopedTransform);
transformList.add(c14NTransform);

//Build XAdesObject
final Document xadesDoc = dbf.newDocumentBuilder().parse(new InputSource(new StringReader(stringxades)));

final List<XMLStructure> content = new ArrayList<XMLStructure>();
final DOMStructure object = new DOMStructure(xadesDoc.getFirstChild());
content.add(object);

final XMLObject xmlObject = dsf.newXMLObject(content, null, null, null);
final List<XMLObject> objects = new ArrayList<XMLObject>();
objects.add(xmlObject);

final Reference refDoc = dsf.newReference( "  " , dsf.newDigestMethod(DigestMethod.SHA1, null), transformList, null, null);
final Reference refXAdES = dsf.newReference( " #XAdES-SignedProperties " , dsf.newDigestMethod(DigestMethod.SHA1, null), transformList, null, null);

final ArrayList<Reference> refs = new ArrayList<Reference>();
refs.add(refDoc);
refs.add(refXAdES);

// Create the SignedInfo.
final SignedInfo si = dsf
        .newSignedInfo(dsf.newCanonicalizationMethod(
                CanonicalizationMethod.INCLUSIVE,
                (C14NMethodParameterSpec) null), dsf
                .newSignatureMethod(SignatureMethod.RSA_SHA1, null), refs);

final XMLSignature signature = dsf.newXMLSignature(si, null, objects,  " Signature " , null);
final DOMSignContext dsc = new DOMSignContext(privKey, doc2sign.getDocumentElement());
signature.sign(dsc);

System.out.println(documentToString(doc2sign));
}


private static String documentToString(final Document dataDocument) throws TransformerException {
final Source source = new DOMSource(dataDocument);
final StringWriter stringWriter = new StringWriter();
try {
final Result result = new StreamResult(stringWriter);
final TransformerFactory factory = TransformerFactory.newInstance();
final Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING,  " UTF-8 " );
transformer.transform(source, result);
return stringWriter.getBuffer().toString();
} finally {
try {
stringWriter.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

private final static String pfx =  " MIIKjgIBAzCCCkoGCSqGSIb3DQEHAaCCCjsEggo3MIIKMzCCA7wGCSqGSIb3DQEHAaCCA60EggOpMIIDpTCCA6EGCyqGSIb3DQEMCgECoIICtjCCArIwHAYKKoZIhvcNAQwBAzAOBAilqnNDH5UBuQICB9AEggKQGe4tXTk5V4xK6WKuusz0GYtjR0IlQ126GQr7lvPzj9965wFQK+hSxkOjVEqqJ/Q2s7RQ38R0f9gfPTNxb7DGSI6VR16HP2pnZXGFAUhDKv0OnjDd4Gw1YBi72ofKTcoqxg8nuMzumxmAtXTez3PazmAqowuYeCVYbuEM4n0yZPw57NcQykrMX7mP88x0bvXEWxN8hP5dzfmpw/3VXDtvvR/YLetFFBOzzvLzv1TTvM7xXrliSg3GBD3+MukKVGXCnBTVwjBfgxpY6VAV8nwXf2oAcnnuLxJgRcwNLJHCLJ1MjP8mpql+/r5qNEA5zX6A0bCDNMY/zlWRylIlwkVCkEKQLBjD6We/qIdcRjpxlOBkExhbY2il+xgkiyHlwxRtsEIzWeZr9TAAvfNSyFS408gMKEHLIyoCFNZmEKPzeF8zcZSyNPj8o7iaU45dJnbZ8K6aGQm4vSaDVScmcFdwfPhEbyVCSlLKs6sKEPJ4J2eqN6qW50RViRwkpbCh5Kwi+0/e7SDaMR3BGZNYC2S+hIT9YR/d6WYex4485NNyoa3sFfF26ihOYT65m+KUjxYfkUrKMuyiNRFHqoQrgxzsSpBt73nlXUYPXLjbeyJoawq5fxti2y2peaqeE0MkdfQ454pukOl8BIEO5djRNhwxsIR1bsL3dN3YNRZhfk+131iR76higKIxeHf7il1xo4fqGbjOZcDRYtUep8Tu2hpkxX2Plbavq+vXGzsrUu1SdxBlvGEEiVnC9eTXVf/SY90+rJPDWvlC2+qJ9c9o1ya6dqEVyJyuPg/A3K0KtSwkg4st5V++86xn82YCk+tvJ+i822xeSiF97AIac+KpOzp5xMhSyFoPqXF8XzGJa8h+QVkxgdcwEwYJKoZIhvcNAQkVMQYEBAEAAAAwWwYJKoZIhvcNAQkUMU4eTAB7AEMAOQAxADMARQAwADMAOAAtADMANwBEADkALQA0AEUAOQA3AC0AQQBEADAAMAAtADkAMwA1AEUAQgA3ADQAQQBCADEAMQA5AH0wYwYJKwYBBAGCNxEBMVYeVABNAGkAYwByAG8AcwBvAGYAdAAgAEIAYQBzAGUAIABDAHIAeQBwAHQAbwBnAHIAYQBwAGgAaQBjACAAUAByAG8AdgBpAGQAZQByACAAdgAxAC4AMDCCBm8GCSqGSIb3DQEHBqCCBmAwggZcAgEAMIIGVQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQIs3+69Ryv3J8CAgfQgIIGKGQ5ns5URyYYLdl4znoOJPa3DT6nirk4mSoV8qp8A3JgmlCktnnQZ5sMjeAF9RVlZuOQ24sIS9/Rdi20eiGBI962qCoNLZ/egG5FYigNvTKi1u2mdqsazq/P05N9yb7gn9XQyD8UXWolnK+HOi5UTLnyoM7RbydpG5aBsEWFrwHF1AxJFEOApg83r7rF8gTgYsqxTl6uyKhxBxmZ52NasWAbYUzdqPi0t6vrsy7v367pDWmeixdEq006nYu/H+qS9hofoTmonvnazAGBzuU3Vo6pDPzVOZ1bMAEDDYDpiW71fFyoI/C2zpUVi8EgCkTM8teUcDAJFlHqCg1ONnQRHAl8S1NPbCCLht+4ISWu4S8EYDcwUKaprcZ88FPAtgybnVvps22Njf0TnvHpmVo5+UhSmK3EnxTPXwxxN/4hUwQqWVIR5k7/z4I1a6OIRDRtOI8waka1QJAllDo89i69qkT+1LBTcALi7qGSRxiifsc2YBNfB9sB0SeIjqy2M1F1053xmdr0hB831/qEPIOzYDfNcLIGKIVhS2mAPiF1Rra3vYCbiZYCPqUZTQKCcGNNF9qgx0KtaHV/ED1YubaK34NSs0ifP6zZwhkuDinF7puGqaxCvcjsdnTBdCCYMhd7gGgpdiMNUXOB7webSZt473lCCxpJAOcfftXqF6jhoYH5ZXia5DShpNrjgx+0XohXHe+97GSehJlm4D+uUxMDDRu42LOC51TRpkiHkiQG6b9hAd2lcIErYcB51YnjD8rw3kClSZhTZhit2pHR4MhWkIernJMppWVLW9n8ieYkhUTmGj/0/q/QeL10cW+ChvOa4ePIXgoH0A58Vdoyt+jQSvZkcKUi0ZbPOgA61l/s3Ho77JDW+W8BWaWjkYtQ0iyLzSPPkGSCZY7UHw0bhraHbAnB+d54hvb75bdHY2FfWs9VLSDy1HQnlwRftrYNJfoS/YrTmE5lFWgb9/UusNMLnhmzqOLYaIXe3SX8ShO6SItYS3yYOTpL1sGuAAWicrMO1LJG1u75ELAMA+wJvFkuDa1gAt8XbY0vRO5GUk8dQDcv+iJBJjg8NuCLFtXbOgqPY+2E54uCRLt8XKRM8T1r3rPV9QpKD+VzTnPy5LbOX0JsnQg3N+0cXLbDeP++J7OPzkSg9COEL4BuAz4CtUryZ1K9dIN6V9QkHju3vdejF8lbD9Mlfok+yRKqeqLI0fgbLgGK764xz6B8qiUDGOMNl/Tki+HAxaB4BKBeK/ECqcQMKBZ54lVeyROSZCpe3Y2XVoMDmF3IJtQXymNBHeC3SbZ1cbL6qjmQj7fauWSQVU04XGAd4sH2ZvjSRLEOJfDcFoA1XbqjwCyX/oEI+Dr54RCaPX1s9hZqxEWMwX4mKdLaiz+5kzcFa8fhU9nZoADtrLXLcS4o/oxXoktrLmeNxWc90+SDlrtHb2+Zh9R2RZ1WhQGTa3ytoezQ2LrbZadtRjAwrBlce07MaNKM03HnlsFN6FTGC4JgzPMjoVJ8MIwXlcKVyn6WEk6+smsePIsKadvtROkMyA9QGFlAesDNAoRJ1Xg8yTOhoi+v2pUwIBpnOnUXBJb44JcivQa034TabOBduhBaEGvfN+q/XYZ1VBC/7Lda/MABch7+vicSooptM5bblewTRGz5tCn6S06xg4zDSYvnBfRI4Q63VtuamasjdEenl9pSOQ4i5pqw5WDem8uijyF0N+0Txk03Z3d8hV3VG+GJu0H76zdCmm4nqTFCXM6nRrRbOdq6qaX2OCSZF5T3ETHI8q/S1ERwODUEVnewvLYTikgJQDd6YA0F2yAsyOU2fv8OiM5Ot0r6U9Z0CdtQJB4jtTotHXaRamCxyNBAEO31+Iq/Qv95A/dnAOVHeV5Oe5TDreYEFO9ybq6FbngCY2H5YraTXJUd2XUYKHsp4T0uwguDk7nj8uH/PfuJUHsFStr9+ZG2nUfNzGWmNmJu/YUk3qGNBb1Vf7U1q+4qpQ/nbLmOX5DBwc3bdDFRnSij8ljoc9r23vH6XkmcLYA/ZjMyvPxifWNjqPHo7qFgnYJe0iJsUCWdcrXPfqwM2u6GPGJpyUp+W9ozX+rSpgHau+pCfNIwOzAfMAcGBSsOAwIaBBQsg7grZTVOKvHPaRzedzgPjZgMUQQU+0Zrg02Um6b4X/4Tr8ocvEyHUdECAgfQ " ;
private final static String pass =  " 12341234 " ;

private static byte[] getPFX() throws Base64DecodingException
{
return Base64.decode(pfx);
}

private static char[] getPFXPass()
{
return pass.toCharArray();
}

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Downgrade to java 1.7.0_21
Comments
The previous code which arbitrarily searched for ID references by the name of "Id" has been removed because it was insecure and is subject to XML Signature wrapping attacks. There are 3 potential workarounds that you can apply: 1. Use a validating schema which will register the elements with ID references. 2. Register the ID elements with the DOMValidateContext.setIdAttributeNS method before validating the signature 3. Implement a custom URIDereferencer which can find these references and override the builtin URIDereferencer with the DOMValidateContext.setURIDereferencer method.
28-06-2013