Skip to content
Snippets Groups Projects
Unverified Commit c800fe7f authored by Matthias Schiffer's avatar Matthias Schiffer
Browse files

gluon-autoupdater: add support for HTTPS and protocol-less URLs


The autoupdater supports HTTPS when a ustream TLS backend is installed,
but we did not allow this in site.conf. However, just allowing HTTPS
URLs unconditionally is also a bad idea, as it might result in nodes
being unable to reach the mirror, in particular if the `tls` feature is
enabled only for some devices.

Solve this by allowing https:// URLs only if the marker file installed
by gluon-tls is found, failing the site check with an error message like
the following otherwise:

    *** All of the following alternatives have failed:
        1) site.conf error: expected autoupdater.branches.test.mirrors.1 to match pattern 'http://', but it is "https://..." (a string value)
        2) site.conf error: expected autoupdater.branches.test.mirrors.1 to use HTTPS only if the 'tls' feature is enabled, but it is "https://..." (a string value)
        3) site.conf error: expected autoupdater.branches.test.mirrors.1 to match pattern '^//', but it is "https://..." (a string value)

In addition, introduce support for protocol-less //server/path URLs,
which will use either HTTP or HTTPS depending on the availablility of
the `tls` feature. No fallback happens when `tls` is available, but the
HTTPS connection fails, preventing downgrade attack.

Based-on-patch-by: default avatarKevin Olbrich <ko@sv01.de>
parent 877ae95a
No related branches found
No related tags found
No related merge requests found
...@@ -39,7 +39,15 @@ ...@@ -39,7 +39,15 @@
branches = { branches = {
stable = { stable = {
name = 'stable', name = 'stable',
mirrors = {'http://update.example.org/stable/sysupgrade'}, mirrors = {
'http://1.updates.example.org/stable/sysupgrade',
-- Requires the tls feature in image-customization.lua
-- 'https://2.updates.example.org/stable/sysupgrade',
-- Uses http or https depending on the tls feature in image-customization.lua
'//3.updates.example.org/stable/sysupgrade',
},
good_signatures = 2, good_signatures = 2,
pubkeys = { pubkeys = {
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', -- Alice 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', -- Alice
......
...@@ -174,7 +174,15 @@ ...@@ -174,7 +174,15 @@
name = 'stable', name = 'stable',
-- List of mirrors to fetch images from. IPv6 required! -- List of mirrors to fetch images from. IPv6 required!
mirrors = {'http://1.updates.services.ffhl/stable/sysupgrade'}, mirrors = {
'http://1.updates.example.org/stable/sysupgrade',
-- Requires the tls feature in image-customization.lua
-- 'https://2.updates.example.org/stable/sysupgrade',
-- Uses http or https depending on the tls feature in image-customization.lua
'//3.updates.example.org/stable/sysupgrade',
},
-- Number of good signatures required. -- Number of good signatures required.
-- Have multiple maintainers sign your build and only -- Have multiple maintainers sign your build and only
......
...@@ -467,7 +467,10 @@ autoupdater \: package ...@@ -467,7 +467,10 @@ autoupdater \: package
name = 'stable', name = 'stable',
mirrors = { mirrors = {
'http://[fdca:ffee:babe:1::fec1]/firmware/stable/sysupgrade/', 'http://[fdca:ffee:babe:1::fec1]/firmware/stable/sysupgrade/',
'http://autoupdate.alpha-centauri.freifunk.net/firmware/stable/sysupgrade/', -- Requires the tls feature in image-customization.lua
'https://autoupdate.alpha-centauri.freifunk.net/firmware/stable/sysupgrade/',
-- Uses http or https depending on the tls feature in image-customization.lua
'//autoupdate2.alpha-centauri.freifunk.net/firmware/stable/sysupgrade/',
}, },
-- Number of good signatures required -- Number of good signatures required
good_signatures = 2, good_signatures = 2,
...@@ -482,6 +485,16 @@ autoupdater \: package ...@@ -482,6 +485,16 @@ autoupdater \: package
All configured mirrors must be reachable from the nodes via IPv6. If you don't want to set an IPv6 address All configured mirrors must be reachable from the nodes via IPv6. If you don't want to set an IPv6 address
explicitly, but use a hostname (which is recommended), see also the :ref:`FAQ <faq-dns>`. explicitly, but use a hostname (which is recommended), see also the :ref:`FAQ <faq-dns>`.
HTTPS URLs can be used if the **tls** feature is enabled in **image-customization.lua**.
Use protocol-less ``//server/path`` URLs to use HTTPS if the **tls** feature is available,
but fall back to HTTP otherwise. The server **must** allow HTTPS connections and provide
a valid certificate in this case; the autoupdater will not fall back to HTTP if the **tls**
feature is enabled, but the HTTPS connection fails.
Note that the validity period of TLS certificates is checked as well, so care must be taken
to provide working NTP servers in addition to the update mirrors when using HTTPS.
.. _user-site-config_mode: .. _user-site-config_mode:
config_mode \: optional config_mode \: optional
......
local has_tls = (function()
local f = io.open((os.getenv('IPKG_INSTROOT') or '') .. '/lib/gluon/features/tls')
if f then
f:close()
return true
end
return false
end)()
local branches = table_keys(need_table({'autoupdater', 'branches'}, function(branch) local branches = table_keys(need_table({'autoupdater', 'branches'}, function(branch)
need_alphanumeric_key(branch) need_alphanumeric_key(branch)
need_string(in_site(extend(branch, {'name'}))) need_string(in_site(extend(branch, {'name'})))
need_string_array_match(extend(branch, {'mirrors'}), '^http://') need_array(extend(branch, {'mirrors'}), function(mirror)
alternatives(function()
need_string_match(mirror, 'http://')
end, function()
need_string_match(mirror, 'https://')
need(mirror, function() return has_tls end, nil,
"use HTTPS only if the 'tls' feature is enabled")
end, function()
need_string_match(mirror, '^//')
end)
end)
local pubkeys = need_string_array_match(in_site(extend(branch, {'pubkeys'})), '^%x+$') local pubkeys = need_string_array_match(in_site(extend(branch, {'pubkeys'})), '^%x+$')
need_number(in_site(extend(branch, {'good_signatures'}))) need_number(in_site(extend(branch, {'good_signatures'})))
......
...@@ -4,14 +4,30 @@ local site = require 'gluon.site' ...@@ -4,14 +4,30 @@ local site = require 'gluon.site'
local uci = require('simple-uci').cursor() local uci = require('simple-uci').cursor()
local unistd = require 'posix.unistd' local unistd = require 'posix.unistd'
local has_tls = unistd.access('/lib/gluon/features/tls') ~= nil
local default_scheme = has_tls and 'https:' or 'http:'
local min_branch local min_branch
local function mirror_urls(mirrors)
local ret = {}
for _, mirror in ipairs(mirrors) do
if string.match(mirror, '^//') ~= nil then
table.insert(ret, default_scheme .. mirror)
else
table.insert(ret, mirror)
end
end
return ret
end
for name, config in pairs(site.autoupdater.branches()) do for name, config in pairs(site.autoupdater.branches()) do
uci:delete('autoupdater', name) uci:delete('autoupdater', name)
uci:section('autoupdater', 'branch', name, { uci:section('autoupdater', 'branch', name, {
name = config.name, name = config.name,
mirror = config.mirrors, mirror = mirror_urls(config.mirrors),
good_signatures = config.good_signatures, good_signatures = config.good_signatures,
pubkey = config.pubkeys, pubkey = config.pubkeys,
}) })
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment