import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.Security; import java.security.UnrecoverableEntryException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import javax.xml.crypto.MarshalException; 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.XMLSignatureException; import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.dom.DOMSignContext; import javax.xml.crypto.dsig.dom.DOMValidateContext; 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.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class XmlSigningAndValidate { public void signXml() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyStoreException, UnrecoverableEntryException, CertificateException, IOException, SAXException, ParserConfigurationException, MarshalException, XMLSignatureException, TransformerException { XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA512, null), Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, null); 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. KeyStore ks = KeyStore.getInstance("JKS"); ks.load(new FileInputStream("keystore.jks"), "pushstart".toCharArray()); KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry("nettr", new KeyStore.PasswordProtection("pushstart".toCharArray())); X509Certificate cert = (X509Certificate) keyEntry.getCertificate(); // Create the KeyInfo containing the X509Data. KeyInfoFactory kif = fac.getKeyInfoFactory(); List<Object> x509Content = new ArrayList(); x509Content.add(cert.getSubjectX500Principal().getName()); x509Content.add(cert); X509Data xd = kif.newX509Data(x509Content); 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("purchaseOrder.xml")); // 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); TransformerFactory tf = TransformerFactory.newInstance(); Transformer trans = tf.newTransformer(); trans.transform(new DOMSource(doc), new StreamResult(new FileOutputStream("SignedFile.xml"))); System.out.println("Signed Xml file written : SignedFile.xml"); } public void validateXml() throws Exception { Security.addProvider(new org.apache.jcp.xml.dsig.internal.dom.XMLDSigRI()); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); java.io.ByteArrayInputStream vb = new java.io.ByteArrayInputStream( Files.readAllBytes(new File("SignedFile.xml").toPath())); Document doc2 = dbf.newDocumentBuilder().parse(vb); NodeList nl = doc2.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); if (nl.getLength() == 0) { throw new Exception("Cannot find Signature element"); } XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM", java.security.Security.getProvider("XMLDSig")); // Unmarshal the XMLSignature. // Create a DOMValidateContext and specify a KeySelector and document context. DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(), nl.item(0)); XMLSignature signature = fac.unmarshalXMLSignature(valContext); // Validate the XMLSignature. boolean coreValidity = signature.validate(valContext); // Check core validation status. if (coreValidity == false) { String validateError; validateError = "Signature core validation status:false"; boolean sv = signature.getSignatureValue().validate(valContext); validateError = validateError + " | Signature validation status:" + sv; if (sv == false || true) { validateError = validateError + " | References: "; // Check the validation status of each Reference. @SuppressWarnings("rawtypes") Iterator g = signature.getSignedInfo().getReferences().iterator(); while (g.hasNext()) { 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"); } } public static void main(String[] args) throws Exception { XmlSigningAndValidate xmlSigningAndValidate = new XmlSigningAndValidate(); xmlSigningAndValidate.signXml(); xmlSigningAndValidate.validateXml(); } }
import java.security.Key; import java.security.PublicKey; import java.security.cert.X509Certificate; import java.util.Iterator; import javax.xml.crypto.AlgorithmMethod; import javax.xml.crypto.KeySelector; import javax.xml.crypto.KeySelectorException; import javax.xml.crypto.KeySelectorResult; import javax.xml.crypto.XMLCryptoContext; import javax.xml.crypto.XMLStructure; import javax.xml.crypto.dsig.SignatureMethod; import javax.xml.crypto.dsig.keyinfo.KeyInfo; import javax.xml.crypto.dsig.keyinfo.X509Data; public class X509KeySelector extends KeySelector { public KeySelectorResult select(KeyInfo keyInfo, KeySelector.Purpose purpose, AlgorithmMethod method, XMLCryptoContext context) throws KeySelectorException { @SuppressWarnings("rawtypes") Iterator ki = keyInfo.getContent().iterator(); while (ki.hasNext()) { XMLStructure info = (XMLStructure) ki.next(); if (!(info instanceof X509Data)) continue; X509Data x509Data = (X509Data) info; @SuppressWarnings("rawtypes") Iterator xi = x509Data.getContent().iterator(); while (xi.hasNext()) { Object o = xi.next(); if (!(o instanceof X509Certificate)) continue; final PublicKey key = ((X509Certificate) o).getPublicKey(); // Make sure the algorithm is compatible // with the method. if (algEquals(method.getAlgorithm(), key.getAlgorithm())) { return new KeySelectorResult() { public Key getKey() { return key; } }; } } } throw new KeySelectorException("No key found!"); } boolean algEquals(String algURI, String algName) { return (algName.equalsIgnoreCase("DSA") && algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) || (algName.equalsIgnoreCase("RSA") && algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1)); } }
Complete Sourcecode download here