Java equivalente di C # metodo per la firma XML
-
26-10-2019 - |
Domanda
ho scritto il seguente .NET Framework metodo 3.5 C # che prende la posizione di un documento XML e una rappresentazione oggetto di un certificato digitale X509 (con una chiave privata) e restituisce il documento XML come un oggetto con il XML Signature ( XMLDSIG) incorporato come primo elemento figlio della radice.
Il fatto è che ho terribilmente bisogno di essere in grado di fare la stessa procedura esatta con Java SE 6, ma non ho scritto alcun Java in epoche e non hai idea da dove cominciare.
Qualcuno può fornire il metodo equivalente in codice Java che produce il esattamente stesso output XML?
private static XmlDocument SignXmlDocument(string xmlFilePath, X509Certificate2 certificate)
{
// load xml from disk preserving whitespaces
XmlDocument xmlDocument = new XmlDocument { PreserveWhitespace = true };
xmlDocument.Load(xmlFilePath);
// create signed xml with a same-document reference containing an enveloped-signature transform
SignedXml signedXml = new SignedXml(xmlDocument) { SigningKey = certificate.PrivateKey };
Reference reference = new Reference { Uri = "" };
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
signedXml.AddReference(reference);
// embed public key information for signature validation purposes
KeyInfo keyInfo = new KeyInfo();
KeyInfoX509Data keyInfoX509Data = new KeyInfoX509Data(certificate, X509IncludeOption.ExcludeRoot);
keyInfo.AddClause(keyInfoX509Data);
signedXml.KeyInfo = keyInfo;
// compute and retreive the signature xml
signedXml.ComputeSignature();
XmlElement xmldsigXmlElement = signedXml.GetXml();
// insert the signature xml into the xml document as first child of the root element
xmlDocument.DocumentElement.PrependChild(xmlDocument.ImportNode(xmldsigXmlElement, true));
return xmlDocument;
}
Soluzione
Di seguito fa la stessa cosa in Java. Si richiede un file di certificato PKCS12 sul disco.
import java.util.*;
import java.io.*;
import java.security.KeyStore;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.cert.X509Certificate;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
public class XMLSigner {
public static void signXmlDocumentOnDisk(String fileToBeSignedPath, String signedFileSavePath, String pkcs12CertificateFilePath, String password) throws Exception {
XMLSignatureFactory fac = getXMLSignatureFactory();
Reference ref = getSHA1WholeDocumentEnvelopedTransformReference(fac);
SignedInfo si = getSignedInfo(fac, ref);
PrivateKeyEntry keyEntry = loadPKCS12KeyStoreAndGetSigningKeyEntry(pkcs12CertificateFilePath, password);
KeyInfo ki = getKeyInfoWithX509Data(keyEntry, fac);
Document doc = instantiateDocumentToBeSigned(fileToBeSignedPath);
signDocumentAndPlaceSignatureAsFirstChildElement(doc, keyEntry, fac, si, ki);
writeResultingDocument(doc, signedFileSavePath);
}
private static XMLSignatureFactory getXMLSignatureFactory() {
return XMLSignatureFactory.getInstance("DOM");
}
private static Reference getSHA1WholeDocumentEnvelopedTransformReference(XMLSignatureFactory fac) throws Exception {
return
fac.newReference(
"",
fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)),
null,
null
);
}
private static SignedInfo getSignedInfo(XMLSignatureFactory fac, Reference ref) throws Exception {
return
fac.newSignedInfo(
fac.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null
),
fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref)
);
}
private static PrivateKeyEntry loadPKCS12KeyStoreAndGetSigningKeyEntry(String pkcs12CertificateFilePath, String password) throws Exception {
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new FileInputStream(pkcs12CertificateFilePath), password.toCharArray());
return (PrivateKeyEntry)ks.getEntry(ks.aliases().nextElement(), new KeyStore.PasswordProtection(password.toCharArray()));
}
private static KeyInfo getKeyInfoWithX509Data(PrivateKeyEntry keyEntry, XMLSignatureFactory fac) {
X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
KeyInfoFactory kif = fac.getKeyInfoFactory();
List x509Content = new ArrayList();
x509Content.add(cert.getSubjectX500Principal().getName());
x509Content.add(cert);
X509Data xd = kif.newX509Data(x509Content);
return kif.newKeyInfo(Collections.singletonList(xd));
}
private static Document instantiateDocumentToBeSigned(String fileToBeSignedPath) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
return dbf.newDocumentBuilder().parse(new FileInputStream(fileToBeSignedPath));
}
private static void signDocumentAndPlaceSignatureAsFirstChildElement(Document doc, PrivateKeyEntry keyEntry, XMLSignatureFactory fac, SignedInfo si, KeyInfo ki) throws Exception {
DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement(), doc.getDocumentElement().getFirstChild());
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
}
private static void writeResultingDocument(Document doc, String signedFileSavePath) throws Exception {
OutputStream os = new FileOutputStream(signedFileSavePath);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(os));
}
}
Altri suggerimenti
Visita la pagina dell'API Java XML Signature digitale: https://www.oracle.com/technetwork/articles/javase/dig-signature-api-140772.html