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

XML Signature Validation throws URIReferenceException

XMLWordPrintable

      FULL PRODUCT VERSION :
      java version " 1.7.0_25 "
      Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
      Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)


      ADDITIONAL OS VERSION INFORMATION :
      Linux debian 3.2.0-4-amd64 #1 SMP Debian 3.2.35-2 x86_64 GNU/Linux

      A DESCRIPTION OF THE PROBLEM :
      When using a ID to reference the part, which should be signed in the XML document - on validating the reference cannot be resolved.

      Stacktrace:
      $ ~/programs/jdk1.7.0_25/bin/java -cp bin XmlSigningTest
      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 _123
      at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(DOMReference.java:412)
      ...

      REGRESSION. Last worked in version 7

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      * Create a keystore with password " changeit " : keytool -genkeypair -keyalg RSA -alias mykey -keystore mykeystore.jks
      * Create the source xml file with the following content:
      <?xml version= " 1.0 " encoding= " UTF-8 " ?>
      <PurchaseOrder ID= " _123 " >
       <Item number= " 130046593231 " >
        <Description>Video Game</Description>
        <Price>10.29</Price>
       </Item>
       <Buyer id= " 8492340 " >
        <Name>My Name</Name>
        <Address>
         <Street>One Network Drive</Street>
         <Town>Burlington</Town>
         <State>MA</State>
         <Country>United States</Country>
         <PostalCode>01803</PostalCode>
        </Address>
       </Buyer>
      </PurchaseOrder>

      * Execute the test case, see source code section.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No exception, but " Validation Result: true "
      ACTUAL -
      Stacktrace:
      $ ~/programs/jdk1.7.0_25/bin/java -cp bin XmlSigningTest
      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 _123
      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 XmlSigningTest.main(XmlSigningTest.java:111)
      Caused by: javax.xml.crypto.URIReferenceException: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID _123
      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 _123
      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 _123
      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 XmlSigningTest.main(XmlSigningTest.java:111)
      Caused by: com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolverException: Cannot resolve element with ID _123
      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.FileInputStream;
      import java.io.FileOutputStream;
      import java.io.OutputStream;
      import java.security.Key;
      import java.security.KeyStore;
      import java.security.PublicKey;
      import java.security.cert.X509Certificate;
      import java.util.ArrayList;
      import java.util.Collections;
      import java.util.Iterator;
      import java.util.List;
      import javax.xml.crypto.AlgorithmMethod;
      import javax.xml.crypto.KeySelector;
      import javax.xml.crypto.KeySelectorException;
      import javax.xml.crypto.KeySelectorResult;
      import javax.xml.crypto.XMLCryptoContext;
      import javax.xml.crypto.XMLStructure;
      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.XMLSignature;
      import javax.xml.crypto.dsig.XMLSignatureFactory;
      import javax.xml.crypto.dsig.dom.DOMSignContext;
      import javax.xml.crypto.dsig.dom.DOMValidateContext;
      import javax.xml.crypto.dsig.keyinfo.KeyInfo;
      import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
      import javax.xml.crypto.dsig.keyinfo.X509Data;
      import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
      import javax.xml.crypto.dsig.spec.TransformParameterSpec;
      import javax.xml.parsers.DocumentBuilderFactory;
      import javax.xml.transform.Transformer;
      import javax.xml.transform.TransformerFactory;
      import javax.xml.transform.dom.DOMSource;
      import javax.xml.transform.stream.StreamResult;
      import org.w3c.dom.Document;
      import org.w3c.dom.NodeList;

      /**
       *
       * keytool -genkeypair -keyalg RSA -alias mykey -keystore mykeystore.jks
       *
       *
       * @see http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html
       */
      public class XmlSigningTest {

          private static final String ID = " #_123 " ;

          public static void main(String[] args) throws Exception {
              // Create a DOM XMLSignatureFactory that will be used to
              // generate the enveloped signature.
              XMLSignatureFactory fac = XMLSignatureFactory.getInstance( " DOM " );

              Reference ref = fac
                  .newReference(ID, fac.newDigestMethod(DigestMethod.SHA1, null),
                      Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null,
                      null);

              // Create the SignedInfo.
              SignedInfo si = fac.newSignedInfo(
                  fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null),
                  fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref));

              // Load the KeyStore and get the signing key and certificate.
              KeyStore ks = KeyStore.getInstance( " JKS " );
              ks.load(new FileInputStream( " mykeystore.jks " ), " changeit " .toCharArray());
              KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry( " mykey " ,
                  new KeyStore.PasswordProtection( " changeit " .toCharArray()));
              X509Certificate cert = (X509Certificate) keyEntry.getCertificate();

              // Create the KeyInfo containing the X509Data.
              KeyInfoFactory kif = fac.getKeyInfoFactory();
              List x509Content = new ArrayList();
              x509Content.add(cert.getSubjectX500Principal().getName());
              x509Content.add(cert);
              X509Data xd = kif.newX509Data(x509Content);
              KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));

              // Instantiate the document to be signed.
              DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
              dbf.setNamespaceAware(true);
              Document doc = dbf.newDocumentBuilder().parse(new FileInputStream( " purchaseOrder.xml " ));

              // Create a DOMSignContext and specify the RSA PrivateKey and
              // location of the resulting XMLSignature's parent element.
              DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement());

              // Create the XMLSignature, but don't sign it yet.
              XMLSignature signature = fac.newXMLSignature(si, ki);

              // Marshal, generate, and sign the enveloped signature.
              signature.sign(dsc);

              // Output the resulting document.
              OutputStream os = new FileOutputStream( " signedPurchaseOrder.xml " );
              TransformerFactory tf = TransformerFactory.newInstance();
              Transformer trans = tf.newTransformer();
              trans.transform(new DOMSource(doc), new StreamResult(os));

              // Find Signature element.
              NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, " Signature " );
              if (nl.getLength() == 0) {
                  throw new Exception( " Cannot find Signature element " );
              }

              // Create a DOMValidateContext and specify a KeySelector
              // and document context.
              DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(), nl.item(0));

              // Unmarshal the XMLSignature.
              XMLSignature signature2 = fac.unmarshalXMLSignature(valContext);

              // Validate the XMLSignature.
              boolean coreValidity = signature2.validate(valContext);
              
              System.out.println( " Validation Result: " + coreValidity);
          }

          public static class X509KeySelector extends KeySelector {
              @Override
              public KeySelectorResult select(KeyInfo keyInfo, KeySelector.Purpose purpose, AlgorithmMethod method,
                  XMLCryptoContext context) throws KeySelectorException {
                  Iterator ki = keyInfo.getContent().iterator();
                  while (ki.hasNext()) {
                      XMLStructure info = (XMLStructure) ki.next();
                      if (!(info instanceof X509Data)) {
                          continue;
                      }
                      X509Data x509Data = (X509Data) info;
                      Iterator xi = x509Data.getContent().iterator();
                      while (xi.hasNext()) {
                          Object o = xi.next();
                          if (!(o instanceof X509Certificate)) {
                              continue;
                          }
                          final PublicKey key = ((X509Certificate) o).getPublicKey();
                          // Make sure the algorithm is compatible
                          // with the method.
                          if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
                              return new KeySelectorResult() {
                                  @Override
                                  public Key getKey() {
                                      return key;
                                  }
                              };
                          }
                      }
                  }
                  throw new KeySelectorException( " No key found! " );
              }

              static boolean algEquals(String algURI, String algName) {
                  if ((algName.equalsIgnoreCase( " DSA " ) && algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1))
                      || (algName.equalsIgnoreCase( " RSA " ) && algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1))) {
                      return true;
                  } else {
                      return false;
                  }
              }
          }
      }

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

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

              Created:
              Updated:
              Resolved: