如何在 Java 中移动已签名 XML 中的签名节点
How to move signature node in signed XML in Java
我有这个XML的例子。我需要的是用 Java 签署 xml。问题是我将 'Signature' 节点放在了错误的位置..
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fu="http://www.fu.gov.si/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Body>
<fu:BusinessPremiseRequest Id="data">
<fu:Header>
<fu:MessageID>20DF8D44-ABBE-76BA-E053-AA02010AEA8E</fu:MessageID>
<fu:DateTime>2015-09-24T12:07:28</fu:DateTime>
</fu:Header>
<fu:BusinessPremise>
<fu:TaxNumber>99999862</fu:TaxNumber>
<fu:BusinessPremiseID>P001</fu:BusinessPremiseID>
<fu:BPIdentifier>
<fu:RealEstateBP>
<fu:PropertyID>
<fu:CadastralNumber>2606</fu:CadastralNumber>
<fu:BuildingNumber>6967</fu:BuildingNumber>
<fu:BuildingSectionNumber>1</fu:BuildingSectionNumber>
</fu:PropertyID>
<fu:Address>
<fu:Street>TEST</fu:Street>
<fu:HouseNumber>7</fu:HouseNumber>
<fu:HouseNumberAdditional>C</fu:HouseNumberAdditional>
<fu:Community>KOPER</fu:Community>
<fu:City>KOPER</fu:City>
<fu:PostalCode>6000</fu:PostalCode>
</fu:Address>
</fu:RealEstateBP>
</fu:BPIdentifier>
<fu:ValidityDate>2010-09-24</fu:ValidityDate>
<fu:SoftwareSupplier>
<fu:TaxNumber>10031685</fu:TaxNumber>
</fu:SoftwareSupplier>
<fu:SpecialNotes>Primer prijave poslovnega prostora</fu:SpecialNotes>
</fu:BusinessPremise>
</fu:BusinessPremiseRequest>
</soapenv:Body>
现在我想用我在 Java 中的私钥签署 xml。
XPathFactory factory = XPathFactory.newInstance();
List transforms = null;
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
Reference ref = fac.newReference(
"#data",
fac.newDigestMethod(DigestMethod.SHA256, null),
transforms,
null,
null
);
SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null),
Collections.singletonList(ref));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = (Document) dbf.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes()));
KeyStore p12 = KeyStore.getInstance("pkcs12");
p12.load(new FileInputStream("c:/cert/furspeter.pfx"), "PWD".toCharArray());
Enumeration e = p12.aliases();
String alias = (String) e.nextElement();
System.out.println("Alias certifikata:" + alias);
Key privateKey = p12.getKey(alias, "PWD".toCharArray());
KeyStore.PrivateKeyEntry keyEntry
= (KeyStore.PrivateKeyEntry) p12.getEntry(alias, new KeyStore.PasswordProtection("PWD".toCharArray()));
X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
KeyInfoFactory kif = fac.getKeyInfoFactory();
System.out.println(cert.getSerialNumber());
X509IssuerSerial x509IssuerSerial = kif.newX509IssuerSerial(cert.getSubjectX500Principal().getName(), cert.getSerialNumber());
List x509Content = new ArrayList();
System.out.println("ime: " + cert.getSubjectX500Principal().getName());
x509Content.add(cert.getSubjectX500Principal().getName());
x509Content.add(x509IssuerSerial);
X509Data xd = kif.newX509Data(x509Content);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
DOMSignContext dsc = new DOMSignContext(privateKey, doc.getDocumentElement());
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
OutputStream os = new FileOutputStream("c:/SignedXml.xml");
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(os));
我想要的是在 'fu:BusinessPremiseRequst' 节点中获取 'Signature' 节点。
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fu="http://www.fu.gov.si/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Body>
<fu:BusinessPremiseRequest Id="data">
<fu:Header>...</fu:Header>
<fu:BusinessPremise>...</fu:BusinessPremise>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">...</Signature>
</fu:BusinessPremiseRequest>
</soapenv:Body>
在我的例子中,我得到的节点位置错误(下面的示例)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fu="http://www.fu.gov.si/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Body>
<fu:BusinessPremiseRequest Id="data">
....
</fu:BusinessPremiseRequest>
</soapenv:Body>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">..</Signature>
</soapenv:Envelope>
我在 Java 示例中做错了什么?或者如何将节点移动到里面?
你的错误可能在这里:DOMSignContext dsc = new DOMSignContext(privateKey, doc.getDocumentElement());
您告诉 DOMSignContext
Signature
应该附加到主文档元素。
如果你想在 fu:BusinessPremiseRequest
中使用它,你应该首先获取该节点,并将其作为参数传递给 new DOMSignContext()
构造函数。
我有这个XML的例子。我需要的是用 Java 签署 xml。问题是我将 'Signature' 节点放在了错误的位置..
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fu="http://www.fu.gov.si/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Body>
<fu:BusinessPremiseRequest Id="data">
<fu:Header>
<fu:MessageID>20DF8D44-ABBE-76BA-E053-AA02010AEA8E</fu:MessageID>
<fu:DateTime>2015-09-24T12:07:28</fu:DateTime>
</fu:Header>
<fu:BusinessPremise>
<fu:TaxNumber>99999862</fu:TaxNumber>
<fu:BusinessPremiseID>P001</fu:BusinessPremiseID>
<fu:BPIdentifier>
<fu:RealEstateBP>
<fu:PropertyID>
<fu:CadastralNumber>2606</fu:CadastralNumber>
<fu:BuildingNumber>6967</fu:BuildingNumber>
<fu:BuildingSectionNumber>1</fu:BuildingSectionNumber>
</fu:PropertyID>
<fu:Address>
<fu:Street>TEST</fu:Street>
<fu:HouseNumber>7</fu:HouseNumber>
<fu:HouseNumberAdditional>C</fu:HouseNumberAdditional>
<fu:Community>KOPER</fu:Community>
<fu:City>KOPER</fu:City>
<fu:PostalCode>6000</fu:PostalCode>
</fu:Address>
</fu:RealEstateBP>
</fu:BPIdentifier>
<fu:ValidityDate>2010-09-24</fu:ValidityDate>
<fu:SoftwareSupplier>
<fu:TaxNumber>10031685</fu:TaxNumber>
</fu:SoftwareSupplier>
<fu:SpecialNotes>Primer prijave poslovnega prostora</fu:SpecialNotes>
</fu:BusinessPremise>
</fu:BusinessPremiseRequest>
</soapenv:Body>
现在我想用我在 Java 中的私钥签署 xml。
XPathFactory factory = XPathFactory.newInstance();
List transforms = null;
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
Reference ref = fac.newReference(
"#data",
fac.newDigestMethod(DigestMethod.SHA256, null),
transforms,
null,
null
);
SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null),
Collections.singletonList(ref));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = (Document) dbf.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes()));
KeyStore p12 = KeyStore.getInstance("pkcs12");
p12.load(new FileInputStream("c:/cert/furspeter.pfx"), "PWD".toCharArray());
Enumeration e = p12.aliases();
String alias = (String) e.nextElement();
System.out.println("Alias certifikata:" + alias);
Key privateKey = p12.getKey(alias, "PWD".toCharArray());
KeyStore.PrivateKeyEntry keyEntry
= (KeyStore.PrivateKeyEntry) p12.getEntry(alias, new KeyStore.PasswordProtection("PWD".toCharArray()));
X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
KeyInfoFactory kif = fac.getKeyInfoFactory();
System.out.println(cert.getSerialNumber());
X509IssuerSerial x509IssuerSerial = kif.newX509IssuerSerial(cert.getSubjectX500Principal().getName(), cert.getSerialNumber());
List x509Content = new ArrayList();
System.out.println("ime: " + cert.getSubjectX500Principal().getName());
x509Content.add(cert.getSubjectX500Principal().getName());
x509Content.add(x509IssuerSerial);
X509Data xd = kif.newX509Data(x509Content);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
DOMSignContext dsc = new DOMSignContext(privateKey, doc.getDocumentElement());
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
OutputStream os = new FileOutputStream("c:/SignedXml.xml");
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(doc), new StreamResult(os));
我想要的是在 'fu:BusinessPremiseRequst' 节点中获取 'Signature' 节点。
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fu="http://www.fu.gov.si/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Body>
<fu:BusinessPremiseRequest Id="data">
<fu:Header>...</fu:Header>
<fu:BusinessPremise>...</fu:BusinessPremise>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">...</Signature>
</fu:BusinessPremiseRequest>
</soapenv:Body>
在我的例子中,我得到的节点位置错误(下面的示例)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fu="http://www.fu.gov.si/" xmlns:xd="http://www.w3.org/2000/09/xmldsig#">
<soapenv:Body>
<fu:BusinessPremiseRequest Id="data">
....
</fu:BusinessPremiseRequest>
</soapenv:Body>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">..</Signature>
</soapenv:Envelope>
我在 Java 示例中做错了什么?或者如何将节点移动到里面?
你的错误可能在这里:DOMSignContext dsc = new DOMSignContext(privateKey, doc.getDocumentElement());
您告诉 DOMSignContext
Signature
应该附加到主文档元素。
如果你想在 fu:BusinessPremiseRequest
中使用它,你应该首先获取该节点,并将其作为参数传递给 new DOMSignContext()
构造函数。