Java 从字节数组反序列化后,Xml文档签名无效
我有一个问题,我对xml文档进行签名,然后验证签名,验证通过,但当我将文档序列化为字节数组,然后将其反序列化回文档时,签名验证失败 以下是用于验证和序列化/反序列化的方法:Java 从字节数组反序列化后,Xml文档签名无效,java,xml,serialization,certificate,digital-signature,Java,Xml,Serialization,Certificate,Digital Signature,我有一个问题,我对xml文档进行签名,然后验证签名,验证通过,但当我将文档序列化为字节数组,然后将其反序列化回文档时,签名验证失败 以下是用于验证和序列化/反序列化的方法: public class DocumentSigner { @Override public byte[] transformToByteArray(Document doc) throws Exception { TransformerFactory transformerFactory =
public class DocumentSigner {
@Override
public byte[] transformToByteArray(Document doc) throws Exception {
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
ByteArrayOutputStream os = new ByteArrayOutputStream();
transformer.transform(new DOMSource(doc), new StreamResult(os));
return os.toByteArray();
}
private Document byteArrayToXmlDoc(byte[] documentoXml) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(documentoXml), "UTF-8");
}
@Override
public Boolean validate(byte[] byteArrayDoc, Integer certificatePropertiesId) throws Exception {
Document doc = byteArrayToXmlDoc(byteArrayDoc);
return validate(doc, certificatePropertiesId);
}
public Boolean validate(Document doc, Integer certificatePropertiesId) throws Exception {
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS,
"Signature");
if (nl.getLength() == 0) {
throw new Exception("No signature element.");
}
KeyStore ks = KeyStore.getInstance("JKS");
CertificatePropertiesDTO certProp = databaseLogic.getCertificateProperties(certificatePropertiesId);
if (certProp == null || certProp.getCertificatePassword().isEmpty() || certProp.getCertificate() == null){
throw new RuntimeException("No certificate.");
}
ks.load(new ByteArrayInputStream(certProp.getCertificate()), certProp.getCertificatePassword().toCharArray());
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(ks.aliases().nextElement(), new KeyStore.PasswordProtection(certProp.getCertificatePassword().toCharArray()));
X509Certificate[] certs = (X509Certificate[]) keyEntry.getCertificateChain();
if (certs == null || certs.length == 0) {
throw new RuntimeException("No certificate found.");
}
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
DOMValidateContext valContext = new DOMValidateContext(keyEntry.getCertificate().getPublicKey(), nl.item(0));
NodeList els = doc.getElementsByTagNameNS("*", "SignatureProperties");
Element el = (Element) els.item(0);
valContext.setIdAttributeNS(el, null, "Id");
valContext.setDefaultNamespacePrefix("dsig");
valContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE);
try {
XMLSignature signature2 = fac
.unmarshalXMLSignature(new DOMStructure(nl.item(0)));
boolean coreValidity = signature2.validate(valContext);
// Check core validation status.
if (coreValidity == false) {
log.info("Signature failed core validation");
boolean sv = signature2.getSignatureValue()
.validate(valContext);
log.info("signature validation status: " + sv);
Iterator<?> i = signature2.getSignedInfo().getReferences()
.iterator();
for (int j = 0; i.hasNext(); j++) {
Reference ref = (Reference) i.next();
boolean refValid = ref.validate(valContext);
log.info("ref[" + j + "] validity status: " + refValid);
}
return false;
} else {
log.info("Signature passed core validation");
return true;
}
} catch (Exception ex) {
log.info("EXCEPTION during validation: " + ex.getMessage());
return false;
}
}
public void signDocument(Document doc)
{
....
}
public void writeToDisk(String path, String rac)
{
BufferedWriter writer = null;
try
{
writer = new BufferedWriter(new FileWriter(path));
writer.write(rac);
}
catch ( IOException e)
{
}
finally
{
try
{
if ( writer != null)
writer.close( );
}
catch ( IOException e)
{
try {
throw e;
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
@Override
public String transformToString(Document doc,
Boolean omitXmlDeclaration) throws Exception {
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
//transformerFactory.setAttribute("indent-number", 4);
Transformer transformer = transformerFactory.newTransformer();
if (omitXmlDeclaration)
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
"yes");
// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
//
StringWriter sw = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(sw));
//String output = sw.getBuffer().toString().replaceAll("\n|\r", "");
return sw.toString();
}
}
如有必要,我将发布创建/签署文档的方法,但文档太大了。
以下是签名方法:
private void signDocument(Document document) throws Exception {
//Remove ApacheXMLDSig because after every SOAP message signing it's set as default provdier, but doesn't know about here() function from XPATH2
Security.removeProvider("ApacheXMLDSig");
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM", "XMLDSig");
String id = String.format("id%s", UUID.randomUUID().toString());
KeyStore ks = KeyStore.getInstance("JKS");
CertificatePropertiesDTO certProp = databaseLogic.getCertificateProperties(1);
if (certProp == null || certProp.getCertificatePassword().isEmpty() || certProp.getCertificate() == null){
throw new RuntimeException("No certificate.");
}
ks.load(new ByteArrayInputStream(certProp.getCertificate()), certProp.getCertificatePassword().toCharArray());
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(ks.aliases().nextElement(), new KeyStore.PasswordProtection(certProp.getCertificatePassword().toCharArray()));
X509Certificate[] certs = (X509Certificate[]) keyEntry.getCertificateChain();
if (certs == null || certs.length == 0) {
throw new RuntimeException("No certificate found.");
}
Element propSig = XMLElement(document, "PROP_Sig", "");
Attr propNS = XMLAtribut(document, "xmlns", "http://ns.adobe.com/pdf/2006");
propSig.setAttributeNodeNS(propNS);
propSig.setAttribute("type", "cabinet");
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssZZ");
Element m = XMLElement(document, "M", String.format("D:%s", df.format(new Date())));
m.setAttribute("type", "text");
Element name = XMLElement(document, "Name", cert.getSubjectX500Principal().getName());
name.setAttribute("type", "text");
propSig.appendChild(m);
propSig.appendChild(name);
SignatureProperty sp = sigFactory.newSignatureProperty(Collections.singletonList(new DOMStructure(propSig)), "data_signature", null);
SignatureProperties sps = sigFactory.newSignatureProperties(Collections.singletonList(sp), id);
CanonicalizationMethod cm = sigFactory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (XMLStructure) null);
SignatureMethod sm = sigFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
DigestMethod dm1 = sigFactory.newDigestMethod(DigestMethod.SHA1, null);
Transform tf1 = sigFactory.newTransform(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (TransformParameterSpec) null);
Reference ref1 = sigFactory.newReference("#" + id, dm1, Collections.singletonList(tf1), "http://www.w3.org/2000/09/xmldsig#SignatureProperties", null);
DigestMethod dm2 = sigFactory.newDigestMethod(DigestMethod.SHA1, null);
String here = "here()/ancestor::dsig:Signature[1]/../../../../../..//. | "
+ "here()/ancestor::dsig:Signature[1]/../../../../../..//@* | "
+ "here()/ancestor::dsig:Signature[1]/../../../../../..//namespace::*";
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("dsig", "http://www.w3.org/2000/09/xmldsig#");
XPathType xp = new XPathType(here, XPathType.Filter.INTERSECT, hm);
TransformParameterSpec paramsXPath2= new XPathFilter2ParameterSpec(Collections.singletonList(xp));
Transform tf2 = sigFactory.newTransform(Transform.XPATH2, paramsXPath2);
Transform tf3 = sigFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null);
Transform tf4 = sigFactory.newTransform(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (TransformParameterSpec) null); //"http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
List<Transform> lt2 = new ArrayList<Transform>();
lt2.add(tf2);
lt2.add(tf3);
lt2.add(tf4);
Reference ref2 = sigFactory.newReference("", dm2, lt2, null, null);
List<Reference> lr = new ArrayList<Reference>();
lr.add(ref1);
lr.add(ref2);
SignedInfo si = sigFactory.newSignedInfo(cm, sm, lr);
KeyInfoFactory kif = KeyInfoFactory.getInstance("DOM", "XMLDSig");
ArrayList<Object> x509Content = new ArrayList<>();
for (int i = 0; i < certs.length; i++) {
x509Content.add(certs[i]);
}
X509Data xd = kif.newX509Data(x509Content);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), document.getElementsByTagName("sac:SignatureInformation").item(0));
XMLSignature signature =
sigFactory.newXMLSignature(si, ki, Collections.singletonList( sigFactory.newXMLObject(Collections.singletonList(sps), null, null, null)), "data_signature", null);
dsc.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE);
dsc.setDefaultNamespacePrefix("dsig");
try {
signature.sign(dsc);
}
catch (Exception ex) {
log.warn(ex.getMessage());
throw new RuntimeException("Signing failed");
}
}
private void signDocument(文档文档)引发异常{
//删除ApacheXMLDSig,因为在每次SOAP消息签名后,它都被设置为默认provdier,但不知道XPATH2中的here()函数
担保。移除提供方(“ApacheXMLDSig”);
XMLSignatureFactory sigFactory=XMLSignatureFactory.getInstance(“DOM”、“XMLDSig”);
String id=String.format(“id%s”,UUID.randomUUID().toString());
KeyStore ks=KeyStore.getInstance(“JKS”);
CertificatePropertiesTo certProp=databaseLogic.getCertificateProperties(1);
if(certProp==null | | certProp.getCertificatePassword().isEmpty()| | certProp.getCertificate()==null){
抛出新的RuntimeException(“无证书”);
}
load(新的ByteArrayInputStream(certProp.getCertificate()),certProp.getCertificatePassword().toCharArray());
KeyStore.PrivateKeyEntry keyEntry=(KeyStore.PrivateKeyEntry)ks.getEntry(ks.aliases().nextElement(),新KeyStore.PasswordProtection(certProp.getCertificatePassword().toCharray());
X509Certificate[]证书=(X509Certificate[])密钥项。getCertificateChain();
if(certs==null | | certs.length==0){
抛出新的RuntimeException(“未找到证书”);
}
Element propSig=XMLElement(文档,“PROP_-Sig”,”);
Attr propNS=XMLAtribut(文档“xmlns”http://ns.adobe.com/pdf/2006");
propSig.setAttributeNodeNS(Props);
propSig.setAttribute(“类型”、“文件柜”);
DateFormat df=新的简化格式(“yyyyMMddHHmmssZZ”);
元素m=XMLElement(文档,“m”,字符串.format(“D:%s”,df.format(new Date()));
m、 setAttribute(“类型”、“文本”);
元素名称=XMLElement(文档“名称”,证书getSubjectX500Principal().getName());
name.setAttribute(“类型”、“文本”);
附属物(m);
propSig.appendChild(姓名);
SignatureProperty sp=sigFactory.newSignatureProperty(Collections.singletonList(新的DOMStructure(propSig)),“数据\签名”,null);
SignatureProperties sps=sigFactory.newSignatureProperties(Collections.singletonList(sp),id);
CanonicalizationMethod cm=sigFactory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE_,带_注释,(XMLStructure)null);
SignatureMethod sm=sigFactory.newSignatureMethod(SignatureMethod.RSA_SHA1,null);
DigestMethod dm1=sigFactory.newDigestMethod(DigestMethod.SHA1,null);
Transform tf1=sigFactory.newTransform(规范化方法.EXCLUSIVE_,带有_注释,(TransformParameterSpec)null);
Reference ref1=sigFactory.newReference(“#”+id,dm1,Collections.singletonList(tf1),”http://www.w3.org/2000/09/xmldsig#SignatureProperties“,空);
DigestMethod dm2=sigFactory.newDigestMethod(DigestMethod.SHA1,null);
String here=“here()/祖先::dsig:Signature[1]/../../../../../../../../...|”
+“here()/祖先::dsig:Signature[1]/../../../../../@*|”
+“here()/祖先::dsig:Signature[1]/../../../../../../namespace::*”;
HashMap hm=新的HashMap();
hm.put(“dsig”http://www.w3.org/2000/09/xmldsig#");
XPathType xp=新的XPathType(此处为XPathType.Filter.INTERSECT,hm);
TransformParameterSpec paramsXPath2=新的XPathFilter2ParameterSpec(Collections.singletonList(xp));
Transform tf2=sigFactory.newTransform(Transform.XPATH2,paramsXPath2);
Transform tf3=sigFactory.newTransform(Transform.ENVELOPED,(TransformParameterSpec)null);
Transform tf4=sigFactory.newTransform(CanonicalizationMethod.EXCLUSIVE_,带_注释,(TransformParameterSpec)null);/“http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
List lt2=新的ArrayList();
lt2.添加(tf2);
lt2.添加(tf3);
lt2.添加(tf4);
Reference ref2=sigFactory.newReference(“”,dm2,lt2,null,null);
List lr=new ArrayList();
lr.添加(参考文献1);
lr.添加(参考文献2);
SignedInfo si=sigFactory.newSignedInfo(cm、sm、lr);
KeyInfoFactory kif=KeyInfoFactory.getInstance(“DOM”、“XMLDSig”);
ArrayList x509Content=新的ArrayList();
对于(int i=0;i
以下是已签名的示例XML文档的一部分:
<ext:UBLExtension>
<ext:ExtensionContent>
<sig:UBLDocumentSignatures>
<sac:SignatureInformation>
<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Id="data_signature">
<dsig:SignedInfo>
<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
<dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<dsig:Reference Type="http://www.w3.org/2000/09/xmldsig#SignatureProperties" URI="#idfe5688f4-583f-4a98-b26c-9d651b2f8918">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>iq802IBHl5kVdIMWA5Wlb5hYEoY=</dsig:DigestValue>
</dsig:Reference>
<dsig:Reference URI="">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2002/06/xmldsig-filter2">
<dsig:XPath Filter="intersect" xmlns:dsig="http://www.w3.org/2002/06/xmldsig-filter2">here()/ancestor::dsig:Signature[1]/../../../../../..//. | here()/ancestor::dsig:Signature[1]/../../../../../..//@* | here()/ancestor::dsig:Signature[1]/../../../../../..//namespace::*</dsig:XPath>
</dsig:Transform>
<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>2jmj7l5rSw0yVb/vlWAYkK/YBwk=</dsig:DigestValue>
</dsig:Reference>
</dsig:SignedInfo>
<dsig:SignatureValue>d+DRc25SXnhxwXJs10A9Hnf1g0gG2bZqqnpTbZvrzp8X3EvtOVr3dBP6Ldc1RMTJYSF+guanlWKn
liaKlu7VbdB+SiQRuAMAZt+9Cnbn0CMlIzt22nRJNzjbeLBpCm7K63jCHGOXsWCW43DI/DYeZwq+
Q2j7WESgOtWLqUO0Jn8=</dsig:SignatureValue>
<dsig:KeyInfo>
<dsig:X509Data>
<dsig:X509Certificate>...</dsig:X509Certificate>
<dsig:X509Certificate>...</dsig:X509Certificate>
</dsig:X509Data>
</dsig:KeyInfo>
<dsig:Object>
<dsig:SignatureProperties Id="idfe5688f4-583f-4a98-b26c-9d651b2f8918">
<dsig:SignatureProperty Target="data_signature">
<PROP_Sig xmlns="http://ns.adobe.com/pdf/2006" type="cabinet">
<M type="text">D:20151130163741+0100</M>
<Name type="text">CN=<CN>,L=<City>,O=<Organization>,C=<Country></Name>
</PROP_Sig>
</dsig:SignatureProperty>
</dsig:SignatureProperties>
</dsig:Object>
</dsig:Signature>
</sac:SignatureInformation>
</sig:UBLDocumentSignatures>
</ext:ExtensionContent>
</ext:UBLExtension>
</ext:UBLExtensions>
<ext:UBLExtension>
<ext:ExtensionContent>
<sig:UBLDocumentSignatures>
<sac:SignatureInformation>
<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Id="data_signature">
<dsig:SignedInfo>
<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
<dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<dsig:Reference Type="http://www.w3.org/2000/09/xmldsig#SignatureProperties" URI="#idfe5688f4-583f-4a98-b26c-9d651b2f8918">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>iq802IBHl5kVdIMWA5Wlb5hYEoY=</dsig:DigestValue>
</dsig:Reference>
<dsig:Reference URI="">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2002/06/xmldsig-filter2">
<dsig:XPath Filter="intersect" xmlns:dsig="http://www.w3.org/2002/06/xmldsig-filter2">here()/ancestor::dsig:Signature[1]/../../../../../..//. | here()/ancestor::dsig:Signature[1]/../../../../../..//@* | here()/ancestor::dsig:Signature[1]/../../../../../..//namespace::*</dsig:XPath>
</dsig:Transform>
<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>2jmj7l5rSw0yVb/vlWAYkK/YBwk=</dsig:DigestValue>
</dsig:Reference>
</dsig:SignedInfo>
<dsig:SignatureValue>d+DRc25SXnhxwXJs10A9Hnf1g0gG2bZqqnpTbZvrzp8X3EvtOVr3dBP6Ldc1RMTJYSF+guanlWKn
liaKlu7VbdB+SiQRuAMAZt+9Cnbn0CMlIzt22nRJNzjbeLBpCm7K63jCHGOXsWCW43DI/DYeZwq+
Q2j7WESgOtWLqUO0Jn8=</dsig:SignatureValue>
<dsig:KeyInfo>
<dsig:X509Data>
<dsig:X509Certificate>...</dsig:X509Certificate>
<dsig:X509Certificate>...</dsig:X509Certificate>
</dsig:X509Data>
</dsig:KeyInfo>
<dsig:Object>
<dsig:SignatureProperties Id="idfe5688f4-583f-4a98-b26c-9d651b2f8918">
<dsig:SignatureProperty Target="data_signature">
<PROP_Sig xmlns="http://ns.adobe.com/pdf/2006" type="cabinet">
<M type="text">D:20151130163741+0100</M>
<Name type="text">CN=<CN>,L=<City>,O=<Organization>,C=<Country></Name>
</PROP_Sig>
</dsig:SignatureProperty>
</dsig:SignatureProperties>
</dsig:Object>
</dsig:Signature>
</sac:SignatureInformation>
</sig:UBLDocumentSignatures>
</ext:ExtensionContent>
</ext:UBLExtension>
</ext:UBLExtensions>