United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-7094155 JSR105 code throws javax.xml.crypto.URIReferenceException when running into Java 7 VM
JDK-7094155 : JSR105 code throws javax.xml.crypto.URIReferenceException when running into Java 7 VM

Details
Type:
Bug
Submit Date:
2011-09-23
Status:
Closed
Updated Date:
2012-10-23
Project Name:
JDK
Resolved Date:
2012-09-12
Component:
security-libs
OS:
windows_7
Sub-Component:
javax.xml.crypto
CPU:
x86
Priority:
P4
Resolution:
Fixed
Affected Versions:
7
Fixed Versions:

Related Reports
Backport:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.7.0"
Java(TM) SE Runtime Environment (build 1.7.0-b147)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
JSR105 code throws javax.xml.crypto.URIReference when running into Java 7 VM. A referenced node is not found.

REGRESSION.  Last worked in version 6u26

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See attached source code.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
XML signature should be produced.
ACTUAL -
a javax.xml.crypto.dsig.XMLSignatureException is thrown with Java 7.

XML signature is produced with Java 1.6.

ERROR MESSAGES/STACK TRACES THAT OCCUR :

javax.xml.crypto.dsig.XMLSignatureException: javax.xml.crypto.URIReferenceException: java.lang.NullPointerException
	at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(Unknown Source)
	at org.jcp.xml.dsig.internal.dom.DOMReference.digest(Unknown Source)
	at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.digestReference(Unknown Source)
	at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(Unknown Source)
	at Main.main(Main.java:332)
Caused by: javax.xml.crypto.URIReferenceException: java.lang.NullPointerException
	at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(Unknown Source)
	... 5 more
