-1

I need to digitally sign an XML document. The requirement given is that the input is an XML file and a private key. The signing should use SHA256/RSA-2048, and the signature should be Enveloping. I have come up with the following method to do just that. On testing, the KeyPair is generated using KeyPairGenerator class with RSA as algorithm and key size set to 2048. The input stream passed is a FileInputStream object and the output stream is a FileOutputStream object. The method seems to work fine.

public void sign(InputStream inputStream, OutputStream outputStream, KeyPair kp) throws Exception {
    XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

    Reference ref = fac.newReference("#object", fac.newDigestMethod(DigestMethod.SHA256, null));

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    org.w3c.dom.Document doc = dbf.newDocumentBuilder().parse(inputStream);
    XMLStructure content = new DOMStructure(doc.getDocumentElement());
    XMLObject obj = fac.newXMLObject(Collections.singletonList(content), "object", null, null);

    SignatureMethod signatureMethod = fac.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null);
    CanonicalizationMethod canonicalizationMethod = fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec)null);

    SignedInfo si = fac.newSignedInfo(canonicalizationMethod, signatureMethod, Collections.singletonList(ref));

    KeyInfoFactory kif = fac.getKeyInfoFactory();
    KeyValue kv = kif.newKeyValue(kp.getPublic());

    KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

    XMLSignature signature = fac.newXMLSignature(si, ki, Collections.singletonList(obj), null, null);

    DOMSignContext dsc = new DOMSignContext(kp.getPrivate(), doc);

    signature.sign(dsc);

    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer trans = tf.newTransformer();
    trans.transform(new DOMSource(doc), new StreamResult(outputStream));       
}

I have some questions:

  1. I did not specify in the code that RSA should be used in the signing, so how does it know? Also, I understand that in encrypting, there is also mode and padding. Again, these are also not specified, so what would they be?

  2. I don't really know how the canonicalization of the XML work. Both CanonicalizationMethod.INCLUSIVE and CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS produce the same output (both have same DigestValue value). What do these different methods mean?

  3. The enveloped message in the object tag seems to be exactly the same as the input XML file content. Is the enveloped message supposed to be the same as the original XML or is it supposed to be the canonicalized version? I know that the canonicalized version is used in the digest but not sure if the enveloped one should be canonicalized or not. My original XML has comments tag, but the comments tag will always be present in the output, regardless of whether I put INCLUSIVE or INCLUSIVE_WITH_COMMENTS.

  4. Is the public key required at all? The requirement given to me was that the private key is an input, but I am not sure if I should ask about the public key as well. It seems that the public key is required for the KeyValue object.

Thanks in advance.

user3573403
  • 1,780
  • 5
  • 38
  • 64

1 Answers1

0

1) Signature algorithm is inferred from the URI you are using with newSignatureMethod ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")

2) You don't specify any canonicalization algorithm for the Reference in newReference. Hence the default one (Canonical XML without comments) is used before computing the digest value of your XML data. Your canonicalizationMethod is used with SignedInfo: the SignedInfo element will be canonicalized with this algorithm before computing the signature value.

To specify a canonicalization algorithm for the signed XML data, you need to say it when you are creating your Reference:

Transform tr = fac.newTransform(CanonicalizationMethod.INCLUSIVE, (TransformParameterSpec) null);

fac.newReference("#object", fac.newDigestMethod(DigestMethod.SHA256, null), Collections.singletonList(tr), null, null);

This code will add a Transform with the canonicalization algorithm in the Reference referencing the #object that will be hashed.

3) You will have in the Object element the very same content you have added to it. Canonicalization (or any other transform) will be applied on this content before computing the digest value.

4) KeyValue is Optional and is hint for the verifier of the signature. Usual signatures will have the certificate in an X509Certificate instead of the key value.

Hope this helps. Moez

Moez
  • 134
  • 7
  • I don't really understand your answer to (2). Anything wrong with the call to newReference() method? – user3573403 Jan 15 '15 at 07:34
  • If I change the canonicalization algorithm in this line: CanonicalizationMethod canonicalizationMethod = signatureFactory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec)null); I noticed that the DigestValue will still remain the same, but the SignatureValue will change. Why is that so? – user3573403 Jan 15 '15 at 07:39
  • The CanonicalizationMethod specifies a canonicalization algorithm that will be used to canonicalize the SignedInfo before computing the signature value. No impact on the digest value of the XML blob. I added in the answer the way to add a canonicalization algorithm for the XML blob. – Moez Jan 15 '15 at 10:02
  • When we do encryption, we can specify mode and padding. For example, RSA/ECB/PKCS1Padding. For the digital signature, I am using RSA. So is there a default mode and padding already built in? Can we specify the mode and padding? – user3573403 Jan 20 '15 at 12:16
  • Padding and additional parameters are implicit from the URI. The URI http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 refers to RSASSA-PKCS1-v1_5 algorithm described in RFC 3447 (see http://www.w3.org/TR/xmldsig-core1/#sec-PKCS1). – Moez Jan 20 '15 at 13:00
  • Hi, it seems that the digital signing codes do not work on AIX (http://stackoverflow.com/questions/28670003/digital-signing-code-fails-only-on-aix). The JRE is implemented by IBM, and it seems that there is a problem with the DOM. You have any idea? – user3573403 Feb 24 '15 at 07:07