Commit 7ff81404 by Vincent Pelletier Committed by Vincent Pelletier

http: Constrain the certificates caucased https CA may sign.

This makes it safer to trust this CA certificate in general-purpose https
clients, like web browsers, as it prevents such trusted CA certificate
from issuing rogue certificates.
Bump pyOpenSSL to latest version (and, as a consequence of pyOpenSSL
18.0.0 itself requiring cryptography 2.1.1, bump it as well) as it seems to
fix a bug related to validating NameConstraints - and anyway fixes
worrying use-after-free errors.
1 parent 95f2f9fa
......@@ -34,6 +34,7 @@ import tempfile
from threading import Thread
from urlparse import urlparse, urlunsplit
from wsgiref.simple_server import make_server, WSGIServer
import ipaddress
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
......@@ -201,7 +202,8 @@ def getSSLContext(
key_len,
threshold,
server_key_path,
hostname,
hostname_ip_address,
hostname_dnsname,
cau,
http_cas,
renew=False, # Force renewal when True - used in tests
......@@ -282,7 +284,7 @@ def getSSLContext(
subject_name=x509.Name([
x509.NameAttribute(
oid=x509.oid.NameOID.COMMON_NAME,
value=hostname.decode('ascii'),
value=hostname_dnsname,
),
]),
extensions=[
......@@ -304,7 +306,9 @@ def getSSLContext(
),
Extension(
x509.SubjectAlternativeName([
x509.DNSName(hostname.decode('ascii')),
x509.DNSName(hostname_dnsname)
if hostname_ip_address is None
else x509.IPAddress(hostname_ip_address),
]),
critical=True,
),
......@@ -485,6 +489,29 @@ def main(argv=None, until=utils.until):
base_url = u'http://' + args.netloc.decode('ascii')
parsed_base_url = urlparse(base_url)
hostname = parsed_base_url.hostname
name_constraints_permited = []
name_constraints_excluded = []
hostname_dnsname = hostname.decode('ascii')
try:
hostname_ip_address = ipaddress.ip_address(hostname_dnsname)
except ValueError:
# Hostname is not an ip address, it must be a hostname
name_constraints_permited.append(
x509.DNSName(hostname_dnsname),
)
hostname_ip_address = None
else:
# Hostname is an ip address, forbid hostname claims.
name_constraints_excluded.append(
x509.DNSName(u''),
)
# Convert to a network to meet NameConstraint restrictions.
# Resulting network has maximal prefix length, so it really just covers
# one IP.
name_constraints_permited.append(
x509.IPAddress(ipaddress.ip_network(hostname_ip_address)),
)
http_port = (
parsed_base_url.port
if args.base_port is None
......@@ -555,6 +582,15 @@ def main(argv=None, until=utils.until):
ca_subject_dict={
'CN': u'Caucased CA at ' + https_base_url,
},
ca_extension_list=[
Extension(
x509.NameConstraints(
permitted_subtrees=name_constraints_permited,
excluded_subtrees=name_constraints_excluded or None,
),
critical=True,
),
],
ca_key_size=args.key_len,
# This CA certificate will be installed in browser key stores, where
# automated renewal will be unlikely to happen. As this CA certificate
......@@ -614,7 +650,8 @@ def main(argv=None, until=utils.until):
key_len=args.key_len,
threshold=args.threshold,
server_key_path=args.server_key,
hostname=hostname,
hostname_ip_address=hostname_ip_address,
hostname_dnsname=hostname_dnsname,
cau=cau,
http_cas=http_cas,
)
......@@ -657,7 +694,8 @@ def main(argv=None, until=utils.until):
key_len=args.key_len,
threshold=args.threshold,
server_key_path=args.server_key,
hostname=hostname,
hostname_ip_address=hostname_ip_address,
hostname_dnsname=hostname_dnsname,
cau=cau,
http_cas=http_cas,
renew=True,
......
......@@ -49,8 +49,8 @@ setup(
license='GPLv3+',
packages=find_packages(),
install_requires=[
'cryptography>=2.1.1', # everything x509 except...
'pyOpenSSL>=17.1.0', # ...certificate chain validation
'cryptography>=2.2.1', # everything x509 except...
'pyOpenSSL>=18.0.0', # ...certificate chain validation
'pem>=17.1.0', # Parse PEM files
],
zip_safe=True,
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!