Invalidate cache when cert content changes

This commit is contained in:
Dayang Shen 2024-01-30 23:37:23 +08:00
parent ed0d4f23b7
commit a2be8cd691
2 changed files with 41 additions and 10 deletions

View file

@ -225,7 +225,7 @@ end
function _M.set_cache_size(size)
local cache, err = lrucache.new(size)
if not cache then
if err then
ngx.log(ngx.ERR, string.format("failed to create the certificate cache: %s", err))
end
certificate_cache = cache
@ -257,19 +257,21 @@ function _M.call()
return
end
local pem_cert = certificate_data:get(pem_cert_uid)
if not pem_cert then
ngx.log(ngx.ERR, "certificate not found, falling back to fake certificate for hostname: "
.. tostring(hostname))
return
end
local cert_crc32 = ngx.crc32_long(pem_cert)
local cached_entry = certificate_cache:get(pem_cert_uid)
if cached_entry then
if cached_entry and cached_entry.crc32 == cert_crc32 then
cert = cached_entry.cert
priv_key = cached_entry.priv_key
der_cert = cached_entry.der_cert
else
local pem_cert = certificate_data:get(pem_cert_uid)
if not pem_cert then
ngx.log(ngx.ERR, "certificate not found, falling back to fake certificate for hostname: "
.. tostring(hostname))
return
end
der_cert, der_cert_err = ssl.cert_pem_to_der(pem_cert)
if not der_cert then
ngx.log(ngx.ERR, "failed to convert certificate chain from PEM to DER: " .. der_cert_err)
@ -282,7 +284,13 @@ function _M.call()
return ngx.exit(ngx.ERROR)
end
certificate_cache:set(pem_cert_uid, { cert = cert, priv_key = priv_key, der_cert = der_cert })
cached_entry = {
cert = cert,
priv_key = priv_key,
der_cert = der_cert,
crc32 = cert_crc32
}
certificate_cache:set(pem_cert_uid, cached_entry)
end
local clear_ok, clear_err = ssl.clear_certs()

View file

@ -94,6 +94,29 @@ describe("Certificate", function()
assert_certificate_is_set(EXAMPLE_CERT)
end)
it("parses certificate and key once when cache hits", function()
spy.on(ssl, "parse_pem_cert")
set_certificate("hostname", EXAMPLE_CERT, UUID)
assert_certificate_is_set(EXAMPLE_CERT)
assert_certificate_is_set(EXAMPLE_CERT)
assert.spy(ssl.parse_pem_cert).was.called(1)
end)
it("parses certificate and key again when cache hits but cert content changes", function()
spy.on(ssl, "parse_pem_cert")
set_certificate("hostname", EXAMPLE_CERT, UUID)
assert_certificate_is_set(EXAMPLE_CERT)
set_certificate("hostname", DEFAULT_CERT, UUID)
assert_certificate_is_set(DEFAULT_CERT)
assert.spy(ssl.parse_pem_cert).was.called(2)
end)
it("sets certificate and key for wildcard cert", function()
ssl.server_name = function() return "sub.hostname", nil end
set_certificate("*.hostname", EXAMPLE_CERT, UUID)