runeflobakk / xmldsig-problem

Solution to XML signature breaking on Java 11 because DOMException: HIERARCHY_REQUEST_ERR
Do What The F*ck You Want To Public License
0 stars 0 forks source link

org.w3c.dom.DOMException: NAMESPACE_ERR on SIgn #1

Closed ethicalhavoc closed 4 years ago

ethicalhavoc commented 4 years ago

Dear Team

I was getting the "org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR" after upgrading to Java 11 while signing a Document.

After going through the solution you have given, I changed the implementation by giving a New Document instead of the Original Document.

But, Now I am getting the "org.w3c.dom.DOMException: NAMESPACE_ERR" at "signature.sign(dsc)" Line in the below code:

public static String signCbCRDataXML(String filePath) {
        OutputStream os = null;
        try{
            //Fetching the CbCR XML File and storing it in String
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            dbFactory.setNamespaceAware ( false );  
            Document doc = dbFactory.newDocumentBuilder().parse(new FileInputStream(filePath));
            String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");

            XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance());

            // Next, create a Reference to a same-document URI that is an Object element and specify the SHA256 digest algorithm
            DigestMethod digestMethod = fac.newDigestMethod(DigestMethod.SHA256, null);
            Reference reference = fac.newReference("#CBC",digestMethod);
            SignatureMethod signatureMethod = fac.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null);
            CanonicalizationMethod canonicalizationMethod = fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null);

            // Create the SignedInfo
            SignedInfo si = fac.newSignedInfo(canonicalizationMethod, signatureMethod, Collections.singletonList(reference));

            // Create a KeyValue containing the RSA PublicKey that was generated
            KeyInfoFactory kif = fac.getKeyInfoFactory();

            // Set the x509Content from the Petronas Certificate to generate signature
            FileInputStream fin = new FileInputStream(PETRONAS_CERTIFICATE_PATH);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            List x509Content = new ArrayList();
            X509Certificate cert = (X509Certificate)cf.generateCertificate(fin);
            X509IssuerSerial issuer = kif.newX509IssuerSerial(cert.getIssuerDN().toString(), cert.getSerialNumber());
            x509Content.add(cert.getSubjectX500Principal().getName());
            x509Content.add(issuer);
            x509Content.add(cert);
            X509Data xd = kif.newX509Data(x509Content);

            // Create a RSA 2048 KeyPair
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(2048);
            KeyPair kp = kpg.generateKeyPair();
            KeyValue kv = kif.newKeyValue(kp.getPublic());

            XMLStructure content = new DOMStructure(doc.getDocumentElement());
            XMLObject obj = fac.newXMLObject(Collections.singletonList(content), "CBC", null, null);

            // Create a KeyInfo and add the KeyValues to it
            List keyInfoItems = new ArrayList();
            keyInfoItems.add(xd);
            keyInfoItems.add(kv);
            KeyInfo ki = kif.newKeyInfo(keyInfoItems);
            Document signedDocument = dbFactory.newDocumentBuilder().newDocument();
            DOMSignContext dsc = new DOMSignContext(kp.getPrivate(), signedDocument);

            // Create the XMLSignature and sign it
            XMLSignature signature = fac.newXMLSignature(si, ki,Collections.singletonList(obj), null, null);
            signature.sign(dsc);

            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer trans = tf.newTransformer();

            //Storing the Signed XML File in the File system
            os = new FileOutputStream(filePath);
            trans.transform(new DOMSource(signedDocument), new StreamResult(os));
        }
}
runeflobakk commented 4 years ago

I'm afraid I don't know, I don't recognise the error.

There are issues related to the JDK's upgrade of Santuario https://bugs.openjdk.java.net/browse/JDK-8217878. The comments on the issue mention JDK-8218629 XML Digital Signature throws NAMESPACE_ERR exception on OpenJDK 11, works 8/9/10 which seems like it may be what you are experiencing.

Both Santuario and JDK seem to have downgraded the XML marshalling used by Santuario. The last comment requests the fix also to be applied to Java 11, but I am not sure if it has been done.

Which Java 11 version are you using? The last version of the OpenJDK seems to be 11.0.6. If the problem is still present in the latest OpenJDK 11, maybe try Java 14.

If this does not help, maybe you should ask either the developers of Apache Santuario, or the JDK itself.