如何将PKCS#7返回信息应用到XML实现远程签名?(Java/Santuario示例)
基于远程PKCS#7响应完成XML签名的实现方案
核心逻辑
- 预先计算待签名XML的消息摘要(需与远程签名服务使用的算法一致,如SHA-256)
- 将摘要发送至远程服务获取PKCS#7格式响应
- 从PKCS#7中提取原始签名值(注意Base64解码)和短期X509证书
- 利用提取的信息,通过Apache Santuario或纯Java API组装合法的XML签名结构
Apache Santuario 实现示例
import org.apache.xml.security.signature.XMLSignature; import org.apache.xml.security.transforms.Transforms; import org.apache.xml.security.utils.Constants; import org.w3c.dom.Document; import org.w3c.dom.Element; import java.security.cert.X509Certificate; public class RemotePKCS7XMLSignature { public static void signXMLWithRemotePKCS7(Document doc, X509Certificate remoteCert, byte[] remoteSignatureValue, String digestAlgorithm) throws Exception { // 初始化Apache Santuario安全配置 org.apache.xml.security.Init.init(); // 创建XML签名实例,指定签名算法(需与远程服务匹配,如SHA256withRSA) XMLSignature signature = new XMLSignature(doc, null, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256); // 将签名节点添加到XML文档根节点 doc.getDocumentElement().appendChild(signature.getElement()); // 添加转换规则(与本地签名时的规则一致) Transforms transforms = new Transforms(doc); transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE); transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS); signature.addDocument("", transforms, digestAlgorithm); // 注入远程服务返回的证书 signature.addKeyInfo(remoteCert); // 跳过本地签名,直接设置远程返回的签名值 signature.getSignedInfo().getSignatureValue().setSignatureValue(remoteSignatureValue); // 生成最终的签名结构 signature.sign(); } }
纯Java JDK 实现示例
import javax.xml.crypto.dsig.*; 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 java.security.Key; import java.security.cert.X509Certificate; import java.util.Base64; import java.util.Collections; import java.util.List; import org.w3c.dom.Document; public class PureJavaRemoteXMLSignature { public static void signXMLWithRemotePKCS7(Document doc, X509Certificate remoteCert, byte[] remoteSignatureValue, String digestAlgorithm) throws Exception { XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM"); // 构建转换规则 Transform envTransform = factory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null); Transform c14nTransform = factory.newTransform(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null); List<Transform> transforms = List.of(envTransform, c14nTransform); // 构建SignedInfo(需与远程签名的算法匹配) Reference ref = factory.newReference("", factory.newDigestMethod(digestAlgorithm, null), transforms, null, null); SignedInfo signedInfo = factory.newSignedInfo( factory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null), factory.newSignatureMethod(SignatureMethod.RSA_SHA256, null), List.of(ref) ); // 构建KeyInfo,注入远程证书 KeyInfoFactory keyInfoFactory = factory.getKeyInfoFactory(); X509Data x509Data = keyInfoFactory.newX509Data(List.of(remoteCert)); KeyInfo keyInfo = keyInfoFactory.newKeyInfo(List.of(x509Data)); // 创建XML签名实例,跳过本地签名逻辑 XMLSignature signature = factory.newXMLSignature(signedInfo, keyInfo); // 绑定签名上下文(用空密钥占位,实际签名由远程完成) DOMSignContext signContext = new DOMSignContext(new DummyPrivateKey(), doc.getDocumentElement()); signature.sign(signContext); // 替换签名值为远程返回的内容 Element signatureValueElem = (Element) doc.getElementsByTagNameNS(Constants.SignatureSpecNS, "SignatureValue").item(0); signatureValueElem.setTextContent(Base64.getEncoder().encodeToString(remoteSignatureValue)); } // 自定义空私钥类,仅用于占位 private static class DummyPrivateKey implements Key { @Override public String getAlgorithm() { return "RSA"; } @Override public String getFormat() { return "PKCS#8"; } @Override public byte[] getEncoded() { return new byte[0]; } } }
关键注意事项
- 算法一致性:确保XML摘要算法、签名算法与远程签名服务完全匹配(如SHA-256对应RSA-SHA256)
- 签名值编码:从PKCS#7中提取的签名值通常是Base64编码,需先解码为字节数组再注入
- 证书嵌入:必须将远程返回的短期X509证书完整嵌入XML的KeyInfo节点,否则签名无法通过验证
- 转换规则:保持与本地签名时的XML转换规则(如C14N规范、Enveloped签名)一致
内容的提问来源于stack exchange,提问作者beat
相关产品推荐
相关产品推荐

