问题描述
我有以下使用JDom库,Apache XML安全性库,org.w3c.dom包和java.security包的方法,以使用来自单个PFX证书的数据对单个XML文件进行签名:
/** This method allows to sign a single XML using data from a single Certificate and a given Namespace
@param pKey Private Key obtained from a PFX certificate
@param cert Certificate data obtained from the PFX file
@param ns Namespace to be associated to the root tag of the signed XML content
**/
public void sign(PrivateKey pKey,X509Certificate cert,Namespace ns) throws JDOMException,InvalidKeyException,NoSuchAlgorithmException,SignatureException,XMLSecurityException,ParserConfigurationException,IOException,SAXException,DTECedidoException,TimbreException,CodigoException,ReciboException {
Constants.setSignatureSpecnsprefix("");
String baseUri = null;
if (ns != null)
baseUri = ns.getURI();
String alg = pKey.getAlgorithm();
if (!alg.equals(cert.getPublicKey().getAlgorithm()))
throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
ByteArrayOutputStream out = new ByteArrayOutputStream();
XMLUtil.getNiceXML(genDocument(ns),out);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
org.w3c.dom.Document doc = db.parse(in);
org.w3c.dom.Element root = doc.getDocumentElement();
XMLSignature sig = null;
if (alg.equals("RSA")) {
if (!((RSAPrivateKey) pKey).getModulus().equals(((RSAPublicKey) cert.getPublicKey()).getModulus()))
throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
sig = new XMLSignature(doc,baseUri,XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
} else if (alg.equals("DSA")) {
if (!(((DSAPrivateKey) pKey).getParams().getG()
.equals(((DSAPublicKey) cert.getPublicKey()).getParams().getG())
&& ((DSAPrivateKey) pKey).getParams().getP()
.equals(((DSAPublicKey) cert.getPublicKey()).getParams().getP())
&& ((DSAPrivateKey) pKey).getParams().getQ()
.equals(((DSAPublicKey) cert.getPublicKey()).getParams().getQ())))
throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_DSA);
} else
throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
root.appendChild(sig.getElement());
sig.addDocument("#" + getId());
X509Data xdata = new X509Data(doc);
xdata.addCertificate(cert);
sig.getKeyInfo().addkeyvalue(cert.getPublicKey());
sig.getKeyInfo().add(xdata);
sig.sign(pKey);
ByteArrayOutputStream bous = new ByteArrayOutputStream();
DOMBuilder docIn = new DOMBuilder();
Document domdoc = docIn.build(doc);
cl.sii.dte.util.XMLUtil.getNiceXML(domdoc,bous);
this.signedDoc = bous.toByteArray();
}
此方法工作正常。但是,我需要重载它,并且新方法必须支持来自多个证书的数据(最多3个)。到目前为止,我有这个:
/** This method allows to sign a single XML using data from multiples Certificates and a given Namespace
@param pKey List of Private Keys obtained from one PFX certificate per key
@param cert List of Certificate datas obtained from one PFX file per data.
@param ns Namespace to be associated to the root tag of the signed XML content
**/
public void sign(List<PrivateKey> pKey,List<X509Certificate> cert,ReciboException {
/* Loads the unsigned XML ENTIRE content in order to add the signatures*/
Constants.setSignatureSpecnsprefix("");
String baseUri = null;
if (ns != null)
baseUri = ns.getURI();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
ByteArrayOutputStream out = new ByteArrayOutputStream();
XMLUtil.getNiceXML(genDocument(ns),out);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
org.w3c.dom.Document doc = db.parse(in);
org.w3c.dom.Element root = doc.getDocumentElement();
XMLSignature sig = null;
for(int i=0; i<pKey.size(); i++){
PrivateKey pk=pKey.get(i);
X509Certificate c=cert.get(i)
String alg = pk.getAlgorithm();
if (!alg.equals(c.getPublicKey().getAlgorithm()))
throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
if (alg.equals("RSA")) {
if (!((RSAPrivateKey) pk).getModulus().equals(((RSAPublicKey) c.getPublicKey()).getModulus()))
throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
} else if (alg.equals("DSA")) {
if (!(((DSAPrivateKey) pk).getParams().getG()
.equals(((DSAPublicKey) c.getPublicKey()).getParams().getG())
&& ((DSAPrivateKey) pk).getParams().getP()
.equals(((DSAPublicKey) c.getPublicKey()).getParams().getP())
&& ((DSAPrivateKey) pk).getParams().getQ()
.equals(((DSAPublicKey) c.getPublicKey()).getParams().getQ())))
throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_DSA);
} else
throw (new DTECedidoException(DTECedidoException.NOT_CORRESPONDING));
root.appendChild(sig.getElement());
sig.addDocument("#" + getId());
/* The following lines of code give me problems*/
X509Data xdata = new X509Data(doc);
xdata.addCertificate(c);
sig.getKeyInfo().addkeyvalue(c.getPublicKey());
sig.getKeyInfo().add(xdata);
sig.sign(pk);
}
/* Generates and stores the byte content of the resulting
signed XML */
ByteArrayOutputStream bous = new ByteArrayOutputStream();
DOMBuilder docIn = new DOMBuilder();
Document domdoc = docIn.build(doc);
cl.sii.dte.util.XMLUtil.getNiceXML(domdoc,bous);
this.signedDoc = bous.toByteArray();
}
主要问题是以下几行代码从整个文档中获取信息,并且仅允许添加一个证书项目,而不是所有证书列表。
X509Data xdata = new X509Data(doc);
xdata.addCertificate(c); // !!!!!!!
sig.getKeyInfo().addkeyvalue(c.getPublicKey());
sig.getKeyInfo().add(xdata); //!!!!!!!
sig.sign(pk);
在哪里可以找到一个使用Java使用多个PFX文件中的信息对XML文件进行签名的好示例(我自己尝试过但没有成功)?
谢谢。
public void sign(List<PrivateKey> pKey,Namespace ns)
throws XMLSecurityException,CesionException {
Constants.setSignatureSpecnsprefix("");
String baseUri = null;
if (ns != null)
baseUri = ns.getURI();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
ByteArrayOutputStream out = new ByteArrayOutputStream();
XMLUtil.getNiceXML(genDocument(ns),out);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
org.w3c.dom.Document doc = db.parse(in);
org.w3c.dom.Element root = doc.getDocumentElement();
XMLSignature sig = null;
for(int i=0; i<pKey.size(); i++) {
PrivateKey pk=pKey.get(i);
X509Certificate c=cert.get(i);
String alg = pk.getAlgorithm();
if (!alg.equals(c.getPublicKey().getAlgorithm()))
throw (new CesionException(CesionException.NOT_CORRESPONDING));
if (alg.equals("RSA")) {
if (!((RSAPrivateKey) pk).getModulus().equals(((RSAPublicKey) c.getPublicKey()).getModulus()))
throw (new CesionException(CesionException.NOT_CORRESPONDING));
sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
} else if (alg.equals("DSA")) {
if (!(((DSAPrivateKey) pk).getParams().getG()
.equals(((DSAPublicKey) c.getPublicKey()).getParams().getG())
&& ((DSAPrivateKey) pk).getParams().getP()
.equals(((DSAPublicKey) c.getPublicKey()).getParams().getP())
&& ((DSAPrivateKey) pk).getParams().getQ()
.equals(((DSAPublicKey) c.getPublicKey()).getParams().getQ())))
throw (new CesionException(CesionException.NOT_CORRESPONDING));
sig = new XMLSignature(doc,XMLSignature.ALGO_ID_SIGNATURE_DSA);
} else
throw (new CesionException(DTECedidoException.NOT_CORRESPONDING));
root.appendChild(sig.getElement());
sig.addDocument("#" + i);
X509Data xdata = new X509Data(doc);
xdata.addCertificate(c);
sig.getKeyInfo().addkeyvalue(c.getPublicKey());
sig.getKeyInfo().add(xdata);
sig.sign(pk);
}
ByteArrayOutputStream bous = new ByteArrayOutputStream();
DOMBuilder docIn = new DOMBuilder();
Document domdoc = docIn.build(doc);
cl.sii.dte.util.XMLUtil.getNiceXML(domdoc,bous);
this.signedDoc = bous.toByteArray();
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)