[Mac/Linux] 用 openssl 下載 HTTPS 網站憑證,解決 curl 抱怨 self-signed certificate 的問題

[Mac/Linux] 用 openssl 下載 HTTPS 網站憑證,解決 curl 抱怨 self-signed certificate 的問題

今天專案遇到一個問題,用 curl 去連一個 HTTPS 網站時,

出現 SSL certificate problem: self signed certificate in certificate chain 的錯誤…

例如我去連趨勢科技的 Site Safety Center

testuser@localhost ~ curl -v https://global.sitesafety.trendmicro.com/

......
* TLSv1.2 (OUT), TLS alert, Server hello (2):
* SSL certificate problem: self signed certificate in certificate chain
* Marked for [closure]: Failed HTTPS connection
......
curl: (60) SSL certificate problem: self signed certificate in certificate chain
More details here: https://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.

 

看起來是因為 curl 認不得這個網站的 HTTPS 憑證簽發者 (CA),

因此以為這個憑證是 self-signed…

平常的 Linux 平台上應該不會有這個問題,

但因為我們在一個沒有設定好 CA bundle (就是 CA 的憑證集合) 的機器上測試,

因此遇到了問題…

 

要解決這個問題,可以把網站憑證和其簽發者的憑證 (CA chain),

通通下載下來,再指定給 curl 使用~

可惜 curl 沒有指令可以下載網站憑證,因此只能用 openssl 的指令,例如:

testuser@localhost ~ echo -n | openssl s_client -connect global.sitesafety.trendmicro.com:443 -showcerts

depth=2 C = US, O = AffirmTrust, CN = AffirmTrust Commercial
verify error:num=19:self signed certificate in certificate chain
verify return:0
---
Certificate chain
 0 s:/C=US/ST=California/L=Cupertino/O=Trend Micro Inc./CN=*.sitesafety.trendmicro.com
   i:/C=US/O=Trend Micro Inc/CN=Trend Micro S2 CA
-----BEGIN CERTIFICATE-----
MIIF8zCCBNugAwIBAgIIAy0tVNSNHhcwDQYJKoZIhvcNAQELBQAwQzELMAkGA1UE
......
......
qVkWXRfA7j5K/PDQle7Otl/d1aWApQd2XBkzWtIayb8xNc1Hd02V
-----END CERTIFICATE-----
 1 s:/C=US/O=Trend Micro Inc/CN=Trend Micro S2 CA
   i:/C=US/O=AffirmTrust/CN=AffirmTrust Commercial
-----BEGIN CERTIFICATE-----
MIIEeDCCA2CgAwIBAgIIW0aZkOx1nTQwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
......
......
dVgSPCvYa7GGG8U43fUASqXwshoOpnbetI+zRN5aH1TtTK71e2kTqcqEckM=
-----END CERTIFICATE-----
 2 s:/C=US/O=AffirmTrust/CN=AffirmTrust Commercial
   i:/C=US/O=AffirmTrust/CN=AffirmTrust Commercial
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
......
......
nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
-----END CERTIFICATE-----
---
Server certificate
subject=/C=US/ST=California/L=Cupertino/O=Trend Micro Inc./CN=*.sitesafety.trendmicro.com
issuer=/C=US/O=Trend Micro Inc/CN=Trend Micro S2 CA

 

在上面的 openssl 指令中,因為有加上 -showcerts,

因此會把網站憑證與其所有的簽發者 (CA chain) 都列出來,

我們可以看到:

  • *.sitesafety.trendmicro.com 的憑證是由 Trend Micro S2 CA 簽發
  • Trend Micro S2 CA的憑證是由 AffirmTrust Commercial 簽發
  • AffirmTrust Commercial的憑證是由 AffirmTrust Commercial 簽發 (Root CA)

 

其中 —–BEGIN CERTIFICATE—– 和 —–END CERTIFICATE—– 包起來的,

就是一個 SSL 憑證,在此例中一共有三個 SSL 憑證。

我們可以利用 sed 指令,只將憑證的部分截取出來,儲存到一個檔案裡:

echo -n | openssl s_client -connect global.sitesafety.trendmicro.com:443 -showcerts | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > trendmicro.cert

 

截取出來的 trendmicro.cert 檔案就是所謂的 CA bundle file,

內容就是一堆簽章的集合:

-----BEGIN CERTIFICATE-----
MIIF8zCCBNugAwIBAgIIAy0tVNSNHhcwDQYJKoZIhvcNAQELBQAwQzELMAkGA1UE
......
......
qVkWXRfA7j5K/PDQle7Otl/d1aWApQd2XBkzWtIayb8xNc1Hd02V
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEeDCCA2CgAwIBAgIIW0aZkOx1nTQwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
......
......
dVgSPCvYa7GGG8U43fUASqXwshoOpnbetI+zRN5aH1TtTK71e2kTqcqEckM=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
......
......
nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
-----END CERTIFICATE-----

 

現在用 curl 加上 –cacert 參數指定 CA bundle file 的路徑,

再重新連線一次,可以看到這次連線就沒有 self-signed certificate 的問題了:

testuser@localhost ~ curl -v --cacert trendmicro.cert https://global.sitesafety.trendmicro.com/

......
* successfully set certificate verify locations:
*   CAfile: trendmicro.cert
......
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* Server certificate:
*  subject: C=US; ST=California; L=Cupertino; O=Trend Micro Inc.; CN=*.sitesafety.trendmicro.com
*  start date: Mar  2 14:02:51 2016 GMT
*  expire date: Mar  3 14:02:51 2018 GMT
*  subjectAltName: host "global.sitesafety.trendmicro.com" matched cert's "*.sitesafety.trendmicro.com"
*  issuer: C=US; O=Trend Micro Inc; CN=Trend Micro S2 CA
*  SSL certificate verify ok.
> GET / HTTP/1.1
> Host: global.sitesafety.trendmicro.com
> User-Agent: curl/7.51.0
> Accept: */*
>
< HTTP/1.1 200 OK
......

 

參考資料:how to download the ssl certificate from a website?

(本頁面已被瀏覽過 443 次)

發表迴響

你的電子郵件位址並不會被公開。