7

I want to make a GET request to https://www.bnro.ro/nbrfxrates.xml (the National Bank of Romania) to get the exchange rates for today.

While the XML document loads fine in the browser (tested in Safari and Chrome), it somehow fails in the terminal (checked with Node.js and curl):

$ curl -vL http://www.bnro.ro/nbrfxrates.xml
* Expire in 0 ms for 6 (transfer 0x7f8a5c009c00)
* Expire in 1 ms for 1 (transfer 0x7f8a5c009c00)
...
* Expire in 5 ms for 1 (transfer 0x7f8a5c009c00)
*   Trying 194.102.208.89...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x7f8a5c009c00)
* Connected to www.bnro.ro (194.102.208.89) port 80 (#0)
> GET /nbrfxrates.xml HTTP/1.1
> Host: www.bnro.ro
> User-Agent: curl/7.64.0
> Accept: */*
> 
< HTTP/1.1 302 Found
< Date: Fri, 14 Jun 2019 11:13:13 GMT
< Location: https://www.bnro.ro/nbrfxrates.xml
< Server: BigIP
< Content-Length: 0
< X-Cache: MISS from HS-F0
< X-Cache-Lookup: MISS from HS-F0:0
< Via: 1.1 HS-F0 (squid/3.4.8)
< Connection: keep-alive
< 
* Connection #0 to host www.bnro.ro left intact
* Issue another request to this URL: 'https://www.bnro.ro/nbrfxrates.xml'
* Expire in 1 ms for 1 (transfer 0x7f8a5c009c00)
* Expire in 0 ms for 1 (transfer 0x7f8a5c009c00)
...
* Expire in 1 ms for 1 (transfer 0x7f8a5c009c00)
*   Trying 194.102.208.89...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x7f8a5c009c00)
* Connected to www.bnro.ro (194.102.208.89) port 443 (#1)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /opt/local/share/curl/curl-ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, unknown CA (560):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 1
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

Both, curl and my Node.js app comaplain about the certificate.

In my Node.js script I get this error:

{ Error: unable to verify the first certificate
    at TLSSocket.<anonymous> (_tls_wrap.js:1104:38)
    at emitNone (events.js:105:13)
    at TLSSocket.emit (events.js:207:7)
    at TLSSocket._finishInit (_tls_wrap.js:638:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:468:38) code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' }

I tried to use the Copy as CURL command option from Chrome, and that does not work either.

Why is this happening? How can it be fixed?

Ionică Bizău
  • 109,027
  • 88
  • 289
  • 474

3 Answers3

1

a missing certificate bundle, read more about it here https://curl.haxx.se/docs/sslcerts.html but the TL;DR is download https://curl.haxx.se/ca/cacert.pem and run

curl -vL --cacert cacert.pem http://www.bnro.ro/nbrfxrates.xml
hanshenrik
  • 19,904
  • 4
  • 43
  • 89
  • That does work indeed, but how can I install that _globally_, so that other Terminal tools will be able to use it (such as my Node.js app)? – Ionică Bizău Jun 16 '19 at 05:26
  • @IonicăBizău good question, i'm not really sure, but if you're on linux, try saving cacert.pem as `/etc/ssl/cert.pem` - after some digging, it appears that curl will search the following locations for certificate bundles on linux systems: `/etc/ssl/certs/ca-certificates.crt` and `/etc/pki/tls/certs/ca-bundle.crt` and `/usr/share/ssl/certs/ca-bundle.crt` and `/usr/local/share/certs/ca-root-nss.crt` and `/etc/ssl/cert.pem` (source: https://github.com/curl/curl/blob/48016832dc179a6cfd819bb7925f4723904eaaaa/CMakeLists.txt ) - if you're on windows tho, i don't really know =/ – hanshenrik Jun 16 '19 at 08:20
  • @IonicăBizău if your Node app is using libcurl, then you can set `curl_easy_setopt(ch,CURLOPT_CAINFO,'/path/to/cacert.pem');` to manually specify where the cacert is located – hanshenrik Jun 16 '19 at 08:22
  • it is not related with client ssl conf,but the server certificate settings – focus zheng Mar 24 '22 at 06:56
1

Probably it is a misconfigured server. They used a wrong cert file (i.e, cert.pem instead of fullchain.pem). For example, if you use the "Let's encrypt" CA and python's ssl.wrap_socket you should write something like

httpd.socket = ssl.wrap_socket (httpd.socket, certfile='path/to/fullchain.pem', keyfile=path/to/privkey.pem' ,server_side=True, ssl_version=ssl.PROTOCOL_TLSv1_2)

If firefox opens the server and you cannot change the server configs and have to use curl,

  1. then download fullchain.pem via firefox (Security->View Certificate-> Miscellaneous -> Download PEM Chain)

  2. Now You can use curl with this chain.

curl --cacert downloaded_chain_for_the_site.pem https://site_name.com
serge
  • 11
  • 2
0

concatenate the CA Intermediate Certificate into your domain certificate

cat intermediate.crt >> domain.crt
ssl_certificate ssl/domain.crt; //your nginx server block

focus zheng
  • 345
  • 1
  • 4
  • 12