Commit 0bced59a authored by Killian Lufau's avatar Killian Lufau

Implement HMAC for babel

HMAC is added to babel to make sure nodes from a given re6st network
don't talk to nodes from another re6st network. This is useful when
machines from separate re6st networks are on a LAN.
The key is the same for all nodes with the same registry: a random
part created by their registry and passed through network parameters,
combined with the prefix and prefix length of this re6st network.

This uses the currently WIP hmac branch of babel:
https://github.com/jech/babeld/tree/hmac
parent d4b53a40
......@@ -97,6 +97,8 @@ class Cache(object):
k = str(k)
if k in base64:
v = v.decode('base64')
if k is 'babel_hmac_rand' or k is 'babel_hmac_rand_accept':
k = self._decrypt(k)
elif type(v) is unicode:
v = str(v)
elif isinstance(v, (list, dict)):
......
......@@ -386,6 +386,12 @@ def main():
subprocess.check_call(x)
ip('route', 'unreachable', my_network)
def hmacFromKey(key):
# We combine a key generated by the registry
# and our network prefix to get a hmac key for babel
return '%064x' % int(bin(len(network))[2:].zfill(7) + network +
bin(int(key.encode('hex'),16))[9+len(network):],2)
config.babel_args += config.iface_list
cleanup.append(plib.router((my_ip, len(subnet)), ipv4,
None if config.gateway else
......@@ -395,6 +401,8 @@ def main():
os.path.join(config.state, 'babeld.state'),
os.path.join(config.run, 'babeld.pid'),
control_socket, cache.babel_default,
hmacFromKey(cache.babel_hmac_rand)if hasattr(cache, 'babel_hmac_rand') else None,
hmacFromKey(cache.babel_hmac_rand_accept)if hasattr(cache, 'babel_hmac_rand_accept') else None,
*config.babel_args).stop)
if config.up:
exit.release()
......
......@@ -61,8 +61,8 @@ def client(iface, address_list, encrypt, *args, **kw):
return openvpn(iface, encrypt, *remote, **kw)
def router(ip, ip4, src, hello_interval, log_path, state_path,
pidfile, control_socket, default, *args, **kw):
def router(ip, ip4, src, hello_interval, log_path, state_path, pidfile,
control_socket, default, hmac_key, accept_hmac, *args, **kw):
ip, n = ip
if ip4:
ip4, n4 = ip4
......@@ -79,9 +79,19 @@ def router(ip, ip4, src, hello_interval, log_path, state_path,
# is not equivalent, at least not the way we use babeld
# (and we don't need RTA_SRC for ipv4).
'-C', 'ipv6-subtrees true',
'-C', 'default ' + default,
'-C', 'redistribute local deny',
'-C', 'redistribute ip %s/%s eq %s' % (ip, n, n)]
if hmac_key:
key_id = 'hmac_key'
cmd += '-C', 'key type sha256 id %s value %s' % (key_id, hmac_key)
cmd += '-C', 'default %s hmac %s' % (default, key_id)
else:
cmd += '-C', 'default ' + default
if accept_hmac is '':
cmd += '-C', 'accept_unsigned'
elif accept_hmac:
accept_id = 'accept_hmac'
cmd += '-C', 'key type sha256 id %s value %s' % (accept_id, accept_hmac)
if ip4:
cmd += '-C', 'redistribute ip %s/%s eq %s' % (ip4, n4, n4)
if src:
......
......@@ -84,7 +84,7 @@ class RegistryServer(object):
utils.sqliteCreateTable(self.db, "crl",
"serial INTEGER PRIMARY KEY NOT NULL",
# Expiration date of revoked certificate.
# TODO: purge rows with dates in the past.
# TODO: purge rows with dates in the past, add hmac random.
"date INTEGER NOT NULL")
self.cert = x509.Cert(self.config.ca, self.config.key)
......@@ -120,6 +120,16 @@ class RegistryServer(object):
'protocol': version.protocol,
'registry_prefix': self.prefix,
}
# The following entry lists values that are base64-encoded.
kw[''] = 'version',
babel_hmac_rand = self.getConfig("babel_hmac_rand", None)
if babel_hmac_rand:
kw['babel_hmac_rand'] = str(babel_hmac_rand).encode('base64')
kw[''] += 'babel_hmac_rand',
babel_hmac_rand_accept = self.getConfig('babel_hmac_rand_accept', None)
if babel_hmac_rand_accept:
kw['babel_hmac_rand_accept'] = str(babel_hmac_rand_accept).encode('base64')
kw[''] += 'babel_hmac_rand_accept',
if self.config.ipv4:
kw['ipv4'], kw['ipv4_sublen'] = self.config.ipv4
if self.config.same_country:
......@@ -136,9 +146,8 @@ class RegistryServer(object):
self.setConfig('version', buffer(self.version))
self.setConfig('last_config', config)
self.sendto(self.prefix, 0)
# The following entry lists values that are base64-encoded.
kw[''] = 'version',
kw['version'] = self.version.encode('base64')
#encryption : self.network_config = kw
self.network_config = zlib.compress(json.dumps(kw), 9)
# The 3 first bits code the number of bytes.
......@@ -483,6 +492,11 @@ class RegistryServer(object):
@rpc
def getNetworkConfig(self, cn):
# encryption : for k in 'babel_hmac_rand', 'babel_hmac_rand_accept':
# if k in self.network_config.keys():
# v = self.network_config[k]
# self.network_config[k] = x509.encrypt(cert, v).encode('base64')
#return zlib.compress(json.dumps(self.network_config), 9)
return self.network_config
def _queryAddress(self, peer):
......@@ -550,6 +564,13 @@ class RegistryServer(object):
q("INSERT INTO crl VALUES (?,?)", (serial, not_after))
self.updateNetworkConfig()
@rpc_private
def newHMAC(self):
with self.lock:
with self.db:
self.setConfig('babel_hmac_rand', buffer(os.urandom(32)))
self.updateNetworkConfig()
@rpc_private
def getNodePrefix(self, email):
with self.lock:
......
......@@ -191,8 +191,9 @@ class BaseTunnelManager(object):
# TODO: To minimize downtime when network parameters change, we should do
# our best to not restart any process. Ideally, this list should be
# empty and the affected subprocesses reloaded.
NEED_RESTART = frozenset(('babel_default', 'encrypt', 'hello',
'ipv4', 'ipv4_sublen'))
NEED_RESTART = frozenset(('babel_default', 'babel_hmac_rand',
'babel_hmac_rand_accept', 'encrypt',
'hello', 'ipv4', 'ipv4_sublen'))
_geoiplookup = None
_forward = None
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment