I'm newbie and I'm in a hurry. I'm just trying to digital sign a part of an XML.
The XML to sign is like this:
<?xml version="1.0" encoding="UTF-8"?><ns0:CEE_Adenda xmlns:ns0="http://adenda.es" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://adenda.es Test_v1.xsd">
<ns0:CEE version="1.0" xmlns:ns0="http://adenda.es">//XML to sing
............
</ns0:CEE>
<ns0:Adenda> //Part to exclude
......
</ns0:Adenda>
</ns0:CEE_Adenda>
, in order to get an structure like this:
<?xml version="1.0" encoding="UTF-8"?><ns0:CEE_Adenda xmlns:ns0="http://adenda.es" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://adenda.es Test_v1.xsd">
<ns0:CEE version="1.0" xmlns:ns0="http://adenda.es">//XML to sing
............
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>vMg+tzKiwC8epApusLGo23at0ss=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>dVqqHp437r7jAeEOB6mxgSOKnpT6EITRscd0mzA/zDep3Wkg1CM/m0ojDHnlkC7l
</ns0:CEE>
<ns0:Adenda> //Part to exclude
......
</ns0:Adenda>
</ns0:CEE_Adenda>
This is the code I'm using to try to sign it, but I need to sign only the part of XML and put the result inside this tag.
This is the code I'm using:
//Create a DOM XMLSignatureFactory that will be used to
// generate the enveloped signature.
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
// Create a Reference to the enveloped document (in this case,
// you are signing the whole document, so a URI of "" signifies
// that, and also specify the SHA1 digest algorithm and
// the ENVELOPED Transform.
try {
List<XPathType> xpaths = new ArrayList<XPathType>();
xpaths.add(new XPathType("//ns0:CFE", XPathType.Filter.INTERSECT));
Reference ref = fac.newReference("",
fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList(fac.newTransform(Transform.ENVELOPED,
(TransformParameterSpec) null)),null,null);
//ori
//Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null));
// Create the SignedInfo
SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec)null),
fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
// Load the KeyStore and get the signing key and certificate.
String p12Password = clave;
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream(keyStoreName), p12Password.toCharArray());
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry)ks.getEntry(alias,
new KeyStore.PasswordProtection(p12Password.toCharArray()));
X509Certificate cert = (X509Certificate)keyEntry.getCertificate();
// Create the KeyInfo containing the X509Data.
KeyInfoFactory kif = fac.getKeyInfoFactory();
List<Serializable> x509Content = new ArrayList<Serializable>();
x509Content.add(cert.getSubjectX500Principal().getName());
x509Content.add(cert);
X509Data xd = kif.newX509Data(x509Content);
javax.xml.crypto.dsig.keyinfo.KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
// Instantiate the document to be signed.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(new FileInputStream(xmlEntrada));
// Create a DOMSignContext and specify the RSA PrivateKey and
// location of the resulting XMLSignature's parent element.
DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement());
// Create the XMLSignature, but don't sign it yet.
XMLSignature signature = fac.newXMLSignature(si, ki);
// Marshal, generate, and sign the enveloped signature.
signature.sign(dsc);
// Output the resulting document.
OutputStream os = new FileOutputStream(xmlSalida);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(os));
Any help will be very appreciated.
Regards
It's probably too late for you but if it can help anybody, here is the code I finally used to sign a SAML Assertion where the signature must be applied only on a part of my XML Document. My first tests was done with org.apache.xml.security but I did not find how to sign just a part of the my XML DOM. Finally I found an other way to sign XML using the Java XML Digital Signature API: http://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html
Please note that I'm not a Java Developer. So the code here-under can surely be improved.
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
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.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/*
* This Class contains method to sign SAML assertion.
*/
public class SAMLSigner {
// Sign an Assertion using the Private Key & Public Certificate from a KeyStore.
public static Document signAssertion(Document doc, SAMLKeyStore samlKeyStore) throws Exception {
// Instance main XML Signature Toolkit.
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
XPathFactory xPathfactory = XPathFactory.newInstance();
// Retreive PrivateKey and Public Certificate from Specified KeyStore.
PrivateKey privateKey = samlKeyStore.getPrivateKey();
X509Certificate publicCertificate = samlKeyStore.getPublicCertificate();
// Retreive Assertion Node to be signed.
XPath xpath = xPathfactory.newXPath();
XPathExpression exprAssertion = xpath.compile("//*[local-name()='Response']//*[local-name()='Assertion']");
Element assertionNode = (Element) exprAssertion.evaluate(doc, XPathConstants.NODE);
// Must mark ID Atrribute as XML ID to avoid BUG in Java 1.7.25.
assertionNode.setIdAttribute("ID", true);
// Retreive Assertion ID because it is used in the URI attribute of the signature.
XPathExpression exprAssertionID = xpath.compile("//*[local-name()='Response']//*[local-name()='Assertion']//@ID");
String assertionID = (String) exprAssertionID.evaluate(doc, XPathConstants.STRING);
// Retreive Subject Node because the signature will be inserted before.
XPathExpression exprAssertionSubject = xpath.compile("//*[local-name()='Response']//*[local-name()='Assertion']//*[local-name()='Subject']");
Node insertionNode = (Node) exprAssertionSubject.evaluate(doc, XPathConstants.NODE);
// Create the DOMSignContext by specifying the signing informations: Private Key, Node to be signed, Where to insert the Signature.
DOMSignContext dsc = new DOMSignContext(privateKey, assertionNode, insertionNode);
dsc.setDefaultNamespacePrefix("ds");
// Create a CanonicalizationMethod which specify how the XML will be canonicalized before signed.
CanonicalizationMethod canonicalizationMethod = fac.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null);
// Create a SignatureMethod which specify how the XML will be signed.
SignatureMethod signatureMethod = fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
// Create an Array of Transform, add it one Transform which specify the Signature ENVELOPED method.
List<Transform> transformList = new ArrayList<Transform>(1);
transformList.add(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null));
// Create a Reference which contain: An URI to the Assertion ID, the Digest Method and the Transform List which specify the Signature ENVELOPED method.
Reference reference = fac.newReference("#" + assertionID, fac.newDigestMethod(DigestMethod.SHA1, null), transformList, null, null);
List<Reference> referenceList = Collections.singletonList(reference);
// Create a SignedInfo with the pre-specified: Canonicalization Method, Signature Method and List of References.
SignedInfo si = fac.newSignedInfo(canonicalizationMethod, signatureMethod, referenceList);
// Create a new KeyInfo and add it the Public Certificate.
KeyInfoFactory kif = fac.getKeyInfoFactory();
List x509Content = new ArrayList();
x509Content.add(publicCertificate);
X509Data xd = kif.newX509Data(x509Content);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
// Create a new XML Signature with the pre-created : Signed Info & Key Info
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
// Return the Signed Assertion.
return doc;
}
}
My XML before signing.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://tmoobiee11gv9.kitrybe.dyndns.org:9704/saml2/sp/acs/post" ID="_0f3f5675-7a3a-4659-be6d-d3cdb0923fc2" IssueInstant="2016-10-19T12:43:40Z" Version="2.0">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">MyIssuer</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_9990f3f5675-7a3a-4659-be6d-d3cdb0923fc2" IssueInstant="2016-10-19T12:43:40Z" Version="2.0">
<saml:Issuer>MyIssuer</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">MyUser</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2016-10-19T12:53:40Z" Recipient="http://tmoobiee11gv9.kitrybe.dyndns.org:9704/saml2/sp/acs/post"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2016-10-19T12:33:40Z" NotOnOrAfter="2016-10-19T12:53:40Z">
<saml:AudienceRestriction>
<saml:Audience>MyAudience</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2016-10-19T12:43:40Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
</saml:Assertion>
</samlp:Response>
Here is the XML after signing.
> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
> <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://tmoobiee11gv9.kitrybe.dyndns.org:9704/saml2/sp/acs/post"
> ID="_0f3f5675-7a3a-4659-be6d-d3cdb0923fc2"
> IssueInstant="2016-10-19T12:43:40Z" Version="2.0">
> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">MyIssuer</saml:Issuer>
> <samlp:Status>
> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
> </samlp:Status>
> <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
> ID="_9990f3f5675-7a3a-4659-be6d-d3cdb0923fc2"
> IssueInstant="2016-10-19T12:43:40Z" Version="2.0">
> <saml:Issuer>MyIssuer</saml:Issuer>
> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
> <ds:SignedInfo>
> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
> <ds:Reference URI="#_9990f3f5675-7a3a-4659-be6d-d3cdb0923fc2">
> <ds:Transforms>
> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
> </ds:Transforms>
> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
> <ds:DigestValue>8uL7NzYK...</ds:DigestValue>
> </ds:Reference>
> </ds:SignedInfo>
> <ds:SignatureValue>BRsAX3XPvFcDw1...</ds:SignatureValue>
> <ds:KeyInfo>
> <ds:X509Data>
> <ds:X509Certificate>MIICvzCCAae...</ds:X509Certificate>
> </ds:X509Data>
> </ds:KeyInfo>
> </ds:Signature>
> <saml:Subject>
> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">MyUser</saml:NameID>
> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
> <saml:SubjectConfirmationData NotOnOrAfter="2016-10-19T12:53:40Z"
> Recipient="http://tmoobiee11gv9.kitrybe.dyndns.org:9704/saml2/sp/acs/post"/>
> </saml:SubjectConfirmation>
> </saml:Subject>
> <saml:Conditions NotBefore="2016-10-19T12:33:40Z" NotOnOrAfter="2016-10-19T12:53:40Z">
> <saml:AudienceRestriction>
> <saml:Audience>MyAudience</saml:Audience>
> </saml:AudienceRestriction>
> </saml:Conditions>
> <saml:AuthnStatement AuthnInstant="2016-10-19T12:43:40Z">
> <saml:AuthnContext>
> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
> </saml:AuthnContext>
> </saml:AuthnStatement>
> </saml:Assertion>
> </samlp:Response>
The signature only applied on Assertion Tag and is placed before the Subject Tag.
Hope it will help.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With