Convert some certbot-ci utilities to use cryptography's APIs (#10102)

This commit is contained in:
Alex Gaynor
2024-12-19 19:37:09 +00:00
committed by GitHub
parent 25a1933e01
commit 314838eb81
@@ -22,10 +22,13 @@ from typing import Iterable
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Tuple from typing import Tuple
import warnings from typing import Union
from cryptography import x509
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import Encoding from cryptography.hazmat.primitives.serialization import Encoding
from cryptography.hazmat.primitives.serialization import NoEncryption from cryptography.hazmat.primitives.serialization import NoEncryption
from cryptography.hazmat.primitives.serialization import PrivateFormat from cryptography.hazmat.primitives.serialization import PrivateFormat
@@ -195,8 +198,9 @@ shutil.rmtree(well_known)
shutil.rmtree(tempdir) shutil.rmtree(tempdir)
def generate_csr(domains: Iterable[str], key_path: str, csr_path: str, def generate_csr(
key_type: str = RSA_KEY_TYPE) -> None: domains: Iterable[str], key_path: str, csr_path: str, key_type: str = RSA_KEY_TYPE
) -> None:
""" """
Generate a private key, and a CSR for the given domains using this key. Generate a private key, and a CSR for the given domains using this key.
:param domains: the domain names to include in the CSR :param domains: the domain names to include in the CSR
@@ -205,35 +209,33 @@ def generate_csr(domains: Iterable[str], key_path: str, csr_path: str,
:param str csr_path: path to the CSR that will be generated :param str csr_path: path to the CSR that will be generated
:param str key_type: type of the key (misc.RSA_KEY_TYPE or misc.ECDSA_KEY_TYPE) :param str key_type: type of the key (misc.RSA_KEY_TYPE or misc.ECDSA_KEY_TYPE)
""" """
key: Union[rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey]
if key_type == RSA_KEY_TYPE: if key_type == RSA_KEY_TYPE:
key = crypto.PKey() key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
key.generate_key(crypto.TYPE_RSA, 2048)
elif key_type == ECDSA_KEY_TYPE: elif key_type == ECDSA_KEY_TYPE:
with warnings.catch_warnings(): key = ec.generate_private_key(ec.SECP384R1())
# Ignore a warning on some old versions of cryptography
warnings.simplefilter('ignore', category=PendingDeprecationWarning)
_key = ec.generate_private_key(ec.SECP384R1(), default_backend())
_bytes = _key.private_bytes(encoding=Encoding.PEM,
format=PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=NoEncryption())
key = crypto.load_privatekey(crypto.FILETYPE_PEM, _bytes)
else: else:
raise ValueError('Invalid key type: {0}'.format(key_type)) raise ValueError("Invalid key type: {0}".format(key_type))
with open(key_path, 'wb') as file_h: with open(key_path, "wb") as file_h:
file_h.write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key)) file_h.write(
key.private_bytes(
Encoding.PEM, PrivateFormat.TraditionalOpenSSL, NoEncryption()
)
)
req = crypto.X509Req() csr = (
san = ', '.join('DNS:{0}'.format(item) for item in domains) x509.CertificateSigningRequestBuilder()
san_constraint = crypto.X509Extension(b'subjectAltName', False, san.encode('utf-8')) .subject_name(x509.Name([]))
req.add_extensions([san_constraint]) .add_extension(
x509.SubjectAlternativeName([x509.DNSName(d) for d in domains]),
critical=False,
)
.sign(key, hashes.SHA256())
)
req.set_pubkey(key) with open(csr_path, "wb") as file_h:
req.set_version(0) file_h.write(csr.public_bytes(Encoding.DER))
req.sign(key, 'sha256')
with open(csr_path, 'wb') as file_h:
file_h.write(crypto.dump_certificate_request(crypto.FILETYPE_ASN1, req))
def read_certificate(cert_path: str) -> str: def read_certificate(cert_path: str) -> str:
@@ -243,11 +245,13 @@ def read_certificate(cert_path: str) -> str:
:param str cert_path: the path to the certificate :param str cert_path: the path to the certificate
:returns: the TEXT version of the certificate, as it would be displayed by openssl binary :returns: the TEXT version of the certificate, as it would be displayed by openssl binary
""" """
with open(cert_path, 'rb') as file: with open(cert_path, "rb") as file:
data = file.read() data = file.read()
cert = crypto.load_certificate(crypto.FILETYPE_PEM, data) cert = x509.load_pem_x509_certificate(data)
return crypto.dump_certificate(crypto.FILETYPE_TEXT, cert).decode('utf-8') return crypto.dump_certificate(
crypto.FILETYPE_TEXT, crypto.X509.from_cryptography(cert)
).decode("utf-8")
def load_sample_data_path(workspace: str) -> str: def load_sample_data_path(workspace: str) -> str: