{"id":20655,"date":"2022-11-11T13:20:52","date_gmt":"2022-11-11T12:20:52","guid":{"rendered":"https:\/\/daniel.haxx.se\/blog\/?p=20655"},"modified":"2022-11-11T13:20:52","modified_gmt":"2022-11-11T12:20:52","slug":"curls-new-ca-store-cache","status":"publish","type":"post","link":"https:\/\/daniel.haxx.se\/blog\/2022\/11\/11\/curls-new-ca-store-cache\/","title":{"rendered":"curl&#8217;s new CA store cache"},"content":{"rendered":"\n<p>When setting up a TLS or QUIC connection, a client like curl needs a <em>CA store<\/em> in order to verify the certificate(s) the server provides in the TLS handshake.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">CA store<\/h2>\n\n\n\n<p>A CA store is a fancy name for a number of certificates. Certificates for the Certificate Authorities (CAs) that a TLS client trusts. On the curl website, we offer a <a href=\"https:\/\/curl.se\/docs\/caextract.html\">PEM version<\/a> of the CA store that Mozilla maintains, for download. This set currently contains 142 certificates and while the exact amount vary a little over time, it has been more than a hundred for many years. A fair amount. And there is nothing in the pipe that will bring down the number significantly anytime soon, to my knowledge. These 142 certificates make up a file that is exactly 225,403 bytes. 1587 bytes per certificate on average.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Load and parse<\/h2>\n\n\n\n<p>When setting up a TLS connection, the 142 certificates need to be loaded from the external file into memory and parsed so that the server&#8217;s certificate can be verified. So that curl knows that the server it has connected to is indeed the correct server and not a man in the middle, an impostor.<\/p>\n\n\n\n<p>This procedure is a rather costly one, in terms of CPU cycles needed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Another cache<\/h2>\n\n\n\n<p>A classic approach to avoid heavy work is to cache the results from a previous use to be able to reuse them again. Starting in curl 7.87.0 curl introduces a <em>CA store cache<\/em>.<\/p>\n\n\n\n<p>Now, curl can keep the loaded and parsed CA store in memory associated with the handle and then subsequent requests can avoid re-loading and re-parsing the CA data when new connections are created &#8211; if they use the same CA store of course. The performance gain in doing this shortcut can be enormous. After all, most transfers are done using the same single CA store.<\/p>\n\n\n\n<p>To quote the numbers Michael Drake presented in <a href=\"https:\/\/github.com\/curl\/curl\/pull\/9620\">the pull request for this new feature<\/a>. He measured number of instructions to load and render a particular web page from BBC with the <a href=\"https:\/\/www.netsurf-browser.org\/\">NetSurf<\/a> browser (which obviously is using libcurl for its HTTPS transfers). With and without this cache.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><tbody><tr><td><strong>CA store cache<\/strong><\/td><td><strong>Total instruction fetch cost<\/strong><\/td><\/tr><tr><td>None<\/td><td>5,168,090,712<\/td><\/tr><tr><td>Enabled<\/td><td>1,020,984,411<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>I think a reduction to one fifth of the original cost is significant.<\/p>\n\n\n\n<p>Converted into a little graph they compare like this (smaller is better):<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"600\" height=\"371\" src=\"https:\/\/daniel.haxx.se\/blog\/wp-content\/uploads\/2022\/11\/CA-cache-impact.png\" alt=\"\" class=\"wp-image-20700\"\/><\/figure>\n<\/div>\n\n\n<p>But even in simpler applications and curl command lines  this caching should have a measurable impact as soon as multiple TLS connections are done using the same handle. An extremely common usage pattern.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Life-time<\/h2>\n\n\n\n<p>Keeping the data around after use potentially changes the behavior a little, but the huge performance gain made us decide to still do this by default. We compensate this a little by setting the default life-time to 24 hours, so applications that keep handles alive for a very long time will still get the cache flushed and read from file again every day.<\/p>\n\n\n\n<p>The CA store is typically not updated more frequently than once every few months or weeks.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/curl.se\/libcurl\/c\/CURLOPT_CA_CACHE_TIMEOUT.html\">CURLOPT_CA_CACHE_TIMEOUT<\/a><\/h2>\n\n\n\n<p>This is a new option for libcurl that allows applications to tweak the life-time and CA cache behavior for when the default as described above is not enough.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Details<\/h2>\n\n\n\n<p>This CA cache system is so far only supported when curl is built to use OpenSSL or one of its forks. I hope others will get inspired and bring this support for other TLS backends as well as we go forward.<\/p>\n\n\n\n<p>CA cache support for curl was authored by Michael Drake. Thanks!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When setting up a TLS or QUIC connection, a client like curl needs a CA store in order to verify the certificate(s) the server provides in the TLS handshake. CA store A CA store is a fancy name for a number of certificates. Certificates for the Certificate Authorities (CAs) that a TLS client trusts. On &hellip; <a href=\"https:\/\/daniel.haxx.se\/blog\/2022\/11\/11\/curls-new-ca-store-cache\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">curl&#8217;s new CA store cache<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":5,"featured_media":19760,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[33,193,381],"class_list":["post-20655","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-curl","tag-curl-and-libcurl","tag-openssl","tag-tls"],"_links":{"self":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/20655","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=20655"}],"version-history":[{"count":36,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/20655\/revisions"}],"predecessor-version":[{"id":20715,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/posts\/20655\/revisions\/20715"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/media\/19760"}],"wp:attachment":[{"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/media?parent=20655"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/categories?post=20655"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/daniel.haxx.se\/blog\/wp-json\/wp\/v2\/tags?post=20655"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}