Curl SSL verify error

Hello,
My domain is:ssl.othing.xyz
The webpage can be opened normally,But something went wrong in cURL.
I ran this command:
curl -kvslI https://ssl.othing.xyz
or
sudo curl -kvslI https://ssl.othing.xyz --cacert /etc/ssl/certs/ca-certificates.crt

It produced this output:

*   Trying 2606:50c0:8000::153:443...
* Connected to ssl.othing.xyz (2606:50c0:8000::153) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=ssl.othing.xyz
*  start date: Nov 21 13:24:02 2021 GMT
*  expire date: Feb 19 13:24:01 2022 GMT
*  issuer: C=US; O=Let's Encrypt; CN=R3
***  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.**
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x559ed0153800)

As you can see

SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway

Why is it so?

My web server is (include version): github pages
My computer:

curl 7.80.0 (x86_64-pc-linux-gnu) libcurl/7.80.0 OpenSSL/1.1.1l zlib/1.2.11 brotli/1.0.9 zstd/1.5.0 libidn2/2.3.2 libpsl/0.21.1 (+libidn2/2.3.0) libssh2/1.10.0 nghttp2/1.46.0
Linux 5.14.21-2-MANJARO #1 SMP PREEMPT Sun Nov 21 22:43:47 UTC 2021 x86_64 GNU/Linux
1 Like

You might need to update ca-certificates

1 Like

$ trust list | grep "ISRG"
label: ISRG Root X1

pkcs11:id=%79%B4%59%E6%7B%B6%E5%E4%01%73%80%08%88%C8%1A%58%F6%E9%9B%6E;type=cert
    type: certificate
    label: ISRG Root X1
    trust: anchor
    category: authority

ISRG appears to be on the trust list

1 Like

Let's confirm OpenSSL, with:

openssl version

echo | openssl s_client -connect ssl.othing.xyz:443 -servername ssl.othing.xyz | head

1 Like

OpenSSL 1.1.1l 24 Aug 2021
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = ssl.othing.xyz
verify return:1
CONNECTED(00000003)

Certificate chain
0 s:CN = ssl.othing.xyz
i:C = US, O = Let's Encrypt, CN = R3
1 s:C = US, O = Let's Encrypt, CN = R3
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
2 s:C = US, O = Internet Security Research Group, CN = ISRG Root X1
i:O = Digital Signature Trust Co., CN = DST Root CA X3

DONE

1 Like

My requirement is to build a ssl monitoring website, monitoring more than 700 domain names and show the invalid ones. If curl can't return the correct result, there will be problems with the monitoring page.

1 Like

You showed ISRG in your PKCS11 store but what about the other store you showed in your second curl example? What is result of this:

grep -E "ISRG Root|DST Root" /etc/ssl/certs/ca-certificates.crt

Should show at least one of these

3 Likes

Well there seems to be a problem with your curl.
It shows:

But your OpenSSL has no problem with that site.
Let's try other sites just to be sure:
https://helloworld.letsencrypt.org
https://acme-staging-v02.api.letsencrypt.org

The possibility still exists that it's NOT your curl:

Name:    saveweb.github.io
Addresses: 2606:50c0:8002::153
           2606:50c0:8003::153
           2606:50c0:8000::153
           2606:50c0:8001::153
           185.199.108.153
           185.199.109.153
           185.199.110.153
           185.199.111.153
Aliases:   ssl.othing.xyz
2 Likes

$ grep -E "ISRG Root|DST Root" /etc/ssl/certs/ca-certificates.crt

DST Root CA X3

ISRG Root X1

2 Likes

