diff --git a/daemon/lua/kluautil.lua b/daemon/lua/kluautil.lua index 1ab6d5356979d6751a9ecd72d00a1b268a5b23d2..158927914d96c5f30d5f94642265e88842ed352b 100644 --- a/daemon/lua/kluautil.lua +++ b/daemon/lua/kluautil.lua @@ -8,3 +8,39 @@ function kr_table_len (t) return len end +-- Fetch over HTTPS +function kr_https_fetch (url, ca_file, file) + local http_ok, http_request = pcall(require, 'http.request') + local openssl_ok, openssl_ctx = pcall(require, 'openssl.ssl.context') + + if not http_ok or not openssl_ok then + return nil, 'error: lua-http and luaossl libraries are missing (but required)' + end + + assert(string.match(url, '^https://')) + assert(ca_file) + + local req = http_request.new_from_uri(url) + req.ctx = openssl_ctx.new() + local store = req.ctx:getStore() + store:add(ca_file) + + req.ctx:setVerify(openssl_ctx.VERIFY_PEER) + req.tls = true + + local headers, stream = req:go() + assert(headers, 'HTTP client library error') + if headers:get(':status') ~= "200" then + return nil, headers:get(':status') + end + + local err, errmsg = stream:save_body_to_file(file) + if err == nil then + return err, errmsg + end + + file:seek ("set", 0) + + return true +end + diff --git a/daemon/lua/trust_anchors.lua.in b/daemon/lua/trust_anchors.lua.in index 87135c81aa46358a57d015b22949236089aa93a0..2676a6a3398f3d5eb018c48247ecbf9ac2558128 100644 --- a/daemon/lua/trust_anchors.lua.in +++ b/daemon/lua/trust_anchors.lua.in @@ -22,32 +22,6 @@ local function upgrade_required(msg) end -- TODO: Move bootstrap to a separate module or even its own binary --- Fetch over HTTPS with peert cert checked -local function https_fetch(url, ca) - local http_ok, http_request = pcall(require, 'http.request') - local openssl_ok, openssl_ctx = pcall(require, 'openssl.ssl.context') - - if not http_ok or not openssl_ok then - return nil, 'error: lua-http and luaossl libraries are missing (but required) for root TA bootstrap' - end - - local request = http_request.new_from_uri(url) - request.ctx = openssl_ctx.new('TLSv1_2') - local store = request.ctx:getStore() - store:add(ca) - - request.ctx:setVerify(openssl_ctx.VERIFY_PEER) - request.tls = true - - local headers, stream = request:go() - if headers == nil then return nil, 'HTTP client library error' end - if headers:get(':status') ~= "200" then return nil, headers:get(':status') end - - local resp, err = stream:get_body_as_string() - - return resp, err or "" -end - -- remove UTC timezone specification if present or throw error local function time2utc(orig_timespec) local patterns = {'[+-]00:00$', 'Z$'} @@ -144,15 +118,21 @@ end -- Fetch root anchors in XML over HTTPS, returning a zone-file-style string -- or false in case of error, and a message. local function bootstrap(url, ca) + local kluautil = pcall(require, 'kluautil') + local file = io.tmpfile() -- RFC 7958, sec. 2, but we don't do precise XML parsing. -- @todo ICANN certificate is verified against current CA -- this is not ideal, as it should rather verify .xml signature which -- is signed by ICANN long-lived cert, but luasec has no PKCS7 - local xml, err = https_fetch(url, ca) - if not xml then - return false, string.format('[ ta ] fetch of "%s" failed: %s', url, err) + local rcode, errmsg = kluautil.kr_https_fetch(url, ca, file) + if rcode == nil then + file:close() + return false, string.format('[ ta ] fetch of "%s" failed: %s', url, errmsg) end + local xml = file:read("*a") + file:close() + -- we support only minimal subset of https://tools.ietf.org/html/rfc7958 assert_str_match(xml, '<?xml version="1%.0" encoding="UTF%-8"%?>', 1) assert_str_match(xml, '<TrustAnchor ', 1) diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua index c5775aae72635ac64a0698f6f439333a3ce6108a..d9da4d80031d8c7e4ca01003e7cb0ae442ac66d2 100644 --- a/modules/policy/policy.lua +++ b/modules/policy/policy.lua @@ -13,7 +13,7 @@ end -- Support for client sockets from inside policy actions local socket_client = function () - return error("missing lua-cqueues library, can't create socket client") + return error("missing lua-cqueues library, can't create socket client") end local has_socket, socket = pcall(require, 'cqueues.socket') if has_socket then diff --git a/modules/prefill/prefill.lua b/modules/prefill/prefill.lua index 821e8bb8f4149525db75fb51459bb63b7d250cdf..aa2246eea89746e795bf9d3336d0202ee8a84cd5 100644 --- a/modules/prefill/prefill.lua +++ b/modules/prefill/prefill.lua @@ -16,50 +16,6 @@ local rz_interval_min = 3600 local prefill = { } - --- Fetch over HTTPS -local function https_fetch(url, ca_file, fname) - local http_ok, http_request = pcall(require, 'http.request') - local openssl_ok, openssl_ctx = pcall(require, 'openssl.ssl.context') - - if not http_ok or not openssl_ok then - return nil, 'lua-http and luaossl needed for root TA bootstrap' - end - - assert(string.match(url, '^https://')) - assert(ca_file) - - local req = http_request.new_from_uri(url) - req.ctx = openssl_ctx.new() - local store = req.ctx:getStore() - store:add(ca_file) - - req.ctx:setVerify(openssl_ctx.VERIFY_PEER) - req.tls = true - - local headers, stream = req:go() - assert(headers, 'HTTP client library error') - if headers:get(':status') ~= "200" then - return nil, headers:get(':status') - end - - local file, errmsg = io.open(fname, 'w') - if not file then - error(string.format("[prefill] unable to open file %s (%s)", - fname, errmsg)) - end - - local err - err, errmsg = stream:save_body_to_file(file) - if err == nil then - return err, errmsg - end - - file:close() - - return file -end - local function display_delay(time) local days = math.floor(time / 86400) local hours = math.floor((time % 86400) / 3600) @@ -93,11 +49,21 @@ local function get_file_ttl(fname) end local function download(url, fname) + local kluautil = pcall(require, 'kluautil') + local file, rcode, errmsg + file, errmsg = io.open(fname, 'w') + if not file then + error(string.format("[prefill] unable to open file %s (%s)", + fname, errmsg)) + end + log("[prefill] downloading root zone to file %s ...", fname) - local rzone, err = https_fetch(url, rz_ca_file, fname) - if rzone == nil then - error(string.format("[prefill] fetch of `%s` failed: %s", url, err)) + rcode, errmsg = kluautil.kr_https_fetch(url, rz_ca_file, file) + if rcode == nil then + error(string.format("[prefill] fetch of `%s` failed: %s", url, errmsg)) end + + file:close() end local function import(fname)