From cff435f67f3f0810278b0a29a67d0af96ccfa0de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Je=C5=BEek?= <lukas.jezek@nic.cz>
Date: Thu, 19 Dec 2019 11:28:02 +0100
Subject: [PATCH] modules/prefill and TA: Move https_fetch to
 daemon/lua/kluautil.lua

---
 daemon/lua/kluautil.lua         | 36 ++++++++++++++++++++
 daemon/lua/trust_anchors.lua.in | 38 +++++----------------
 modules/policy/policy.lua       |  2 +-
 modules/prefill/prefill.lua     | 60 +++++++--------------------------
 4 files changed, 59 insertions(+), 77 deletions(-)

diff --git a/daemon/lua/kluautil.lua b/daemon/lua/kluautil.lua
index 1ab6d5356..158927914 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 87135c81a..2676a6a33 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 c5775aae7..d9da4d800 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 821e8bb8f..aa2246eea 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)
-- 
GitLab