Commit 0fe8148a authored by Julien Muchembled's avatar Julien Muchembled

Require private key to have a matching certificate

parent 319b8b18
...@@ -9,7 +9,23 @@ class Error(Exception): pass ...@@ -9,7 +9,23 @@ class Error(Exception): pass
FILETYPE_PEM = 1 FILETYPE_PEM = 1
class X509(object):
pass
def dump_publickey(type, pkey):
assert type == FILETYPE_PEM, type
pkey.seek(0, 0)
r = pkey.read()
if not r.startswith('-----BEGIN PUBLIC KEY-----'):
Please register or sign in to reply
p = Popen(("openssl", "rsa", "-in", pkey.name, "-pubout"),
stdout=PIPE, stderr=PIPE)
r, err = p.communicate()
if p.poll():
raise Error(err)
return r
def load_privatekey(type, buffer): def load_privatekey(type, buffer):
assert type == FILETYPE_PEM, type
r = _tmpfile() r = _tmpfile()
r.write(buffer.encode()) r.write(buffer.encode())
r.flush() r.flush()
...@@ -17,13 +33,16 @@ def load_privatekey(type, buffer): ...@@ -17,13 +33,16 @@ def load_privatekey(type, buffer):
def load_certificate(type, buffer): def load_certificate(type, buffer):
# extract public key since we only use it to verify signatures # extract public key since we only use it to verify signatures
assert type == FILETYPE_PEM, type
r = _tmpfile() r = _tmpfile()
p = Popen(("openssl", "x509", "-pubkey", "-noout"), p = Popen(("openssl", "x509", "-pubkey", "-noout"),
stdin=PIPE, stdout=r, stderr=PIPE) stdin=PIPE, stdout=r, stderr=PIPE)
err = p.communicate(buffer.encode())[1] err = p.communicate(buffer.encode())[1]
if p.poll(): if p.poll():
raise Error(err) raise Error(err)
return r cert = X509()
cert.get_pubkey = lambda: r
return cert
def sign(pkey, data, digest): def sign(pkey, data, digest):
p = Popen(("openssl", digest, "-sign", pkey.name), p = Popen(("openssl", digest, "-sign", pkey.name),
...@@ -37,8 +56,8 @@ def verify(cert, signature, data, digest): ...@@ -37,8 +56,8 @@ def verify(cert, signature, data, digest):
with _tmpfile() as f: with _tmpfile() as f:
f.write(signature) f.write(signature)
f.flush() f.flush()
p = Popen(("openssl", digest, "-verify", cert.name, "-signature", f.name), p = Popen(("openssl", digest, "-verify", cert.get_pubkey().name,
stdin=PIPE, stdout=PIPE, stderr=STDOUT) "-signature", f.name), stdin=PIPE, stdout=PIPE, stderr=STDOUT)
err = p.communicate(data)[0] err = p.communicate(data)[0]
if p.poll(): if p.poll():
raise Error(err) raise Error(err)
...@@ -199,10 +199,14 @@ class NetworkcacheClient(object): ...@@ -199,10 +199,14 @@ class NetworkcacheClient(object):
config = dict(parser.items('networkcache')) config = dict(parser.items('networkcache'))
self.config = config self.config = config
path = config.get('signature-private-key-file') path = config.get('signature-private-key-file')
pubkey = None
if path: if path:
with open(path) as f: with open(path) as f:
self.signature_private_key = crypto.load_privatekey(crypto.FILETYPE_PEM, self.signature_private_key = crypto.load_privatekey(crypto.FILETYPE_PEM,
f.read()) f.read())
if config.get('download-dir-url'):
pubkey = crypto.dump_publickey(crypto.FILETYPE_PEM,
self.signature_private_key)
if signature_certificate_list is None: if signature_certificate_list is None:
signature_certificate_list = config.get('signature-certificate-list') signature_certificate_list = config.get('signature-certificate-list')
if type(signature_certificate_list) is str: if type(signature_certificate_list) is str:
...@@ -216,9 +220,18 @@ class NetworkcacheClient(object): ...@@ -216,9 +220,18 @@ class NetworkcacheClient(object):
for certificate in signature_certificate_list or (): for certificate in signature_certificate_list or ():
try: try:
loaded_certificate = crypto.load_certificate(crypto.FILETYPE_PEM, certificate) loaded_certificate = crypto.load_certificate(crypto.FILETYPE_PEM, certificate)
self.signature_certificate_list.append(loaded_certificate)
except Exception as e: except Exception as e:
logger.info('Ignored wrong certificate, reason:\n%s, offending certificate:\n%s', e, certificate) logger.info('Ignored wrong certificate, reason:\n%s, offending certificate:\n%s', e, certificate)
else:
if pubkey and pubkey == crypto.dump_publickey(
crypto.FILETYPE_PEM, loaded_certificate.get_pubkey()):
pubkey = None
self.signature_certificate_list.append(loaded_certificate)
if pubkey:
raise NetworkcacheException(
'Invalid configuration: no matching certificate for private key'
' (continuing would cause duplicate uploads because it would never'
' manage to download these uploads)')
# NetworkcacheClient context manager catches all exceptions and logs them # NetworkcacheClient context manager catches all exceptions and logs them
# with INFO severity. This provides a easy way to use a networkcache safely # with INFO severity. This provides a easy way to use a networkcache safely
......
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