我正在尝试使用私钥和证书对XML文档进行签名,这些证书可以正确地从数据库中检索。这个私钥和证书给了我,所以我不太确定Java中的提供程序等价。为了签署XML文档,我使用了this tutorial
我为此执行的代码如下:
PrivateKey pk = null;
javax.security.cert.X509Certificate cert = null;
try{
ByteArrayInputStream bis = new ByteArrayInputStream(keyCer.getLlave());
ObjectInput in = new ObjectInputStream(bis);
pk = (PrivateKey) in.readObject();
bis.close();
bis = new ByteArrayInputStream(keyCer.getCertificado());
in = new ObjectInputStream(bis);
cert = (javax.security.cert.X509Certificate) in.readObject();
bis.close();
keyCer.setCertB64(Base64.encodeBase64String(cert.getEncoded()));
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
dbfac.setNamespaceAware(true);
DocumentBuilder docBuilder;
docBuilder = dbfac.newDocumentBuilder();
DOMImplementation domImpl = docBuilder.getDOMImplementation();
Document doc = domImpl.createDocument("http://cancelacfd.sat.gob.mx", "Cancelacion", null);
doc.setXmlVersion("1.0");
doc.setXmlStandalone(true);
Element cancelacion = doc.getDocumentElement();
cancelacion.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xsd","http://www.w3.org/2001/XMLSchema");
cancelacion.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
cancelacion.setAttribute("RfcEmisor", rfc);
cancelacion.setAttribute("Fecha", fecha);
Element folios = doc.createElement("Folios");
cancelacion.appendChild(folios);
for (int i=0; i<uuid.length; i++) {
Element u = doc.createElement("UUID");
u.setTextContent(uuid[i]);
folios.appendChild(u);
}
DOMSignContext dsc = new DOMSignContext (pk, doc.getDocumentElement());
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
Reference ref = fac.newReference ("", fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList
(fac.newTransform(Transform.ENVELOPED,
(TransformParameterSpec) null)), null, null);
SignedInfo si = fac.newSignedInfo
(fac.newCanonicalizationMethod
(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null),
Collections.singletonList(ref));
KeyInfoFactory kif = fac.getKeyInfoFactory();
KeyValue kv = kif.newKeyValue(cert.getPublicKey());
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer trans = transfac.newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
trans.setOutputProperty(OutputKeys.VERSION, "1.0");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
//CREAR STRING DEL ARBOL XML
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
DOMSource source = new DOMSource(doc);
trans.transform(source, result);
String xmlString = sw.toString();
System.out.println(xmlString);
} catch (Exception e) {
e.printStackTrace();
}
运行程序时,我得到以下异常:
javax.xml.crypto.dsig.XMLSignatureException: java.security.InvalidKeyException: No installed provider supports this key: sun.security.rsa.RSAPrivateCrtKeyImpl
[java] at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.sign(Unknown Source)
[java] at prueba.cancelaciones.CancelaFE.doPost(CancelaFE.java:140)
[java] at prueba.cancelaciones.CancelaFE.doGet(CancelaFE.java:66)
[java] at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
[java] at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
[java] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:306)
[java] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
[java] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
[java] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
[java] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
[java] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
[java] at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:541)
[java] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
[java] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:383)
[java] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:243)
[java] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
[java] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
[java] at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:288)
[java] at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
[java] at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
[java] at java.lang.Thread.run(Unknown Source)
[java] Caused by: java.security.InvalidKeyException: No installed provider supports this key: sun.security.rsa.RSAPrivateCrtKeyImpl
[java] at java.security.Signature$Delegate.chooseProvider(Unknown Source)
[java] at java.security.Signature$Delegate.engineInitSign(Unknown Source)
[java] at java.security.Signature.initSign(Unknown Source)
[java] at org.jcp.xml.dsig.internal.dom.DOMSignatureMethod.sign(Unknown Source)
[java] ... 21 more
有什么建议吗?
答案 0 :(得分:6)
问题是我的,我错误地指定了签名方法。它应该是:
SignedInfo si = fac.newSignedInfo
(fac.newCanonicalizationMethod
(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
答案 1 :(得分:0)
也许您需要安装一个JCE / JCA提供程序,可以在BouncyCastle找到。只是一个猜测。