Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

topogen: remove CA generator #3515

Merged
merged 4 commits into from
Dec 13, 2019
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
topogen: Use cryptograpgy instead of openssl for CA
We can get rid of the openSSL dependency also PyCA strongly recommend against using pyOpenSSL.
lukedirtwalker committed Dec 13, 2019
commit e0fd4a206034e3d333407e12960d91d288b185c6
2 changes: 0 additions & 2 deletions env/pip3/requirements.txt
Original file line number Diff line number Diff line change
@@ -12,8 +12,6 @@ toml==0.9.4 --hash=sha256:8e86bd6ce8cc11b9620cb637466453d94f5d57ad86f17e98a98d1f
plumbum==1.6.7 --hash=sha256:df96a5facf621db4a6d682bdc93afa5ed6b107a8667c73c3f0a0f0fab4217c81 # Direct dependency
# pyyaml
pyyaml==5.1.1 --hash=sha256:b4bb4d3f5e232425e25dda21c070ce05168a786ac9eda43768ab7f3ac2770955
#pyOpenSSL
pyOpenSSL==19.1.0 --hash=sha256:621880965a720b8ece2f1b2f54ea2071966ab00e2970ad2ce11d596102063504
# supervisor: licenses/supervisor
supervisor==4.1.0 --hash=sha256:2dc86fe0476e945e61483d614ceb2cf4f93b95282eb243bdf792621994360383 --hash=sha256:a76b2f77a560f2dc411c0254a4eb15f555e99faac48621b0f1fc9ab013944f47 # Direct dependency
# supervisor-wildcards: licenses/BSD-3-Clause
80 changes: 53 additions & 27 deletions python/topology/ca.py
Original file line number Diff line number Diff line change
@@ -18,9 +18,14 @@
"""
# Stdlib
from collections import defaultdict
import datetime

# External packages
from OpenSSL import crypto
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID

# SCION
from lib.crypto.util import (
@@ -58,55 +63,76 @@ def _iterate(self, f):
f(ca_name, ca_config)

def _gen_ca_key(self, ca_name, ca_config):
self.ca_key_pairs[ca_name] = crypto.PKey()
self.ca_key_pairs[ca_name].generate_key(crypto.TYPE_RSA, 2048)
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
public_key = private_key.public_key()
self.ca_key_pairs[ca_name] = (private_key, public_key)

def _gen_ca(self, ca_name, ca_config):
ca = crypto.X509()
ca.set_version(3)
ca.set_serial_number(1)
ca.get_subject().CN = ca_config["commonName"]
ca.gmtime_adj_notBefore(0)
ca.gmtime_adj_notAfter(5 * 365 * 24 * 60 * 60)
ca.set_issuer(ca.get_subject())
ca.set_pubkey(self.ca_key_pairs[ca_name])

one_day = datetime.timedelta(1, 0, 0)
five_years = 5 * 365 * one_day

builder = x509.CertificateBuilder()
builder = builder.subject_name(x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, ca_config["commonName"]),
]))
builder = builder.issuer_name(x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, ca_config["commonName"]),
]))
builder = builder.not_valid_before(datetime.datetime.today() - one_day)
builder = builder.not_valid_after(datetime.datetime.today() + five_years)
builder = builder.serial_number(x509.random_serial_number())
builder = builder.public_key(self.ca_key_pairs[ca_name][1])
# From RFC5280: Conforming CAs MUST include keyUsage extension in
# certificates that contain public keys that are used to validate
# digital signatures on other public key certificates or CRLs.
# To facilitate certification path construction, subjectKeyIdentifier
# extension MUST appear in all conforming CA certificates, that is, all
# certificates including the basic constraints extension where the
# value of cA is TRUE.
ca.add_extensions([
builder = builder.add_extension(
# basicConstraints identifies whether subject of certificate is a CA
# pathLen expresses the number of possible intermediate CA
# certificates in a path built from an end-entity certificate up
# to the CA certificate.
crypto.X509Extension(
b"basicConstraints", True, b"CA:TRUE, pathlen:1"),
x509.BasicConstraints(ca=True, path_length=1), critical=True,
)
builder = builder.add_extension(
# The keyCertSign bit is asserted when the subject public key is
# used for verifying signatures on public key certificates.
crypto.X509Extension(b"keyUsage", True, b"keyCertSign, cRLSign"),
x509.KeyUsage(digital_signature=False, content_commitment=False, key_encipherment=False,
data_encipherment=False, key_agreement= False, key_cert_sign=True,
crl_sign=True, encipher_only=False, decipher_only=False), critical=True,
)
builder = builder.add_extension(
# From RFC5280: The keyIdentifier is composed of the 160-bit SHA-1
# hash of the value of the BIT STRING subjectPublicKey
crypto.X509Extension(b"subjectKeyIdentifier", False, b"hash",
subject=ca),
])
ca.sign(self.ca_key_pairs[ca_name], "sha256")
self.ca_certs[ca_config["ISD"]][ca_name] = ca
x509.SubjectKeyIdentifier.from_public_key(self.ca_key_pairs[ca_name][1]),
critical=False,
)
certificate = builder.sign(
private_key=self.ca_key_pairs[ca_name][0], algorithm=hashes.SHA256(),
backend=default_backend()
)
self.ca_certs[ca_config["ISD"]][ca_name] = certificate

def _gen_private_key_files(self, ca_name, ca_config):
isd = ca_config["ISD"]
ca_private_key_path = \
get_ca_private_key_file_path("ISD%s" % isd, ca_name)
ca_private_key_path = get_ca_private_key_file_path("ISD%s" % isd, ca_name)
self.ca_private_key_files[isd][ca_private_key_path] = \
crypto.dump_privatekey(crypto.FILETYPE_PEM,
self.ca_key_pairs[ca_name])
self.ca_key_pairs[ca_name][0].private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)

def _gen_cert_files(self, ca_name, ca_config):
isd = ca_config["ISD"]
ca_cert_path = get_ca_cert_file_path("ISD%s" % isd, ca_name)
self.ca_cert_files[isd][ca_cert_path] = \
crypto.dump_certificate(crypto.FILETYPE_PEM,
self.ca_certs[ca_config["ISD"]][ca_name])
self.ca_certs[ca_config["ISD"]][ca_name].public_bytes(
serialization.Encoding.PEM
)