Skip to content

Commit

Permalink
Add support for OCSP
Browse files Browse the repository at this point in the history
  • Loading branch information
aledbf committed Jan 5, 2020
1 parent 9c0061f commit 088066c
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
1 change: 1 addition & 0 deletions build/test-lua.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ resty \
--shdict "balancer_ewma 1M" \
--shdict "balancer_ewma_last_touched_at 1M" \
--shdict "balancer_ewma_locks 512k" \
--shdict "ocsp_cache 1M" \
./rootfs/etc/nginx/lua/test/run.lua ${BUSTED_ARGS} ./rootfs/etc/nginx/lua/test/
1 change: 1 addition & 0 deletions internal/ingress/controller/template/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ var (
"balancer_ewma_last_touched_at": 10,
"balancer_ewma_locks": 1,
"certificate_servers": 5,
"ocsp_cache": 5, // 1MB ~100 responses
}
)

Expand Down
90 changes: 90 additions & 0 deletions rootfs/etc/nginx/lua/certificate.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
local ssl = require("ngx.ssl")
local configuration = require("configuration")
local re_sub = ngx.re.sub
local http = require "resty.http"
local ocsp = require "ngx.ocsp"

local certificate_servers = ngx.shared.certificate_servers

local _M = {}

Expand Down Expand Up @@ -48,6 +52,57 @@ local function get_pem_cert_key(raw_hostname)
return pem_cert_key
end

local function get_ocsp_response(pem_cert_key)
local der_cert_chain, der_cert_err = ssl.cert_pem_to_der(pem_cert_key)
if not der_cert_chain then
return nil, "failed to convert certificate chain from PEM to DER: " .. der_cert_err
end

local ocsp_url, ocsp_responder_err = ocsp.get_ocsp_responder_from_der_chain(der_cert_chain)
if not ocsp_url then
return nil, "failed to get OCSP URL: " .. (ocsp_responder_err or "")
end

local ocsp_req, ocsp_request_err = ocsp.create_ocsp_request(der_cert_chain)
if not ocsp_req then
return nil, "failed to create OCSP request: " .. (ocsp_request_err or "")
end

local httpc = http.new()
httpc:set_timeout(10000)

local res, req_err = httpc:request_uri(ocsp_url, {
method = "POST",
body = ocsp_req,
headers = {
["Content-Type"] = "application/ocsp-request",
}
})

-- Perform various checks to ensure we have a valid OCSP response.
if not res then
return nil, "OCSP responder query failed (" .. (ocsp_url or "") .. "): " .. (req_err or "")
end

if res.status ~= 200 then
return nil, "OCSP responder returns bad HTTP status code (" .. (ocsp_url or "") .. "): " .. (res.status or "")
end

httpc:set_keepalive()

local ocsp_resp = res.body
if not ocsp_resp or ocsp_resp == "" then
return nil, "OCSP responder returns bad response body (" .. (ocsp_url or "") .. "): " .. (ocsp_resp or "")
end

local ok, ocsp_validate_err = ocsp.validate_ocsp_response(ocsp_resp, der_cert_chain)
if not ok then
return nil, "failed to validate OCSP response (" .. (ocsp_url or "") .. "): " .. (ocsp_validate_err or "")
end

return ocsp_resp, nil
end

function _M.configured_for_current_request()
if ngx.ctx.configured_for_current_request ~= nil then
return ngx.ctx.configured_for_current_request
Expand Down Expand Up @@ -89,6 +144,41 @@ function _M.call()
ngx.log(ngx.ERR, set_pem_cert_key_err)
return ngx.exit(ngx.ERROR)
end

--- fake SSL certificate should not return OCSP responses
if hostname == DEFAULT_CERT_HOSTNAME then
return
end

--- only server names with a valid certificate can return OCSP responses
local cert_exists = certificate_servers:get(hostname)
if not cert_exists then
return
end

--- check if the OCSP response is in the cache
local ocsp_resp = ngx.shared.ocsp_cache:get(hostname)
if not ocsp_resp then
local ocsp_response_err
ocsp_resp, ocsp_response_err = get_ocsp_response(pem_cert_key)
if not ocsp_resp then
ngx.log(ngx.ERR, "failed to get OCSP response for hostname " .. hostname .. " : " .. ocsp_response_err)
return
end

local _, set_ocsp_err, set_ocsp_forcible = ngx.shared.ocsp_cache:set(hostname, ocsp_resp, 3600)
if set_ocsp_err then
ngx.log(ngx.ERR, "failed to set cache of OCSP response for " .. hostname .. ": ", set_ocsp_err)
elseif set_ocsp_forcible then
ngx.log(ngx.ERR, "'lua_shared_dict ocsp_cache' might be too small - consider increasing the size")
end
end

local ok, ocsp_status_err = ocsp.set_ocsp_status_resp(ocsp_resp)
if not ok then
ngx.log(ngx.ERR, "failed to set OCSP information: " .. ocsp_status_err)
end

end

return _M

0 comments on commit 088066c

Please sign in to comment.