summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsarthurdev <965089+sarthurdev@users.noreply.github.com>2021-07-05 14:12:35 +0200
committersarthurdev <965089+sarthurdev@users.noreply.github.com>2021-07-05 16:23:31 +0200
commit20c4d06c717cd34e099cef942f86776b9b838e58 (patch)
tree063f876a84eda2bedb374ce21f6c12b732c6d13d
parent562ead14a6dd1eb9190b9a9f38981423937bfc94 (diff)
downloadvyos-1x-20c4d06c717cd34e099cef942f86776b9b838e58.tar.gz
vyos-1x-20c4d06c717cd34e099cef942f86776b9b838e58.zip
pki: T3642: Support for adding SANs on certificate requests
-rw-r--r--python/vyos/pki.py22
-rwxr-xr-xsrc/op_mode/pki.py32
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 = []