diff options
author | sarthurdev <965089+sarthurdev@users.noreply.github.com> | 2021-07-05 14:12:35 +0200 |
---|---|---|
committer | sarthurdev <965089+sarthurdev@users.noreply.github.com> | 2021-07-05 16:23:31 +0200 |
commit | 20c4d06c717cd34e099cef942f86776b9b838e58 (patch) | |
tree | 063f876a84eda2bedb374ce21f6c12b732c6d13d | |
parent | 562ead14a6dd1eb9190b9a9f38981423937bfc94 (diff) | |
download | vyos-1x-20c4d06c717cd34e099cef942f86776b9b838e58.tar.gz vyos-1x-20c4d06c717cd34e099cef942f86776b9b838e58.zip |
pki: T3642: Support for adding SANs on certificate requests
-rw-r--r-- | python/vyos/pki.py | 22 | ||||
-rwxr-xr-x | src/op_mode/pki.py | 32 |
2 files changed, 45 insertions, 9 deletions
diff --git a/python/vyos/pki.py b/python/vyos/pki.py index a575ac16a..1c6282d84 100644 --- a/python/vyos/pki.py +++ b/python/vyos/pki.py @@ -15,6 +15,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import datetime +import ipaddress from cryptography import x509 from cryptography.exceptions import InvalidSignature @@ -112,7 +113,7 @@ def create_private_key(key_type, key_size=None): private_key = ec.generate_private_key(curve) return private_key -def create_certificate_request(subject, private_key): +def create_certificate_request(subject, private_key, subject_alt_names=[]): subject_obj = x509.Name([ x509.NameAttribute(NameOID.COUNTRY_NAME, subject['country']), x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, subject['state']), @@ -120,9 +121,20 @@ def create_certificate_request(subject, private_key): x509.NameAttribute(NameOID.ORGANIZATION_NAME, subject['organization']), x509.NameAttribute(NameOID.COMMON_NAME, subject['common_name'])]) - return x509.CertificateSigningRequestBuilder() \ - .subject_name(subject_obj) \ - .sign(private_key, hashes.SHA256()) + builder = x509.CertificateSigningRequestBuilder() \ + .subject_name(subject_obj) + + if subject_alt_names: + alt_names = [] + for obj in subject_alt_names: + if isinstance(obj, ipaddress.IPv4Address) or isinstance(obj, ipaddress.IPv6Address): + alt_names.append(x509.IPAddress(obj)) + elif isinstance(obj, str): + alt_names.append(x509.DNSName(obj)) + if alt_names: + builder = builder.add_extension(x509.SubjectAlternativeName(alt_names), critical=False) + + return builder.sign(private_key, hashes.SHA256()) def add_key_identifier(ca_cert): try: @@ -166,7 +178,7 @@ def create_certificate(cert_req, ca_cert, ca_private_key, valid_days=365, cert_t builder = builder.add_extension(add_key_identifier(ca_cert), critical=False) for ext in cert_req.extensions: - builder = builder.add_extension(ext, critical=False) + builder = builder.add_extension(ext.value, critical=False) return builder.sign(ca_private_key, hashes.SHA256()) diff --git a/src/op_mode/pki.py b/src/op_mode/pki.py index d7bb0d6ae..7dbeb4097 100755 --- a/src/op_mode/pki.py +++ b/src/op_mode/pki.py @@ -15,6 +15,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import argparse +import ipaddress import os import re import sys @@ -248,7 +249,24 @@ def generate_private_key(): return create_private_key(key_type, size), key_type -def generate_certificate_request(private_key=None, key_type=None, return_request=False, name=None, install=False): +def parse_san_string(san_string): + if not san_string: + return None + + output = [] + san_split = san_string.strip().split(",") + + for pair_str in san_split: + tag, value = pair_str.strip().split(":", 1) + if tag == 'ipv4': + output.append(ipaddress.IPv4Address(value)) + elif tag == 'ipv6': + output.append(ipaddress.IPv6Address(value)) + elif tag == 'dns': + output.append(value) + return output + +def generate_certificate_request(private_key=None, key_type=None, return_request=False, name=None, install=False, ask_san=True): if not private_key: private_key, key_type = generate_private_key() @@ -259,8 +277,14 @@ def generate_certificate_request(private_key=None, key_type=None, return_request subject['locality'] = ask_input('Enter locality:', default=default_values['locality']) subject['organization'] = ask_input('Enter organization name:', default=default_values['organization']) subject['common_name'] = ask_input('Enter common name:', default='vyos.io') + subject_alt_names = None - cert_req = create_certificate_request(subject, private_key) + if ask_san and ask_yes_no('Do you want to configure Subject Alternative Names?'): + print("Enter alternative names in a comma separate list, example: ipv4:1.1.1.1,ipv6:fe80::1,dns:vyos.net") + san_string = ask_input('Enter Subject Alternative Names:') + subject_alt_names = parse_san_string(san_string) + + cert_req = create_certificate_request(subject, private_key, subject_alt_names) if return_request: return cert_req @@ -285,7 +309,7 @@ def generate_certificate(cert_req, ca_cert, ca_private_key, is_ca=False, is_sub_ def generate_ca_certificate(name, install=False): private_key, key_type = generate_private_key() - cert_req = generate_certificate_request(private_key, key_type, return_request=True) + cert_req = generate_certificate_request(private_key, key_type, return_request=True, ask_san=False) cert = generate_certificate(cert_req, cert_req, private_key, is_ca=True) passphrase = ask_passphrase() @@ -325,7 +349,7 @@ def generate_ca_certificate_sign(name, ca_name, install=False): cert_req = None if not ask_yes_no('Do you already have a certificate request?'): private_key, key_type = generate_private_key() - cert_req = generate_certificate_request(private_key, key_type, return_request=True) + cert_req = generate_certificate_request(private_key, key_type, return_request=True, ask_san=False) else: print("Paste certificate request and press enter:") lines = [] |