I am completely desperate. I tried some time ago to find an answer using vba, and I didn't get a solution.
I went back to the load trying to use cURL from the command line, but it doesn't work either. In this case, I am going to show you the entire process carried out with CURL, which, according to what I have been able to document, should work. But something escapes me, because I can't get the Treasury Web Service to receive my files
Export Certificate (.pfx)
In order to use the certificate, first of all you have to export it from my browser. To do this, you can do:
- Chrome settings
- Manage certificates...
- Export the private key
- Personal Information Exchange: PKCS #12 (.PFX)
- Include all certificates in the certification path (if possible)
- Export all extended properties
- Give it password: 12345
- Name the file: Certificate.pfx
- Personal Information Exchange: PKCS #12 (.PFX)
- Export the private key
- Manage certificates...
Once this is done, I get a certificate in .pfx format
Convert .pfx certificate to .pem (OpenSSL)
This format is not valid for cURL. Therefore, it must be transformed to .pem before. And for this, everywhere they talk about OpenSSL. I downloaded version 1.0.21 May 25, 2017 (accessed from the command line) I transform certificate:
--Importo certificado PEM (sin key)
C:\OpenSSL-Win64\bin\openssl.exe pkcs12 -in C:\VariasSII\Certificados\Certificado.pfx -out C:\VariasSII\Certificados\Certificado-CL.pem -clcerts -nokeys
--Importo KEY
C:\OpenSSL-Win64\bin\openssl.exe pkcs12 -in C:\VariasSII\Certificados\Certificado.pfx -out C:\VariasSII\Certificados\Certificado-KEY.pem -nocerts
--Importo CA (Esto en muchas partes no se usa. Lo tengo, y puedo ponerlo o no, aunque en cualquiera de los casos no me sirve para que funcione el envío
C:\OpenSSL-Win64\bin\openssl.exe pkcs12 -in C:\VariasSII\Certificados\Certificado.pfx -out C:\VariasSII\Certificados\Certificado-CA.pem -cacerts -nokeys
Send (using cURL)
Finally, with this instruction you should be able to send XML files to the Treasury:
curl --data C:\VariasSII\TEST.xml --output C:\VariasSII\respuesta.xml --cert C:\VariasSII\Certificados\Certificado-CL.pem --key C:\VariasSII\Certificados\Certificado-KEY.pem https://www7.aeat.es/wlpl/SSII-FACT/ws/fe/SiiFactFEV1SOAP
cURL Response
The response to this request is as follows:
<?xml version="1.0" encoding="UTF-8"?><env:Envelope
xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"><env:Body><env:Fault>
<faultcode>env:Client</faultcode><faultstring>Codigo[1304].No se permite
contenido en el prólogo. (1,1)</faultstring><detail><callstack>XML no válido o mal formado
WSExcepcion [faultcode=null, detailMap=null, version=0, faultstring=No se permite contenido en el prólogo. (1,1), faultactor=null, faultSubCode=null, reasonText=null, detail=null, nameSpaceUriDetail=null]
at es.aeat.adws.jdit.imp.ws.WSFilterSrvImpl.verificarFirma(WSFilterSrvImpl.java:810)
at es.aeat.adws.jdit.imp.ws.WSFilterSrvImpl.doFilter(WSFilterSrvImpl.java:246)
at es.aeat.adws.jdit.api.ws.WSFilter.doFilter(WSFilter.java:24)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:207)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:91)
at es.aeat.adht.jdit.imp.infra.JDitFilterSrvImpl.filtroIni(JDitFilterSrvImpl.java:178)
at es.aeat.adht.jdit.imp.infra.JDitFilterSrvImpl.doFilter(JDitFilterSrvImpl.java:86)
at es.aeat.adht.jdit.imp.infra.JDitFilterSrvImpl.doFilter(JDitFilterSrvImpl.java:63)
at es.aeat.adht.jdit.api.filter.JDitFilter.doFilter(JDitFilter.java:24)
at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:207)
at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:91)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:1021)
at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1143)
at com.ibm.ws.webcontainer.servlet.CacheServletWrapper.handleRequest(CacheServletWrapper.java:82)
at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:934)
at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.run(DynamicVirtualHost.java:262)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink$TaskWrapper.run(HttpDispatcherLink.java:958)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.wrapHandlerAndExecute(HttpDispatcherLink.java:357)
at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink.ready(HttpDispatcherLink.java:317)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleDiscrimination(HttpInboundLink.java:471)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.handleNewRequest(HttpInboundLink.java:405)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.processRequest(HttpInboundLink.java:285)
at com.ibm.ws.http.channel.internal.inbound.HttpInboundLink.ready(HttpInboundLink.java:256)
at com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.sendToDiscriminators(NewConnectionInitialReadCallback.java:174)
at com.ibm.ws.tcpchannel.internal.NewConnectionInitialReadCallback.complete(NewConnectionInitialReadCallback.java:83)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.requestComplete(WorkQueueManager.java:504)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.attemptIO(WorkQueueManager.java:574)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager.workerRun(WorkQueueManager.java:929)
at com.ibm.ws.tcpchannel.internal.WorkQueueManager$Worker.run(WorkQueueManager.java:1018)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1153)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.lang.Thread.run(Thread.java:785)
Caused by: es.aeat.adws.jdit.api.xml.XmlExcepcion: No se permite contenido en el prólogo. (1,1)
at es.aeat.adws.jdit.imp.xml.DomUtilsImpl.isToDoc(DomUtilsImpl.java:85)
at es.aeat.adws.jdit.imp.xml.DomUtilsImpl.isToDoc(DomUtilsImpl.java:51)
at es.aeat.adws.jdit.imp.ws.WSFilterSrvImpl.verificarFirma(WSFilterSrvImpl.java:781)
... 31 more
Caused by: org.xml.sax.SAXParseException: No se permite contenido en el prólogo.
at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source)
at org.apache.xerces.util.ErrorHandlerWrapper.fatalError(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source)
at org.apache.xerces.impl.XMLScanner.reportFatalError(Unknown Source)
at org.apache.xerces.impl.XMLDocumentScannerImpl$PrologDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
at org.apache.xerces.parsers.DOMParser.parse(Unknown Source)
at org.apache.xerces.jaxp.DocumentBuilderImpl.parse(Unknown Source)
at javax.xml.parsers.DocumentBuilder.parse(Unknown Source)
at es.aeat.adws.jdit.imp.xml.DomUtilsImpl.isToDoc(DomUtilsImpl.java:81)
... 33 more
According to error, it might seem that the error is in the XML file, but I assure you that it is not. This file can be sent perfectly from the enabled environment of the tax agency without problems, and it can also be sent using an external application (SoapUI)
Last considerations
In some web page I saw that they exported the CA of the certificate to later use it in cURL (I previously added the instruction that would allow the CA to be extracted). However, in most of the consulted sites they do not use this CA.
At an informative level, using said CA generates the following warning:
curl.exe [...] --cacert C:\VariasSII\Certificados\Certificado-CA.pem
curl: (60) SSL certificate problem: self signed certificate in certificate chain
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
I am convinced that the problem is in the certificate. But taking into account that the certificate.pfx works fine (I have tested it with SoapUI, and I have exported it to another computer, being able to use that certificate on that computer without problems) ... I would be left to think that something is wrong when converting that . pfx in .pem when using OpenSSL? The steps in OpenSSL and cURL I found on the net, and have checked with all possible sources. It works fine for people. But I'm not moving on from here.
Hopefully someone can shed some light on this problem.
I modify the answer since it seems that the problem in your case was not with the certificate but with the cURL parameters.
How to make the call from cURL
Part by part:
--cert ./ALEXANDRU_CATALIN_bundle.pem
set the certificate--header "Content-Type: text/xml;charset=UTF-8"
indicates type of content sent--header "SOAPAction: SuministroLRFacturasEmitidas"
indicates the webservice command we want to call--data @datos_xml.txt
specifies the file with the data, IMPORTANT apparently the@
one in front of the file path is a very important detail since it is what tells cURL that it should read from a fileContent
datos_xml.txt
:Response:
How to get valid PEM bundle certificate
I tell you the steps to obtain a valid certificate, but first two notes:
Here we go..
These are the commands to execute with
openssl
:With these commands you extract the certificate on the one hand and the private key on the other, examples:
Content
archivo_mycert.pem
:Content
archivo_mykey.pem
:Next, what you must do is create a third file that we will call it
archivo_bundle.pem
and where within this file we paste the contents of the certificate and the key, leaving something like this:Done, now you will use the file
archivo_bundle.pem
as a parameter in your cURL or SoapClient call.Finally, let me tell you that at http://www.aeatsiidesarrolladores.es/ I have written a technical ebook on the implementation of the SII. It contains examples of code in PHP and a mini application that has the entire communication circuit with the SII, which only needs to be uploaded to a server and leave a certificate in PFX format and it is already operational. You might be interested in taking a look! Luck! :-)