curl -kvslI https://helloworld.letsencrypt.org

  • Trying 52.9.173.94:443...
  • Connected to helloworld.letsencrypt.org (52.9.173.94) port 443 (#0)
  • ALPN, offering h2
  • ALPN, offering http/1.1
  • TLSv1.3 (OUT), TLS handshake, Client hello (1):
  • TLSv1.3 (IN), TLS handshake, Server hello (2):
  • TLSv1.2 (IN), TLS handshake, Certificate (11):
  • TLSv1.2 (IN), TLS handshake, Server key exchange (12):
  • TLSv1.2 (IN), TLS handshake, Server finished (14):
  • TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
  • TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
  • TLSv1.2 (OUT), TLS handshake, Finished (20):
  • TLSv1.2 (IN), TLS handshake, Finished (20):
  • SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
  • ALPN, server accepted to use h2
  • Server certificate:
  • subject: CN=helloworld.letsencrypt.org
  • start date: Oct 27 15:00:22 2021 GMT
  • expire date: Jan 25 15:00:21 2022 GMT
  • issuer: C=US; O=Let's Encrypt; CN=R3
  • SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
  • Using HTTP2, server supports multiplexing
  • Connection state changed (HTTP/2 confirmed)
  • Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
  • Using Stream ID: 1 (easy handle 0x55d781c76800)

Looks the same error.Not only is there a problem with let’s encrypt certificate.The same error occurs in other certs.
For example,

  • Server certificate:
  • subject: CN=*.lenciel.com
  • start date: Oct 25 09:41:36 2021 GMT
  • expire date: Nov 26 09:41:36 2022 GMT
  • issuer: C=BE; O=GlobalSign nv-sa; CN=AlphaSSL CA - SHA256 - G2
  • SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.

If it is really a problem with curl, where can I get help?

2 Likes

Well, lenciel is not the best example as that site does not send intermediates. My openssl verify fails (as does my curl) and you can see that here too:
https://decoder.link/sslchecker/lenciel.com/443

You could try something like digicert.com for a non-LE test

3 Likes

Did this one return the same error?:

2 Likes

What about?:
trust list | grep "R3"

3 Likes

Thanks for your help. I just finished a week of high school studies, sorry for the late reply.

Yes, the same error :

curl -kvslI https://acme-staging-v02.api.letsencrypt.org

  • Trying 2606:4700:60:0:f41b:d4fe:4325:6026:443...
  • Connected to acme-staging-v02.api.letsencrypt.org (2606:4700:60:0:f41b:d4fe:4325:6026) port 443 (#0)
  • ALPN, offering h2
  • ALPN, offering http/1.1
  • TLSv1.3 (OUT), TLS handshake, Client hello (1):
  • TLSv1.3 (IN), TLS handshake, Server hello (2):
  • TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
  • TLSv1.3 (IN), TLS handshake, Certificate (11):
  • TLSv1.3 (IN), TLS handshake, CERT verify (15):
  • TLSv1.3 (IN), TLS handshake, Finished (20):
  • TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
  • TLSv1.3 (OUT), TLS handshake, Finished (20):
  • SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
  • ALPN, server accepted to use h2
  • Server certificate:
  • subject: CN=acme-staging-v02.api.letsencrypt.org
  • start date: Nov 29 03:20:57 2021 GMT
  • expire date: Feb 27 03:20:56 2022 GMT
  • issuer: C=US; O=Let's Encrypt; CN=R3
  • SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
1 Like

trust list | grep "R3"

label: GlobalSign Root CA - R3
label: GTS Root R3

Please show:
cat /etc/os-release
echo | openssl s_client -connect acme-v02.api.letsencrypt.org:443 | head

2 Likes

NAME="Manjaro Linux"
ID=manjaro
ID_LIKE=arch
BUILD_ID=rolling
PRETTY_NAME="Manjaro Linux"
ANSI_COLOR="32;1;24;144;200"
HOME_URL="https://manjaro.org/"
DOCUMENTATION_URL="https://wiki.manjaro.org/"
SUPPORT_URL="https://manjaro.org/"
BUG_REPORT_URL="https://bugs.manjaro.org/"
LOGO=manjarolinux

echo | openssl s_client -connect acme-v02.api.letsencrypt.org:443 | head                                                
depth=2 C = US, O = Internet Security Research Group, CN = ISRG Root X1
verify return:1
depth=1 C = US, O = Let's Encrypt, CN = R3
verify return:1
depth=0 CN = acme-v02.api.letsencrypt.org
verify return:1
CONNECTED(00000003)
---
Certificate chain
 0 s:CN = acme-v02.api.letsencrypt.org
   i:C = US, O = Let's Encrypt, CN = R3
 1 s:C = US, O = Let's Encrypt, CN = R3
   i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
---
Server certificate
-----BEGIN CERTIFICATE-----
DONE

1 Like

OpenSSL is good.
Let's try specifying the ca-cert file:

curl --cacert /etc/ssl/certs/ca-certificates.crt -vsI \
https://acme-v02.api.letsencrypt.org/
2 Likes
curl --cacert /etc/ssl/certs/ca-certificates.crt -vsI \                                                                 
https://acme-v02.api.letsencrypt.org/
*   Trying 2606:4700:60:0:f53d:5624:85c7:3a2c:443...
* Connected to acme-v02.api.letsencrypt.org (2606:4700:60:0:f53d:5624:85c7:3a2c) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=acme-v02.api.letsencrypt.org
*  start date: Nov 29 09:56:06 2021 GMT
*  expire date: Feb 27 09:56:05 2022 GMT
*  subjectAltName: host "acme-v02.api.letsencrypt.org" matched cert's "acme-v02.api.letsencrypt.org"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x55bcad290800)
> HEAD / HTTP/2
> Host: acme-v02.api.letsencrypt.org
> user-agent: curl/7.80.0
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
< HTTP/2 200 
HTTP/2 200 
< server: nginx
server: nginx
< date: Sat, 04 Dec 2021 12:16:53 GMT
date: Sat, 04 Dec 2021 12:16:53 GMT
< content-type: text/html
content-type: text/html
< content-length: 2174
content-length: 2174
< last-modified: Wed, 18 Aug 2021 16:35:58 GMT
last-modified: Wed, 18 Aug 2021 16:35:58 GMT
< etag: "611d36ee-87e"
etag: "611d36ee-87e"
< x-frame-options: DENY
x-frame-options: DENY
< strict-transport-security: max-age=604800
strict-transport-security: max-age=604800

< 
* Connection #0 to host acme-v02.api.letsencrypt.org left intact
1 Like

OK, so curl just doesn't know where to find the ca-cert file.
Now you know what to fix.

1 Like