Commit c1967ccd authored by Vincent Pelletier's avatar Vincent Pelletier

ca: Copy latest CA's subject and extensions on renewal.

Also, inline createCAKeyPair method in its only caller. This was not
intended to be part of the API.
Prepares support for externally-provided CA certificates.
parent 8984006f
......@@ -188,94 +188,6 @@ class CertificateAuthority(object):
})
self._ca_key_pairs_list = ca_key_pair_list
def createCAKeyPair(self):
"""
Create a new CA key pair.
CA certificate renewal normally happens automatically as long as
certificates are getting signed and revocation list downloaded.
"""
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=self._ca_key_size,
backend=_cryptography_backend,
)
public_key = private_key.public_key()
subject_key_identifier = x509.SubjectKeyIdentifier.from_public_key(
public_key,
)
now = datetime.datetime.utcnow()
certificate = x509.CertificateBuilder(
subject_name=self._ca_subject,
issuer_name=self._ca_subject,
not_valid_before=now,
not_valid_after=now + self._ca_life_time,
serial_number=x509.random_serial_number(),
public_key=public_key,
extensions=[
Extension(
x509.BasicConstraints(
ca=True,
path_length=0,
),
critical=True, # "MUST mark the extension as critical"
),
Extension(
x509.KeyUsage(
# pylint: disable=bad-whitespace
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,
# pylint: enable=bad-whitespace
),
critical=True, # "SHOULD mark this extension critical"
),
# Should we make use of certificate policies ? If we do, we need to enable
# this extension and fill the values.
# Extension(
# x509.PolicyConstraints(
# require_explicit_policy=,
# inhibit_policy_mapping=,
# ),
# critical=True, # MUST mark this extension as critical
# ),
Extension(
subject_key_identifier,
critical=False, # "MUST mark this extension as non-critical"
),
Extension(
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
# Dummy extension, from_issuer_subject_key_identifier accesses .data directly
Extension(
subject_key_identifier,
critical=False,
),
),
critical=False, # "MUST mark this extension as non-critical"
),
],
).sign(
private_key=private_key,
algorithm=self._default_digest_class(),
backend=_cryptography_backend,
)
self._storage.appendCAKeyPair(
utils.datetime2timestamp(certificate.not_valid_after),
{
'key_pem': utils.dump_privatekey(private_key),
'crt_pem': utils.dump_certificate(certificate),
},
)
self._loadCAKeyPairList()
assert self._ca_key_pairs_list
def getCertificateSigningRequest(self, csr_id):
"""
Retrieve a PEM-encoded certificate signing request.
......@@ -532,7 +444,107 @@ class CertificateAuthority(object):
# No CA certificate at all or less than 2 certificate validity periods
# left with latest CA certificate. Prepare the next one so it starts
# getting distributed.
self.createCAKeyPair()
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=self._ca_key_size,
backend=_cryptography_backend,
)
if self._ca_key_pairs_list:
latest_crt = self._ca_key_pairs_list[-1]['crt']
subject = latest_crt.subject
extension_list = latest_crt.extensions
else:
# Provide a default subject extension set.
subject = self._ca_subject
extension_list = [
Extension(
x509.BasicConstraints(
ca=True,
path_length=0,
),
critical=True, # "MUST mark the extension as critical"
),
Extension(
x509.KeyUsage(
# pylint: disable=bad-whitespace
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,
# pylint: enable=bad-whitespace
),
critical=True, # "SHOULD mark this extension critical"
),
# Should we make use of certificate policies ? If we do, we need to enable
# this extension and fill the values.
# Extension(
# x509.PolicyConstraints(
# require_explicit_policy=,
# inhibit_policy_mapping=,
# ),
# critical=True, # MUST mark this extension as critical
# ),
]
public_key = private_key.public_key()
subject_key_identifier = x509.SubjectKeyIdentifier.from_public_key(
public_key,
)
now = datetime.datetime.utcnow()
crt_builder = x509.CertificateBuilder(
subject_name=subject,
issuer_name=subject,
not_valid_before=now,
not_valid_after=now + self._ca_life_time,
serial_number=x509.random_serial_number(),
public_key=public_key,
extensions=[
Extension(
subject_key_identifier,
critical=False, # "MUST mark this extension as non-critical"
),
Extension(
x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
# Dummy extension, from_issuer_subject_key_identifier accesses .data directly
Extension(
subject_key_identifier,
critical=False,
),
),
critical=False, # "MUST mark this extension as non-critical"
),
],
)
# Copy all extensions, except the ones which depend on the key (and which
# we just set).
skipped_extension_oid_set = (
x509.SubjectKeyIdentifier.oid,
x509.AuthorityKeyIdentifier.oid,
)
for extension in extension_list:
if extension.oid not in skipped_extension_oid_set:
crt_builder = crt_builder.add_extension(
extension.value,
extension.critical,
)
certificate = crt_builder.sign(
private_key=private_key,
algorithm=self._default_digest_class(),
backend=_cryptography_backend,
)
self._storage.appendCAKeyPair(
utils.datetime2timestamp(certificate.not_valid_after),
{
'key_pem': utils.dump_privatekey(private_key),
'crt_pem': utils.dump_certificate(certificate),
},
)
self._loadCAKeyPairList()
assert self._ca_key_pairs_list
finally:
self._ca_renewal_lock.release()
......
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