Caused by: java.lang.NullPointerException
	at com.sun.org.apache.xml.internal.security.utils.IdResolver.isElement(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.IdResolver.getEl(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.IdResolver.getElementBySearching(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.IdResolver.getElementById(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(Unknown Source)
	... 6 more
javax.xml.crypto.URIReferenceException: java.lang.NullPointerException
	at org.jcp.xml.dsig.internal.dom.DOMURIDereferencer.dereference(Unknown Source)
	at org.jcp.xml.dsig.internal.dom.DOMReference.dereference(Unknown Source)
	at org.jcp.xml.dsig.internal.dom.DOMReference.digest(Unknown Source)
	at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.digestReference(Unknown Source)
	at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(Unknown Source)
	at Main.main(Main.java:332)
Caused by: java.lang.NullPointerException
	at com.sun.org.apache.xml.internal.security.utils.IdResolver.isElement(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.IdResolver.getEl(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.IdResolver.getElementBySearching(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.IdResolver.getElementById(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment.engineResolve(Unknown Source)
	at com.sun.org.apache.xml.internal.security.utils.resolver.ResourceResolver.resolve(Unknown Source)
	... 6 more

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import javax.xml.crypto.Data;
import javax.xml.crypto.NodeSetData;
import javax.xml.crypto.URIDereferencer;
import javax.xml.crypto.URIReference;
import javax.xml.crypto.URIReferenceException;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
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.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.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.jcp.xml.dsig.internal.dom.ApacheNodeSetData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

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


public class JSR105Test {

	private static PrivateKey privateKey;
	private static java.security.cert.Certificate certificate = null;
	private static Element data;
	private static Element signedProperties;
		
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		try {
			
			XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");
			String signatureId = "MySignatureId";
			
			// Retrieve a certificate object
			retrieveCertificateAndPrivateKey();
			if (null == certificate || null == privateKey) {
				throw new Exception("no certificate");
			}
						
			Document document = createDocument(null);
			data = createElement(document, "DummyData", null, null);
			CanonicalizationMethod canonicalizationMethod = null;
					
			List referencesList = new ArrayList();
			List objectsList = new ArrayList();
			
			String signedPropertiesId =  signatureId + "_SignedProperties";
			
			// xad:QualifyingProperties
			Element qualifyingProperties = createElement(document, "QualifyingProperties", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			qualifyingProperties.setAttributeNS(null, "Target", "#"+signatureId);
			qualifyingProperties.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:"+"xad", "http://uri.etsi.org/01903/v1.3.2#");
			
			// xad:SignedProperties
			signedProperties = createElement(document, "SignedProperties", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			signedProperties.setAttributeNS(null, "Id", signedPropertiesId);
			qualifyingProperties.appendChild(signedProperties);
			
			
			
			// xad:UnsignedProperties
			Element unsignedProperties = createElement(document, "UnsignedProperties", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			qualifyingProperties.appendChild(unsignedProperties);
			DOMStructure qualifyingPropertiesStructure = new DOMStructure(qualifyingProperties);
			XMLObject xadesObject = xmlSignatureFactory.newXMLObject(Collections.singletonList(qualifyingPropertiesStructure), null, null, null);
			objectsList.add(xadesObject);
			
			// xad:SignedSignatureProperties
			Element signedSignatureProperties = createElement(document, "SignedSignatureProperties", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			signedProperties.appendChild(signedSignatureProperties);
			
			// xad:SigningTime, yyyy-MM-dd'T'HH:mm:ssZ
			Element signingTime = createElement(document, "SigningTime", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			Text signingTimeText = document.createTextNode(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(new Date()));
			signingTime.appendChild(signingTimeText);
			signedSignatureProperties.appendChild(signingTime);
			
			// xad:SigningCertificate
			Element signingCertificateElement = createElement(document, "SigningCertificate", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			signedSignatureProperties.appendChild(signingCertificateElement);
			Element cert = createElement(document, "Cert", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			signingCertificateElement.appendChild(cert);
			Element certDigest = createElement(document, "CertDigest", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			cert.appendChild(certDigest);
			Element issuerSerial = createElement(document, "IssuerSerial", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			cert.appendChild(issuerSerial);
			Element digestMethodElement = createElement(document, "DigestMethod", "ds", "http://www.w3.org/2000/09/xmldsig#");
			digestMethodElement.setAttribute("Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
			Element digestValueElement = createElement(document, "DigestValue", "ds", "http://www.w3.org/2000/09/xmldsig#");
			try {
				byte[] hashBytes = Util.digestStream(new ByteArrayInputStream(certificate.getEncoded()));
			} catch (Exception e) {
				e.printStackTrace();
				throw new Exception("unable to compute certificate digest");
			}
			Text digestValueText = document.createTextNode(new String(Base64.encode(hashBytes));
			digestValueElement.appendChild(digestValueText);
			certDigest.appendChild(digestMethodElement);
			certDigest.appendChild(digestValueElement);
			Element x509IssuerName  = createElement(document, "X509IssuerName", "ds", "http://www.w3.org/2000/09/xmldsig#");
			issuerSerial.appendChild(x509IssuerName);
			Text x509IssuerNameText = document.createTextNode(certificate.getSubjectDistinguishedName());
			x509IssuerName.appendChild(x509IssuerNameText);
			Element x509IssuerSerialNumber  = createElement(document, "X509SerialNumber", "ds", "http://www.w3.org/2000/09/xmldsig#");
			issuerSerial.appendChild(x509IssuerSerialNumber);
			Text x509IssuerSerialNumberText = document.createTextNode(certificate.getSerialNumber().toString());
			x509IssuerSerialNumber.appendChild(x509IssuerSerialNumberText);
			
			// xad:SignaturePolicyIdentifier
			Element signaturePolicyIdentifier = createElement(document, "SignaturePolicyIdentifier", "xad", "http://uri.etsi.org/01903/v1.3.2#");
			signedSignatureProperties.appendChild(signaturePolicyIdentifier);
			
			try {
				C14NMethodParameterSpec c14nSpec = null;
				canonicalizationMethod = xmlSignatureFactory.newCanonicalizationMethod("http://www.w3.org/2001/10/xml-exc-c14n#", c14nSpec);
			}  catch (Exception e) {
				e.printStackTrace();
				throw new Exception("a cryptographic algorithm seems unsupported");
			}
			
			String xadesReferenceNodeId = signedPropertiesId + "_Reference";
			Reference xadesReference = xmlSignatureFactory.newReference("#"+signedPropertiesId, xmlSignatureFactory.newDigestMethod("http://www.w3.org/2000/09/xmldsig#sha1", null), Collections.singletonList(canonicalizationMethod), "http://uri.etsi.org/01903/#SignedProperties", xadesReferenceNodeId);
			referencesList.add(xadesReference);

			//
			// Prepare the data
			//
			XMLStructure dataContent = new DOMStructure(data);
		
			//
			// Prepare the transforms
			//
			SignatureMethod signatureMethod;
			C14NMethodParameterSpec c14nSpec = null;
			ArrayList standardTransformList = new ArrayList();
			
			try {
				signatureMethod = xmlSignatureFactory.newSignatureMethod("http://www.w3.org/2000/09/xmldsig#rsa-sha1", null);
				canonicalizationMethod = xmlSignatureFactory.newCanonicalizationMethod("http://www.w3.org/TR/2001/REC-xml-c14n-20010315", c14nSpec);
			}  catch (Exception e) {
				e.printStackTrace();
				throw new Exception("a cryptographic algorithm seems unsupported");
			}
	
			standardTransformList.add(canonicalizationMethod); // always c14n
			
			//
			// Build the data reference & object
			//
			int currentObjectCount = 0;
			String dataObjectNodeId = "";
			String dataReferenceUri = dataObjectNodeId;
			String dataReferenceType = null;
			String dataObjectMimeType = "text/xml";

			// use the signature Id for <ds:object>
			dataObjectNodeId = signatureId + "_D" + currentObjectCount++;
			dataReferenceUri = "#"+dataObjectNodeId;
			String dataReferenceNodeId = dataObjectNodeId + "_Reference";
							
			//
			// Add the data reference & object
			//
			Reference dataReference = xmlSignatureFactory.newReference(dataReferenceUri, xmlSignatureFactory.newDigestMethod("http://www.w3.org/2000/09/xmldsig#sha1", null), standardTransformList, dataReferenceType, dataReferenceNodeId);
			referencesList.add(0, dataReference);
			
			XMLObject dataObject = xmlSignatureFactory.newXMLObject(Collections.singletonList(dataContent), dataObjectNodeId, dataObjectMimeType, null);
			objectsList.add(0, dataObject);
			
			// SignedInfo creation from references
			try {
				canonicalizationMethod = xmlSignatureFactory.newCanonicalizationMethod("http://www.w3.org/2001/10/xml-exc-c14n#", c14nSpec);
			}  catch (Exception e) {
				e.printStackTrace();
				throw new Exception("a cryptographic algorithm seems unsupported");
			}
			SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(canonicalizationMethod, signatureMethod, referencesList);
					
			// KeyInfo creation
			KeyInfoFactory keyInfoFactory = xmlSignatureFactory.getKeyInfoFactory();
			List x509Content = new ArrayList();
			x509Content.add((X509Certificate)certificate);
			X509Data x509Data = keyInfoFactory.newX509Data(x509Content);
			
			KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data));
	
			// Compute signature
			XMLSignature signature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo, objectsList, signatureId, signatureId+"_SV");
			DOMSignContext domSignContext = new DOMSignContext(privateKey, document);
			domSignContext.setDefaultNamespacePrefix("ds");
	
			try {
				signature.sign(domSignContext);
			}
			catch (Exception e) {
				e.printStackTrace();
				throw new Exception("signature failed !");
			}
			
		} catch (Exception e)  {
			e.printStackTrace();
		}
	}
	
	/**
	 * Retrieve a certificate
	 */
	private static void retrieveCertificateAndPrivateKey() {
		// TODO Auto-generated method stub
	}

	/**
	 * Element creation helper
	 */
	protected static Element createElement(Document document, String elementName, String namespacePrefix, String namespaceURI) {
		String finalName = (null==namespacePrefix)?elementName:namespacePrefix+":"+elementName;
		return document.createElementNS(namespaceURI, finalName);
	}
	
	/**
	 * Document creation helper
	 * @throws Exception
	 */
	protected static Document createDocument(InputStream data) throws Exception {
		Document document = null;
		try {
			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
			documentBuilderFactory.setNamespaceAware(true);
			if (null!=data) {
				document = documentBuilderFactory.newDocumentBuilder().parse(data);
			} else {
				document = documentBuilderFactory.newDocumentBuilder().newDocument();
			}
		} catch (Exception e) {
			throw new Exception("unable to create or parse the XML document");
		}
		return document;
	}
}

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

                                    

Comments
EVALUATION

This has been fixed in the Apache Santuario code base. See https://issues.apache.org/bugzilla/show_bug.cgi?id=49692
I will port that fix to the JDK.
                                     
2011-10-20
EVALUATION

The problem is that you are using a DOM API that is not namespace aware: Element.setAttribute. You should always use the DOM APIs that take namespace URIs. Otherwise you may encounter other issues when signing or validating XML signatures. In this particular case, we are able to fix the problem in the implementation.
                                     
2011-10-26
WORK AROUND

Always use the DOM namespace-safe methods. Ex: replace Element.setAttribute() with setAttributeNS:

digestMethodElement.setAttributeNS(XMLSignature.XMLNS, "Algorithm", "http://www.w3.org/2000/09/xmldsig#sha1");
                                     
2011-10-26



Hardware and Software, Engineered to Work Together