Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8019379

ResourceResolverException is throwed in complex XMLSignatures with JRE 1.7.0_25

XMLWordPrintable

      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 = " 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 " ;
      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

            mullan Sean Mullan
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: