24

I am getting the error given below when parsing the signature. Anybody has idea why the error is showing?

Note that:

  1. Using the same certificate I signed my own XML and verified which is working fine. That mean there is no issue with certificate.

  2. Client provided signed document not able to validate.

Errors:

Exception in thread "main" javax.xml.crypto.MarshalException: Cannot create X509Certificate
at org.jcp.xml.dsig.internal.dom.DOMX509Data.unmarshalX509Certificate(DOMX509Data.java:225)
at org.jcp.xml.dsig.internal.dom.DOMX509Data.<init>(DOMX509Data.java:116)
at org.jcp.xml.dsig.internal.dom.DOMKeyInfo.<init>(DOMKeyInfo.java:116)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.<init>(DOMXMLSignature.java:150)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshal(DOMXMLSignatureFactory.java:173)
at org.jcp.xml.dsig.internal.dom.DOMXMLSignatureFactory.unmarshalXMLSignature(DOMXMLSignatureFactory.java:137)
at com.signing.ValidateSignedXML.main(ValidateSignedXML.java:126)
Caused by: java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: Empty input
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:104)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:339)
at org.jcp.xml.dsig.internal.dom.DOMX509Data.unmarshalX509Certificate(DOMX509Data.java:223)
... 6 more
Caused by: java.io.IOException: Empty input
at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:101)

Adding the code here for reference

package com.signing;

import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.Iterator;

import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class ValidateSignedXML {

    /**
     * @param args
     * @throws Exception 
     */
/**
     * @param args
     * @throws Exception 
     */
    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub

        // Load the KeyStore and get the signing key and certificate.
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream("C:\\Program Files\\Java\\jre1.8.0_31\\bin\\newstore8.jks"), "changeit7".toCharArray());


        KeyStore.PrivateKeyEntry keyEntry =
            (KeyStore.PrivateKeyEntry) ks.getEntry
                ("newkey8", new KeyStore.PasswordProtection("changeit7".toCharArray()));
        X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");


        //Load the signed document.
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = dbf.newDocumentBuilder().parse
            (new FileInputStream("C:\\src\\com\\signing\\signed.xml"));


        // Find Signature element.
        NodeList nl =
            doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
        if (nl.getLength() == 0) {
            throw new Exception("Cannot find Signature element");
        }else{
            /*System.out.println("---- Start of Print Tag ----\n");
            for(int k=0;k<nl.getLength();k++){
                 printTags((Node)nl.item(k));
             }
            System.out.println("---- End of Print Tag ----\n");*/
        }

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

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

        // Validate the XMLSignature.
        boolean coreValidity = signatures.validate(valContext);

        System.out.println("Signature Validate :"+coreValidity);

        // Check core validation status.
        if (coreValidity == false) {
            String validateError;
            validateError = "Signature core validation status:false";
            boolean sv = signatures.getSignatureValue().validate(valContext);
            validateError = validateError + " | Signature validation status:" + sv;
            if (sv == false || true) {
                validateError = validateError + " | References: ";
                // Check the validation status of each Reference.
                Iterator g = signatures.getSignedInfo().getReferences().iterator();
                for (int j = 0; g.hasNext(); j++) {

                    Reference r = (Reference) g.next();
                    boolean refValid = r.validate(valContext);
                    validateError = validateError + "{ref[" + r.getURI() + "] validity status: " + refValid + "}";
                }
            }
            throw new Exception(validateError);
        } else {
            System.out.println("Signature passed core validation");
        }

    }

}
4
  • Thanks for replying,Yes I added the code in question itself. Its failing when unmarshal happening only for client signed xml.But if I use any unsigned xml file with same certificate,do sign and validate it is giving above error. Commented Jul 7, 2015 at 19:43
  • look [here][1] [1]: stackoverflow.com/questions/10594000/… I think it will solve your problem. Commented Jul 7, 2015 at 19:50
  • 1.Thanks for replying but it's related with SSL connection which I doesnt need,2.This is earlier comment edit "But if I use any unsigned xml file with same certificate,do sign and validate it is working." typo issue. Commented Jul 7, 2015 at 19:57
  • The certificate is empty in the XML. What's does the XML look like? How was it created? Commented Mar 11, 2020 at 0:35

5 Answers 5

34

It's been a while since this post but I came here looking for this issue. In my case, the key was that the certificate was in a Base64-String.getBytes[] instead of a DECODED-Base64-String.getBytes[].

Hope it helps someone :)

Sign up to request clarification or add additional context in comments.

3 Comments

Hi, can you clarify this a bit more?
Yeah, sure! The issue in my case was that I was trying to parse to a X509Certificate from a String that it wasn't a X509Certificate. It was a Base64 string that contains the data of the certificate so in order to parse it, I had to decode the string previously and then parse it to a X509.
To clarify this further, I used Base64.getDecoder().decode(certString) successfully when I got this error message.
6

Error can be as simple as not having the BEGIN and END tags in your certificate set.

-----BEGIN CERTIFICATE-----
your cert data here
-----END CERTIFICATE-----

Comments

2

After going through so many blogs nothing helped as such. Finally we confirmed the way client is doing his encryption and used the same jars used for our verification. I am not sure if this is correct answer or not but may help somebody who is trying hard to resolve this issue. It may give you some clue if not able to resolve above error after going through many sites. So try to use same jars which used for client encryption and get the compatible private key for your public key and add to pk12 file. Convert pk12 to jks which you can use for encryption and verification too which resolved our issue. Some process too

#**Create PKCS12 keystore from private key and public certificate.**
openssl pkcs12 -export -name myservercert -in selfsigned.crt -inkey server.key -out keystore.p12
#**Convert PKCS12 keystore into a JKS keystore**
keytool -importkeystore -destkeystore mykeystore.jks -srckeystore keystore.p12 -srcstoretype pkcs12 -alias myservercer

Good luck guys.

1 Comment

None of this addresses an empty certificate in the XML.
0

In my case, the x509 certificate in java String was one liner as below:

String x509Cert = "-----BEGIN CERTIFICATE-----<cert-data>-----END CERTIFICATE-----";

I had to create expected String by adding \r a carriage return and \n a line feed character for begin & end certs, like below:

"-----BEGIN CERTIFICATE-----\r\n<cert-data>\r\n-----END CERTIFICATE-----";

Psuedo Code:

1. Get cert data substring between -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----.

2. Create String by adding System.lineSeparator() such that
a. -----BEGINE CERTIFICATE-----
b. System.lineSeparator()
c. cert data from pt 1.
d. System.lineSeparator()
e. -----END CERTIFICATE-----

Comments

-3

The error occurs when the content of the certificate is not correct. Reference: enter link description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.