{"id":11503,"date":"2018-11-07T07:58:20","date_gmt":"2018-11-07T06:58:20","guid":{"rendered":"https:\/\/daniel.haxx.se\/blog\/?p=11503"},"modified":"2024-01-31T09:09:53","modified_gmt":"2024-01-31T08:09:53","slug":"get-the-ca-cert-for-curl","status":"publish","type":"post","link":"https:\/\/daniel.haxx.se\/blog\/2018\/11\/07\/get-the-ca-cert-for-curl\/","title":{"rendered":"Get the CA cert for curl"},"content":{"rendered":"\n<p>When you use curl to communicate with a HTTPS site (or any other protocol that uses TLS), it will by default verify that the server is signed by a trusted Certificate Authority (CA). It does this by checking the CA bundle it was built to use, or instructed to use with the <a href=\"https:\/\/curl.se\/docs\/manpage.html#--cacert\">&#8211;cacert<\/a> command line option.<\/p>\n\n\n\n<p>Sometimes you end up in a situation where you don&#8217;t have the necessary CA cert in your bundle. It could then look something like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><span style=\"color: #ff0000;\">$ curl https:\/\/example.com\/\ncurl: (60) SSL certificate problem: self signed certificate\nMore details here: https:\/\/curl.se\/docs\/sslcerts.html<\/span><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Do not disable!<\/h2>\n\n\n\n<p>A first gut reaction could be to disable the certificate check. Don&#8217;t do that. You&#8217;ll just make that end up in production or get copied by someone else and then you&#8217;ll spread the insecure use to other places and eventually cause a security problem.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Get the CA cert<\/h2>\n\n\n\n<p>I&#8217;ll show you four different ways to fix this.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">1. Update your OS CA store<\/h5>\n\n\n\n<p>Operating systems come with a CA bundle of their own and on most of them, curl is setup to use the system CA store. A system update often makes curl work again.<\/p>\n\n\n\n<p>This of course doesn&#8217;t help you if you have a self-signed certificate or otherwise use a CA that your operating system doesn&#8217;t have in its trust store.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">2. Get an updated CA bundle from us<\/h5>\n\n\n\n<p>curl can be told to use a separate stand-alone file as CA store, and conveniently enough curl provides <a href=\"https:\/\/curl.se\/docs\/caextract.html\">an updated one on the curl web site<\/a>. That one is automatically converted from the one Mozilla provides for Firefox, updated daily. It also provides a little backlog so the ten most recent CA stores are available.<\/p>\n\n\n\n<p>If you agree to trust the same CAs that Firefox trusts. This is a good choice.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">3. Get it with openssl<\/h5>\n\n\n\n<p>Now we&#8217;re approaching the less good options. It&#8217;s way better to get the CA certificates via other means than from the actual site you&#8217;re trying to connect to!<\/p>\n\n\n\n<p>This method uses the <a href=\"https:\/\/www.openssl.org\/docs\/man1.1.0\/apps\/openssl.html\">openssl command line tool<\/a>. The servername option used below is there to set the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Server_Name_Indication\">SNI field<\/a>, which often is necessary to tell the server which actual site&#8217;s certificate you want.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><span style=\"color: #0000ff;\">$ echo quit | openssl s_client -showcerts -servername server -connect server:443 &gt; cacert.pem<\/span><\/pre>\n\n\n\n<p>A real world example, getting the certs for daniel.haxx.se and then getting the main page with curl using them:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><span style=\"color: #0000ff;\">$ echo quit | openssl s_client -showcerts -servername daniel.haxx.se -connect daniel.haxx.se:443 &gt; cacert.pem\n\n$ curl --cacert cacert.pem https:\/\/daniel.haxx.se\n<\/span><\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">4. Get it with Firefox<\/h5>\n\n\n\n<p>Suppose you&#8217;re browsing the site already fine with Firefox. Then you can do inspect it using the browser and export to use with curl.<\/p>\n\n\n\n<p>Step 1 &#8211; click the i in the circle on the left of the URL in the address bar of your browser.<\/p>\n\n\n\n<p>Step 2 &#8211; click the right arrow on the right side in the drop-down window that appeared.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/site-information.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"718\" height=\"539\" src=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/site-information.jpg\" alt=\"\" class=\"wp-image-11511\" srcset=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/site-information.jpg 718w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/site-information-200x150.jpg 200w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/site-information-450x338.jpg 450w\" sizes=\"auto, (max-width: 718px) 100vw, 718px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>Step 3 &#8211; new contents appeared, now click the &#8220;More Information&#8221; at the bottom, which pops up a new separate window&#8230;<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/more-information.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"731\" height=\"523\" src=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/more-information.jpg\" alt=\"\" class=\"wp-image-11512\" srcset=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/more-information.jpg 731w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/more-information-200x143.jpg 200w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/more-information-450x322.jpg 450w\" sizes=\"auto, (max-width: 731px) 100vw, 731px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>Step 4 &#8211; Here you get security information from Firefox about the site you&#8217;re visiting. Click the &#8220;View Certificate&#8221; button on the right. It pops up yet another separate window.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/viewcert.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"821\" height=\"669\" src=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/viewcert.jpg\" alt=\"\" class=\"wp-image-11513\" srcset=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/viewcert.jpg 821w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/viewcert-200x163.jpg 200w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/viewcert-450x367.jpg 450w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/viewcert-768x626.jpg 768w\" sizes=\"auto, (max-width: 821px) 100vw, 821px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>Step 5 &#8211; in this window full of certificate information, select the &#8220;Details&#8221; tab&#8230;<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/details.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"826\" height=\"726\" src=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/details.jpg\" alt=\"\" class=\"wp-image-11514\" srcset=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/details.jpg 826w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/details-200x176.jpg 200w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/details-450x396.jpg 450w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/details-768x675.jpg 768w\" sizes=\"auto, (max-width: 826px) 100vw, 826px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>Step 6 &#8211; when switched to the details tab, there&#8217;s the certificate hierarchy shown at the top and we select the top choice there. This list will of course look different for different sites<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/export.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"829\" height=\"728\" src=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/export.jpg\" alt=\"\" class=\"wp-image-11515\" srcset=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/export.jpg 829w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/export-200x176.jpg 200w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/export-450x395.jpg 450w, https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2018\/08\/export-768x674.jpg 768w\" sizes=\"auto, (max-width: 829px) 100vw, 829px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p>Step 7 &#8211; now click the &#8220;Export&#8221; tab at the bottom left and save the file (that uses a .crt extension) somewhere suitable.<\/p>\n\n\n\n<p>If you for example saved the exported certificate using in \/tmp, you could then use curl with that saved certificate something like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><span style=\"color: #0000ff;\">$ curl --cacert \/tmp\/GlobalSignRootCA-R3.crt https:\/\/curl.se<\/span><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">But I&#8217;m not using openssl!<\/h2>\n\n\n\n<p>This description assumes you&#8217;re using a curl that uses a CA bundle in the PEM format, which not all do &#8211; in particular not the ones built with NSS, Schannel (native Windows) or Secure Transport (native macOS and iOS) don&#8217;t.<\/p>\n\n\n\n<p>If you use one of those, you need to then add additional command to import the PEM formatted cert into the particular CA store of yours.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A CA store is many PEM files concatenated<\/h2>\n\n\n\n<p>Just concatenate many different PEM files into a single file to create a CA store with multiple certificates.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you use curl to communicate with a HTTPS site (or any other protocol that uses TLS), it will by default verify that the server is signed by a trusted Certificate Authority (CA). It does this by checking the CA bundle it was built to use, or instructed to use with the &#8211;cacert command line &hellip; <a href=\"https:\/\/daniel.haxx.se\/blog\/2018\/11\/07\/get-the-ca-cert-for-curl\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Get the CA cert for curl<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":5,"featured_media":11526,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7,393,133],"tags":[33,86,193,381],"class_list":["post-11503","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-curl","category-firefox-floss","category-security","tag-curl-and-libcurl","tag-firefox","tag-openssl","tag-tls"],"_links":{"self":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/11503","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/comments?post=11503"}],"version-history":[{"count":23,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/11503\/revisions"}],"predecessor-version":[{"id":24159,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/11503\/revisions\/24159"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/media\/11526"}],"wp:attachment":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/media?parent=11503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/categories?post=11503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/tags?post=11503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}