The existing Apache Santuario - XML Security for Java implementation is DOM-based. What this essentially means is that the complete XML Document must be read into memory before being signed or verified. For large XML Documents this carries a corresponding performance penalty. In addition, it means that XML Signature is not feasible for very large documents. In contrast, the StAX API uses a streaming approach, resulting in very low memory usage.
The streaming XML/WS-Security functionality is split between the Apache Santuario and WSS4J projects. The Apache Santuario project contains the core streaming capabilities for XML Signature and Encryption. The Apache WSS4J project builds on this functionality to deliver a streaming WS-Security stack. The entire streaming security functionality is the work of Marc Giger, who donated his SWSSF project to Apache. Marc has done an outstanding job to implement this technically difficult task, and also to integrate the functionality into existing Apache projects. If you wish to experiment with the new functionality, it is available via the 2.0.0-rc1 release.
1) XML Signature test-cases
In this post we will focus on XML Signature only. I have uploaded some test-cases to github to show how to use the new StAX-based API. There are currently three junit tests in this project:
- SignatureDOMTest - Sign + verify using the (older) DOM API
- SignatureStAXTest - Sign + verify using the new StAX API
- SignatureInteropTest - Test interop between the two implementations
To see how to configure the new outbound StAX-based XML Signature functionality, take a look at the "signUsingStAX" method used by the tests. The streaming XML Security functionality is configured by populating a XMLSecurityProperties Object. You must typically call the following methods:
- properties.setAction(XMLSecurityConstants.Action) - an "Action" to perform, which for XML Signature purposes is XMLSecurityConstants.SIGNATURE.
- properties.setSignatureKey(Key) - The signing key. Can be a PrivateKey or SecretKey.
- properties.setSigningCerts(X509Certificate[]) - The signing certs. May be inserted into the Signature KeyInfo depending on the Signature KeyIdentifier.
- properties.addSignaturePart(SecurePart) - Add a SecurePart to sign, e.g. sign a given QName. You can also specify a digest method or transform algorithm here. You can also sign the entire request via SecurePart.setSecureEntireRequest(boolean).
- properties.setSignatureAlgorithm(String) - Signature Algorithm to use. The default depends on the signing key.
- properties.setSignatureDigestAlgorithm(String) - Signature Digest Algorithm to use. The default is the URI for SHA-1.
- properties.setSignatureCanonicalizationAlgorithm(String) - The canonicalization algorithm to use. The default is XMLSecurityConstants.NS_C14N_EXCL_OMIT_COMMENTS.
- properties.setSignatureKeyIdentifier(SecurityTokenConstants.KeyIdentifier) - How to reference the signing key/cert. The default is SecurityTokenConstants.KeyIdentifier_IssuerSerial.
- SecurityTokenConstants.KeyIdentifier_KeyValue
- SecurityTokenConstants.KeyIdentifier_KeyName
- SecurityTokenConstants.KeyIdentifier_IssuerSerial
- SecurityTokenConstants.KeyIdentifier_SkiKeyIdentifier
- SecurityTokenConstants.KeyIdentifier_X509KeyIdentifier
- SecurityTokenConstants.KeyIdentifier_X509SubjectName
- SecurityTokenConstants.KeyIdentifier_NoKeyInfo
3) Inbound StAX configuration
To see how to configure the new inbound StAX-based XML Signature functionality, take a look at the "verifyUsingStAX" method used by the tests. As with signature creation, it is necessary to create a XMLSecurityProperties Object, and to tell it what "Action" to perform. In addition you must call the following method, unless the complete signing key is contained in the Signature KeyInfo:
- properties.setSignatureVerificationKey(Key) - a key to use to verify the Signature.
Hello,
ReplyDeleteI'm trying to prove the signature verification with StAX.
In my case if I change the content of XML after the signature has not reported any problems. It should return an error indicating that the document is invalid.
How I can check if the content has been modified after signing and get the error?
Thank you very much
How are you modifying the signature? Do you have a test-case?
ReplyDeleteColm.
Hello,
DeleteWhere I can send the xml to test?
You could create a github project + mail a link to it here. Alternatively send it to the CXF user list.
ReplyDeleteColm.
or you can try to document.getDocumentElement().getFirstChild().setNodeValue("NODE MODIFIED"); after the signature
ReplyDelete
ReplyDeleteThat is just changing the value of the first node. If you look at the test-case, it is signing the "PaymentInfo" node. Hence changing the value of the first node does not affect signature verification.
Colm.
I want to check signature integrity: the content hash vs signatureValue hash.
DeleteXml signature is not only to know the identy of signer, you have to know if document is not manipulated after has signed.
Yes, but I am telling you that changing the first node does not affect digest calculation, as that node is not included in the signature. If the example signed the entire document, and the modification was made, then signature validation would fail.
DeleteColm.
This comment has been removed by the author.
ReplyDeleteI have the next example: ....
ReplyDeleteAfter signature I have changed data of Person.
The same invalid XML with SignatureDomTest:
oct 16, 2014 1:54:28 PM org.apache.xml.security.signature.Reference verify
Advertencia: Verification failed for URI ""
oct 16, 2014 1:54:28 PM org.apache.xml.security.signature.Reference verify
Advertencia: Expected Digest: Oyyx+K28+cp7kuUgcnANtTBdUwg=
oct 16, 2014 1:54:28 PM org.apache.xml.security.signature.Reference verify
Advertencia: Actual Digest: lE7NVwAKFheZoXEVLdxJXLWSY28=
With SignatureStAXTest is not reporting any error.
How are you changing the XML for the SignatureStAXTest though? It doesn't use DOM between signing +verifying, so if you are changing the DOM here it has no effect.
DeleteColm.
I have xml file in resources with data modified.
ReplyDeleteI has commented the signature part SignatureUtils.signUsingStAX or DOM
In other words I have declared inputstream with xml modified and call SignatureUtils.verifyUsingStAX() or SignatureUtils.verifyUsingDOM()
The same document with StAX is not reporting errors and with DOM is reporting Verification failed
Could you create a pull request for the project on github that reproduces the problem, + I will take a look?
ReplyDeleteColm.
Hi, I have created fork for Digest Value Test
ReplyDeleteAny news???
ReplyDeleteWorking on it. Can you give me an email address to contact you at privately?
ReplyDeleteColm.
This comment has been removed by the author.
ReplyDeleteI need to sign a xml document provided by a customer. How can I using the stax api to sign a full xml file and add the signature at the end? How can I changed the element dsig:Signature to a ds:Signature element?
ReplyDeleteYou can customize where the Signature is added via the following: https://issues.apache.org/jira/browse/SANTUARIO-405 - this has not yet been released though. For now, the prefix is hard-coded to "dsig". Please raise a JIRA if you want to be able to change it.
ReplyDeleteColm.
With this version I`ve two issues.
ReplyDeleteStax signer
- When I set XMLSecurityProperties.setSignaturePosition(1); no signature is being written, with "0" the signature is written on the top of the file.
Dom Verify
- With this new version 2.0.3 I`m getting an exception, it was working with 2.0.2, but I need the RSA-PSS algorithm support, therefore I want to upgrade
Caused by: org.apache.xml.security.exceptions.XMLSecurityException: Invalid digest of reference #ID_097f0764-9f73-4fb2-b2e0-7de370930288
Another question is, why does that code:
ReplyDeleteString id = "ID_" + UUID.randomUUID().toString();
elementToSign.setAttributeNS(null, "Id", id);
elementToSign.setIdAttributeNS(null, "Id", true);
transforms = new Transforms(document);
transforms
.addTransform("http://www.w3.org/2001/10/xml-exc-c14n#");
xmlSignature.addDocument("#" + id, transforms,
"http://www.w3.org/2000/09/xmldsig#sha1");
set the id on the top of the xml document and also to the reference field?
Is that a correct behaviour?
I tried to make a signature on root element (PurchaseOrder), and then a verification.
ReplyDeleteBut signature verification failed :(
I have just replaced this line :
namesToSign.add(new QName("urn:example:po", "PaymentInfo"));
by :
namesToSign.add(new QName("urn:example:po", "PurchaseOrder"));
And it raises this error :
org.apache.xml.security.exceptions.XMLSecurityException: Invalid digest of reference #G33e45112-ac8f-4ed2-9da9-12c5af4a782e
I think that, when computing document digest, it doesn't remove "Signature" node.
Can you say what to change to make a "root element signature verification" ?
You need to use an "enveloped signature transform" when you are signing the root node, and including the Signature inside the root node (as the test-case is doing). This tells the validation code not to include the Signature in the digest calculation.
ReplyDeleteSo for the DOM code in the test-case, add the following line in SignatureUtils.signUsingDOM:
transforms.addTransform("http://www.w3.org/2000/09/xmldsig#enveloped-signature");
For the streaming code in SignatureUtils.signUsingStAX:
String[] transforms = new String[2];
transforms[0] = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
transforms[1] = "http://www.w3.org/2001/10/xml-exc-c14n#";
securePart.setTransforms(transforms);
Colm.
Hi,
ReplyDeleteI've tested what you say, and it works great !
Thank you very much !
Hi,
ReplyDeleteAt first thanks for the helpful test examples.
I am not sure If the signature transform is the "thing" I am looking for.
I have to nest the signature inside of the paymentInfo element as child. Is this somehow possible with santuario?
Best Regards
Yes, see the enveloped signature transform comment above.
ReplyDeleteColm.
Hi Colm,
Deletethe transform doesn't have any effect on the Data. The only thing I see are some extra Debug lines in the logs.
I am adding the transform by:
SecurePart securePart = new SecurePart(namesToSign.get(0),
SecurePart.Modifier.Content);
String[] transforms = new String[2];
transforms[0] = "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
transforms[1] = "http://www.w3.org/2001/10/xml-exc-c14n#";
securePart.setTransforms(transforms);
Best Regards
I am using the STAX-API btw.
DeleteI furthermore realized that there is put an ID field in the Tag .
ReplyDeleteIs it somehow possible to avoid? Since the server I am communicating with, isn't able to handle this.
Hi,
ReplyDeleteIs it possible to validate a XML with 2 signature with the Stax API ?
By my side, I got a stack trace...
To reproduce :
- take the Stax example(SignatureStAXTest)
- generate a 2nd keypair, and a new signature on the document (new key ID, new key pair)
- re run the test
java.lang.NullPointerException
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:386)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:374)
at org.apache.xml.security.stax.ext.AbstractInputSecurityHeaderHandler.parseStructure(AbstractInputSecurityHeaderHandler.java:46)
at org.apache.xml.security.stax.impl.processor.input.AbstractSignatureInputHandler.handle(AbstractSignatureInputHandler.java:58)
at org.apache.xml.security.stax.impl.processor.input.XMLSecurityInputProcessor.processNextEvent(XMLSecurityInputProcessor.java:129)
at org.apache.xml.security.stax.impl.InputProcessorChainImpl.processEvent(InputProcessorChainImpl.java:193)
at org.apache.xml.security.stax.impl.XMLSecurityStreamReader.next(XMLSecurityStreamReader.java:78)
at com.diehl.metering.izar.com.lib.security.XadesManager.verifyUsingStAX(XadesManager.java:261)
...
:-(
Could you submit a pull request for the code in github with your change + I'll take a look?
ReplyDeleteThe patch is quiet simple :
ReplyDeletediff --git a/apache/santuario/santuario-xml-signature/src/test/java/org/apache/coheigea/santuario/xmlsignature/SignatureStAXTest.java b/apache/santuario/santuario-xml-signature/src/test/java/org/apache/coheigea/santuario/xmlsignature/SignatureStAXTest.java
index 220a9ef..7515dd0 100644
--- a/apache/santuario/santuario-xml-signature/src/test/java/org/apache/coheigea/santuario/xmlsignature/SignatureStAXTest.java
+++ b/apache/santuario/santuario-xml-signature/src/test/java/org/apache/coheigea/santuario/xmlsignature/SignatureStAXTest.java
@@ -58,9 +58,19 @@
sourceDocument, namesToSign, "http://www.w3.org/2000/09/xmldsig#rsa-sha1", key, cert
);
+ // Sign using StAX
+ InputStream sourceDocument2 = new ByteArrayInputStream(baos.toByteArray());
+ List namesToSign2 = new ArrayList();
+ namesToSign2.add(new QName("urn:example:po", "PaymentInfo"));
+ ByteArrayOutputStream baos2 = SignatureUtils.signUsingStAX(
+ sourceDocument2, namesToSign2, "http://www.w3.org/2000/09/xmldsig#rsa-sha1", key, cert
+ );
+
+ System.out.println(new String(baos2.toByteArray()));
+
// Verify using StAX
SignatureUtils.verifyUsingStAX(
- new ByteArrayInputStream(baos.toByteArray()), namesToSign, cert);
+ new ByteArrayInputStream(baos2.toByteArray()), namesToSign2, cert);
}
I already tried with 2 keys / certificats... same problem : NPE in the StAX parser. The processing of the second is in error.
My usecase :
- a client generate a XML file (after GZ 50 MB)
- the client sign the content
- the client send the file to the server
- the server check the signature
- the server generate a timestamp a sign the XML with the timestamp in the metadata
- the server archivate the XML (with the 2 signature and the timestamp)
And now, I want the check the content of the archive !
-> with DOM : Ok
-> with StAX : Ko
Can someone reproduce ?
ReplyDeleteYes I can reproduce. I raised the following JIRA:
ReplyDeletehttps://issues.apache.org/jira/browse/SANTUARIO-424
Colm.
This comment has been removed by a blog administrator.
ReplyDeleteFirst many thanks for the sample programmes, without which it is really hard to put all the pieces together from reading the Javadoc.
ReplyDeleteRegarding the EncryptionStAXtest, I have two questions:
1. Does StAX API supports multiple recipients? i.e. Can I add more than one properties.setEncryptionTransportKey (wrappingKeyX)
2. I have a use case, where I have to encrypt an arbitrary (big) data file and
have it enveloped in as CipherValue (not CipherReference) in EncryptedData. What are the XMLSecruityProperties value to apply?
It cannot be SecurePart I presume. (There is no input XML file)
Setting more than one key transport key is not supported. Please feel free to submit a JIRA for the Santuario project for this if if it something you'd like to see supported.
ReplyDeleteI'm not sure I understand you're second point. If it is not XML then what format is it?
Colm.
Thansk for the quick reply.
Delete1. It mean the actual Santuario StAX API does not support multi-recipeints for Encryption. right. Then does its counterpart Santuario DOM API do it ?
2.Let me put it in another way. Suppose I get a XML element whose content (to be encrypted) comes from a external file. Is there any way in Santuario API to indicate it via XmlSecurityProperties ?
1) Yes. See this test I just added: http://svn.apache.org/viewvc?view=revision&revision=1697004
Delete2) I don't follow you. The EncryptionStAXTest does exactly that - it reads in an XML Document "plaintext.xml" and encrypts it using a streaming approach. SecurePart just refers to the QName of the Element to encrypt in the stream/document.
Thank you for the new example.
DeleteI got two questions on XMLSecurityProperties class.
1. In case of KeyIdentifier.KeyName used, how can I set a value for the "keyname" value for the generated EncryptedKey?
2. The field "EncryptionUseThisCertificate" is for transport Key encryption or for Data encryption ? If it is for Transport key, then will the EncryptionTransportKey ignored in case both are given ?
Please ask any future questions on the Apache Santuario mailing lists...
Delete1) You can't - it's not supported at the moment. Feel free to create a JIRA for this.
2) It's for key transport. The EncryptionTransportKey is used if it is specified, otherwise it falls back to the Cert. The Cert is required if you are using a key referencing mechanism such as IssuerSerial.
Colm.
This comment has been removed by the author.
ReplyDeleteI was hoping for a performance boost when signing with the Stax method vs using DOM but found no such difference. Should not the Stax method perform better?
ReplyDeleteThis was done using Santuario 2.0.5
I reached the same conclusion, the CPU-usage performance is the same in DOM and Stax
DeleteSee here:
ReplyDeletehttp://coheigea.blogspot.ie/2014/04/apache-santuario-xml-security-for-java_25.html
Do you have any solution for android xml digital signature?
ReplyDeleteHi,
ReplyDeleteI found that the StAX signing always sign the xml by Id even for entire document. However, according to XML digital signature, for the whole xml signing, the reference URI can be "".
Could StAX be set to sign the entire document without adding Id attribute? As my existing XML schema doesn't support any Id attribute.
Thanks a lot.
No, but there's a patch being reviewed at the moment to support this: https://issues.apache.org/jira/browse/SANTUARIO-458
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHi sir,
ReplyDeleteAny idea, pointers, how we can inject the "Signature" part via StAX streaming API into an arbitrary xml tag ? So not as a child from the root tag, but more down deep ? I played with the signaturePosition attribute, but no luck here....
You can either use signaturePosition or else the new "signaturePositionQName" which will be available in the next Santuario release (currently under vote):
Deletehttps://issues.apache.org/jira/browse/SANTUARIO-468
Can you elaborate how the streaming API works in terms of caching and memory usage, if the entire XML is signed (enveloped mode). How is the part of the XML after the "Signature" part handled while canonicalizing/transforming/digestCalculation ?
ReplyDeleteSuppose, you have a big XML file, where the "Signature" part is in the header ?
Regards, Bert.
Colm
ReplyDeleteWe're using Santuario 2.1.1 canonicalise, digest and then encode an XML signature as part of a non-repudiation service. However we're finding that any document >4MB has sever performance issues when calling performTransforms. By severe, think hours taken to do a transform! Do you have any thoughts or pointers as to what could be the issue?
No, could you create a JIRA here and attach a test-case to reproduce the issue? https://issues.apache.org/jira/projects/SANTUARIO. Have you tried with the streaming implementation - it might give better performance?
DeleteHi Stax team..
ReplyDeleteMy problem is to decipher some xml fields wihtout specifying the list of them but based on the xsd type : "xenc:EncryptedDataType"
Is it possible ?