def create_selfsigned_ca_cert(self, subject_dn, validity_days, signing_hash, serial, custom_x509_extensions=None): x509_extensions = self.expand_extensions( extension_template="rootca", custom_x509_extensions=custom_x509_extensions) OpenSSLTools.create_selfsigned_certificate( self.private_key_storage, self.root_crt_filename, subject_dn, validity_days, signing_hash=signing_hash, serial=serial, x509_extensions=x509_extensions)
def test_gen_privkey_rsa(self): input_output_data = [ ( { "bitlen": 512 }, b"512 bit", ), ( { "bitlen": 600 }, b"600 bit", ), ] for (input_data, output_data) in input_output_data: with tempfile.NamedTemporaryFile(prefix = "privkey_", suffix = ".pem") as f: OpenSSLTools.create_private_key(PrivateKeyStorage(storage_form = PrivateKeyStorageForm.PEM_FILE, filename = f.name), keyspec = KeySpecification(cryptosystem = Cryptosystems.RSA, parameters = input_data)) content = self._read_file(f.name) self.assertIn(b"BEGIN RSA PRIVATE KEY", content) self.assertIn(b"END RSA PRIVATE KEY", content) output = SubprocessExecutor([ "openssl", "rsa", "-text" ], stdin = content).run().stdout self.assertIn(output_data, output)
def sign_csr(self, csr_filename, crt_filename, subject_dn, validity_days, extension_template=None, custom_x509_extensions=None, subject_alternative_dns_names=None, subject_alternative_ip_addresses=None, signing_hash=None): extensions = self.expand_extensions(extension_template, custom_x509_extensions) OpenSSLTools.ca_sign_csr( self, csr_filename, crt_filename, subject_dn, validity_days, x509_extensions=extensions, subject_alternative_dns_names=subject_alternative_dns_names, subject_alternative_ip_addresses=subject_alternative_ip_addresses, signing_hash=signing_hash)
def test_gen_privkey_ecc(self): input_output_data = [ ( { "curvename": "secp384r1" }, (b"384 bit", b"secp384r1"), ), ( { "curvename": "secp256r1" }, (b"256 bit", b"prime256v1"), ), ] for (input_data, output_data) in input_output_data: with tempfile.NamedTemporaryFile(prefix = "privkey_", suffix = ".pem") as f: OpenSSLTools.create_private_key(PrivateKeyStorage(storage_form = PrivateKeyStorageForm.PEM_FILE, filename = f.name), keyspec = KeySpecification(cryptosystem = Cryptosystems.ECC_ECDSA, parameters = input_data)) content = self._read_file(f.name) self.assertNotIn(b"BEGIN EC PARAMETERS", content) self.assertNotIn(b"END EC PARAMETERS", content) self.assertIn(b"BEGIN EC PRIVATE KEY", content) self.assertIn(b"END EC PRIVATE KEY", content) output = SubprocessExecutor([ "openssl", "ec", "-text" ], stdin = content).run().stdout self.assertIn(output_data[0], output) self.assertIn(output_data[1], output)
def create_csr(cls, private_key_storage, csr_filename, subject_dn, extension_template=None, custom_x509_extensions=None, subject_alternative_dns_names=None, subject_alternative_ip_addresses=None, signing_hash=None): extensions = cls.expand_extensions(extension_template, custom_x509_extensions) extensions = { key: value for (key, value) in extensions.items() if key not in cls._FILTER_EXTENSIONS_FOR_CSR } OpenSSLTools.create_csr( private_key_storage, csr_filename, subject_dn, x509_extensions=extensions, subject_alternative_dns_names=subject_alternative_dns_names, subject_alternative_ip_addresses=subject_alternative_ip_addresses, signing_hash=signing_hash)
def _forge_cert(self, cert_issuer_id, issuer, cert_subject_id, subject): self._log.debug("Forging chain element %d -> %d: %s -> %s", cert_issuer_id, cert_subject_id, issuer, subject) issuer_key_filename = self._args.key_template % (cert_issuer_id) key_filename = self._args.key_template % (cert_subject_id) crt_filename = self._args.cert_template % (cert_subject_id) if (not os.path.isfile(key_filename)) or self._args.force: OpenSSLTools.create_private_key(PrivateKeyStorage(storage_form = PrivateKeyStorageForm.PEM_FILE, filename = key_filename), subject.pubkey.keyspec) # Read new private key and convert to public key with tempfile.NamedTemporaryFile(prefix = "pubkey_", suffix = ".pem") as pubkey_file: OpenSSLTools.private_to_public(key_filename, pubkey_file.name) subject_pubkey = PublicKey.read_pemfile(pubkey_file.name)[0] # Do the same for the issuer key to get the issuer key ID with tempfile.NamedTemporaryFile(prefix = "pubkey_", suffix = ".pem") as pubkey_file: OpenSSLTools.private_to_public(issuer_key_filename, pubkey_file.name) issuer_pubkey = PublicKey.read_pemfile(pubkey_file.name)[0] # Replace public key first forged_cert_asn1 = subject.asn1_clone forged_cert_asn1["tbsCertificate"]["subjectPublicKeyInfo"] = subject_pubkey.asn1 # Do identifiers need to be recalculated? if self._args.recalculate_keyids: if subject.extensions.has(OIDDB.X509Extensions.inverse("SubjectKeyIdentifier")): # Replace subject key identifier new_key_id = subject_pubkey.keyid() replacement_extension = X509SubjectKeyIdentifierExtension.construct(new_key_id) subject.extensions.filter(OIDDB.X509Extensions.inverse("SubjectKeyIdentifier"), replacement_extension) if subject.extensions.has(OIDDB.X509Extensions.inverse("AuthorityKeyIdentifier")): # Replace authority key identifier new_key_id = issuer_pubkey.keyid() replacement_extension = X509AuthorityKeyIdentifierExtension.construct(new_key_id) subject.extensions.filter(OIDDB.X509Extensions.inverse("AuthorityKeyIdentifier"), replacement_extension) forged_cert_asn1["tbsCertificate"]["extensions"] = subject.extensions.to_asn1() # Re-serialize certificate forged_cert = X509Certificate.from_asn1(forged_cert_asn1) # Then sign the modified certifiate signature = OpenSSLTools.sign_data(subject.signature_algorithm, issuer_key_filename, forged_cert.signed_payload) # Finally, place the signature into the certificate forged_cert_asn1["signatureValue"] = ASN1Tools.bytes2bitstring(signature) forged_cert = X509Certificate.from_asn1(forged_cert_asn1) forged_cert.write_pemfile(crt_filename)
def __init__(self, cmdname, args): BaseAction.__init__(self, cmdname, args) if self._args.force: try: os.unlink(self._args.capath) except (IsADirectoryError, FileNotFoundError): pass try: shutil.rmtree(self._args.capath) except FileNotFoundError: pass else: if os.path.exists(self._args.capath): raise UnfulfilledPrerequisitesException( "File/directory %s already exists. Remove it first or use --force." % (self._args.capath)) os.makedirs(self._args.capath) os.chmod(self._args.capath, 0o700) camgr = CAManager(self._args.capath) custom_x509_extensions = { custom_x509_extension.key: custom_x509_extension.value for custom_x509_extension in self._args.extension } if (self._args.gen_keyspec is not None) or ((self._args.gen_keyspec is None) and (self._args.hardware_key is None)): # We need to generate a key. if self._args.gen_keyspec is not None: keyspec = self._args.gen_keyspec else: # Cannot default to this in argparse because it's part of a # mutually exclusive group with hardware_key keyspec = KeySpecification.from_cmdline_str("ecc:secp384r1") private_key_storage = PrivateKeyStorage( PrivateKeyStorageForm.PEM_FILE, filename="CA.key", search_path=camgr.capath) OpenSSLTools.create_private_key(private_key_storage, keyspec=keyspec) else: # The key is stored in hardware. private_key_storage = PrivateKeyStorage( PrivateKeyStorageForm.HARDWARE_TOKEN, pkcs11uri=self._args.hardware_key, so_search_path=self._args.pkcs11_so_search, module_so=self._args.pkcs11_module) signing_hash = self._args.hashfnc if private_key_storage.is_file_based: privkey = private_key_storage.load_private_key() if isinstance(privkey, EDPrivateKey): # We cannot specify a hash function for EdDSA because this # causes OpenSSL to fail with "elliptic curve # routines:pkey_ecd_ctrl:invalid digest type" -- for EdDSA, the # hash algorithms are implied signing_hash = None camgr.create_ca_structure( private_key_storage=private_key_storage, unique_subject=not self._args.allow_duplicate_subjects) if self._args.parent_ca is None: # Self-signed root CA camgr.create_selfsigned_ca_cert( subject_dn=self._args.subject_dn, validity_days=self._args.validity_days, custom_x509_extensions=custom_x509_extensions, signing_hash=signing_hash, serial=self._args.serial) # Create certificate chain file that only consists of our # self-signed certificate shutil.copy(self._args.capath + "/CA.crt", self._args.capath + "/chain.crt") else: # Intermediate CA if self._args.serial is not None: raise InvalidUsageException( "Can only specify certificate serial number when creating self-signed root CA certificate." ) with tempfile.NamedTemporaryFile("w", prefix="ca_", suffix=".csr") as csr: camgr.create_ca_csr(csr_filename=csr.name, subject_dn=self._args.subject_dn) parent_ca = CAManager(self._args.parent_ca) parent_ca.sign_csr( csr.name, camgr.root_crt_filename, subject_dn=self._args.subject_dn, validity_days=self._args.validity_days, custom_x509_extensions=custom_x509_extensions, extension_template="ca", signing_hash=signing_hash) # Create a certificate chain by appending the parent chain to our certificate if os.path.isfile(self._args.parent_ca + "/chain.crt"): with open(self._args.parent_ca + "/chain.crt") as parent_chainfile: parent_chain = parent_chainfile.read() with open(self._args.capath + "/CA.crt") as new_certificate_file: new_certificate = new_certificate_file.read() with open(self._args.capath + "/chain.crt", "w") as intermediate_chainfile: intermediate_chainfile.write(parent_chain) intermediate_chainfile.write(new_certificate)
def create_crl(self, *args, **kwargs): OpenSSLTools.ca_create_crl(self, *args, **kwargs)
def revoke_crt(self, *args, **kwargs): OpenSSLTools.ca_revoke_crt(self, *args, **kwargs)
def create_ca_csr(self, csr_filename, subject_dn): OpenSSLTools.create_csr(self.private_key_storage, csr_filename, subject_dn)
def test_gen_csr(self): with tempfile.NamedTemporaryFile(prefix = "privkey_", suffix = ".pem") as privkey_file, tempfile.NamedTemporaryFile(prefix = "csr_", suffix = ".pem") as csr_file: OpenSSLTools.create_private_key(PrivateKeyStorage(storage_form = PrivateKeyStorageForm.PEM_FILE, filename = privkey_file.name), keyspec = KeySpecification.from_cmdline_str("ecc:secp256r1")) private_key_storage = PrivateKeyStorage(storage_form = PrivateKeyStorageForm.PEM_FILE, filename = privkey_file.name) OpenSSLTools.create_csr(private_key_storage = private_key_storage, csr_filename = csr_file.name, subject_dn = "/CN=Foobar") output = SubprocessExecutor([ "openssl", "req", "-text" ], stdin = self._read_file(csr_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE REQUEST", output) self.assertIn(b"END CERTIFICATE REQUEST", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertNotIn(b"Requested Extensions:", output) OpenSSLTools.create_csr(private_key_storage = private_key_storage, csr_filename = csr_file.name, subject_dn = "/CN=Foobar", subject_alternative_dns_names = [ "muhkuh" ]) output = SubprocessExecutor([ "openssl", "req", "-text" ], stdin = self._read_file(csr_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE REQUEST", output) self.assertIn(b"END CERTIFICATE REQUEST", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertIn(b"Requested Extensions:", output) self.assertIn(b"X509v3 Subject Alternative Name:", output) self.assertIn(b"DNS:muhkuh", output) OpenSSLTools.create_csr(private_key_storage = private_key_storage, csr_filename = csr_file.name, subject_dn = "/CN=Foobar", subject_alternative_dns_names = [ "muhkuh", "kruckelmuckel" ]) output = SubprocessExecutor([ "openssl", "req", "-text" ], stdin = self._read_file(csr_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE REQUEST", output) self.assertIn(b"END CERTIFICATE REQUEST", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertIn(b"Requested Extensions:", output) self.assertIn(b"X509v3 Subject Alternative Name:", output) self.assertIn(b"DNS:muhkuh", output) self.assertIn(b"DNS:kruckelmuckel", output) OpenSSLTools.create_csr(private_key_storage = private_key_storage, csr_filename = csr_file.name, subject_dn = "/CN=Foobar", subject_alternative_dns_names = [ "muhkuh", "kruckelmuckel" ], subject_alternative_ip_addresses = [ "11.22.33.44", "99.88.77.66", "abcd::9876" ]) output = SubprocessExecutor([ "openssl", "req", "-text" ], stdin = self._read_file(csr_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE REQUEST", output) self.assertIn(b"END CERTIFICATE REQUEST", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertIn(b"Requested Extensions:", output) self.assertIn(b"X509v3 Subject Alternative Name:", output) self.assertIn(b"DNS:muhkuh", output) self.assertIn(b"DNS:kruckelmuckel", output) self.assertIn(b"IP Address:11.22.33.44", output) self.assertIn(b"IP Address:99.88.77.66", output) self.assertIn(b"IP Address:ABCD:0:0:0:0:0:0:9876", output) OpenSSLTools.create_csr(private_key_storage = private_key_storage, csr_filename = csr_file.name, subject_dn = "/CN=Foobar", subject_alternative_dns_names = [ "muhkuh", "kruckelmuckel" ], subject_alternative_ip_addresses = [ "11.22.33.44", "99.88.77.66", "abcd::9876" ], x509_extensions = { "2.3.4.5.6.7": "ASN1:UTF8String:Never gonna give you up" }) output = SubprocessExecutor([ "openssl", "req", "-text" ], stdin = self._read_file(csr_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE REQUEST", output) self.assertIn(b"END CERTIFICATE REQUEST", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertIn(b"Requested Extensions:", output) self.assertIn(b"X509v3 Subject Alternative Name:", output) self.assertIn(b"DNS:muhkuh", output) self.assertIn(b"DNS:kruckelmuckel", output) self.assertIn(b"IP Address:11.22.33.44", output) self.assertIn(b"IP Address:99.88.77.66", output) self.assertIn(b"IP Address:ABCD:0:0:0:0:0:0:9876", output) self.assertIn(b"Never gonna give you up", output)
def test_gen_selfsigned_cert(self): with tempfile.NamedTemporaryFile(prefix = "privkey_", suffix = ".pem") as privkey_file, tempfile.NamedTemporaryFile(prefix = "crt_", suffix = ".pem") as certificate_file: OpenSSLTools.create_private_key(PrivateKeyStorage(storage_form = PrivateKeyStorageForm.PEM_FILE, filename = privkey_file.name), keyspec = KeySpecification(cryptosystem = Cryptosystems.ECC_ECDSA, parameters = { "curvename": "secp256r1" })) private_key_storage = PrivateKeyStorage(storage_form = PrivateKeyStorageForm.PEM_FILE, filename = privkey_file.name) OpenSSLTools.create_selfsigned_certificate(private_key_storage = private_key_storage, certificate_filename = certificate_file.name, subject_dn = "/CN=Foobar", validity_days = 365) output = SubprocessExecutor([ "openssl", "x509", "-text" ], stdin = self._read_file(certificate_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE--", output) self.assertIn(b"END CERTIFICATE--", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertNotIn(b"X509v3 extensions:", output) OpenSSLTools.create_selfsigned_certificate(private_key_storage = private_key_storage, certificate_filename = certificate_file.name, subject_dn = "/CN=Foobar", subject_alternative_dns_names = [ "muhkuh" ], validity_days = 365) output = SubprocessExecutor([ "openssl", "x509", "-text" ], stdin = self._read_file(certificate_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE--", output) self.assertIn(b"END CERTIFICATE--", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertIn(b"X509v3 extensions:", output) self.assertIn(b"X509v3 Subject Alternative Name:", output) self.assertIn(b"DNS:muhkuh", output) OpenSSLTools.create_selfsigned_certificate(private_key_storage = private_key_storage, certificate_filename = certificate_file.name, subject_dn = "/CN=Foobar", subject_alternative_dns_names = [ "muhkuh", "kruckelmuckel" ], validity_days = 365) output = SubprocessExecutor([ "openssl", "x509", "-text" ], stdin = self._read_file(certificate_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE--", output) self.assertIn(b"END CERTIFICATE--", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertIn(b"X509v3 extensions:", output) self.assertIn(b"X509v3 Subject Alternative Name:", output) self.assertIn(b"DNS:muhkuh", output) self.assertIn(b"DNS:kruckelmuckel", output) OpenSSLTools.create_selfsigned_certificate(private_key_storage = private_key_storage, certificate_filename = certificate_file.name, subject_dn = "/CN=Foobar", subject_alternative_dns_names = [ "muhkuh", "kruckelmuckel" ], subject_alternative_ip_addresses = [ "11.22.33.44", "99.88.77.66", "abcd::9876" ], validity_days = 365) output = SubprocessExecutor([ "openssl", "x509", "-text" ], stdin = self._read_file(certificate_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE--", output) self.assertIn(b"END CERTIFICATE--", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertIn(b"X509v3 extensions:", output) self.assertIn(b"X509v3 Subject Alternative Name:", output) self.assertIn(b"DNS:muhkuh", output) self.assertIn(b"DNS:kruckelmuckel", output) self.assertIn(b"IP Address:11.22.33.44", output) self.assertIn(b"IP Address:99.88.77.66", output) self.assertIn(b"IP Address:ABCD:0:0:0:0:0:0:9876", output) OpenSSLTools.create_selfsigned_certificate(private_key_storage = private_key_storage, certificate_filename = certificate_file.name, subject_dn = "/CN=Foobar", subject_alternative_dns_names = [ "muhkuh", "kruckelmuckel" ], subject_alternative_ip_addresses = [ "11.22.33.44", "99.88.77.66", "abcd::9876" ], x509_extensions = { "2.3.4.5.6.7": "ASN1:UTF8String:Never gonna give you up" }, validity_days = 365) output = SubprocessExecutor([ "openssl", "x509", "-text" ], stdin = self._read_file(certificate_file.name)).run().stdout self.assertIn(b"BEGIN CERTIFICATE--", output) self.assertIn(b"END CERTIFICATE--", output) self.assertTrue((b"Subject: CN = Foobar" in output) or (b"Subject: CN=Foobar" in output)) self.assertIn(b"X509v3 extensions:", output) self.assertIn(b"X509v3 Subject Alternative Name:", output) self.assertIn(b"DNS:muhkuh", output) self.assertIn(b"DNS:kruckelmuckel", output) self.assertIn(b"IP Address:11.22.33.44", output) self.assertIn(b"IP Address:99.88.77.66", output) self.assertIn(b"IP Address:ABCD:0:0:0:0:0:0:9876", output) self.assertIn(b"Never gonna give you up", output)
def __init__(self, cmdname, args): BaseAction.__init__(self, cmdname, args) if (self._args.private_key is not None) and (self._args.outform != "pkcs12"): raise InvalidUsageException( "A private key will only be exported with a PKCS#12 output file." ) if self._args.outform != "pkcs12": if self._args.pkcs12_legacy_crypto: raise InvalidUsageException( "Specifying PKCS#12 legacy crypto while not using PKCS#12 output format has no effect." ) if self._args.pkcs12_no_passphrase: raise InvalidUsageException( "Specifying no PKCS#12 passphrase while not using PKCS#12 output format has no effect." ) if self._args.pkcs12_passphrase_file is not None: raise InvalidUsageException( "Specifying a PKCS#12 passphrase while not using PKCS#12 output format has no effect." ) else: if (self._args.pkcs12_legacy_crypto or self._args.pkcs12_no_passphrase or self._args.pkcs12_passphrase_file is not None) and (self._args.private_key is None): raise InvalidUsageException( "Specifying any PKCS#12 passphrase/crypto options when not including a private key makes no sense." ) self._pool = CertificatePool() self._load_truststore() if self._args.inform == "pem": certs = X509Certificate.read_pemfile(self._args.crtfile) if not self._args.dont_trust_crtfile: self._pool.add_certificates(certs) cert = certs[0] elif self._args.inform == "der": cert = X509Certificate.read_derfile(self._args.crtfile) else: raise NotImplementedError("inform", self._args.inform) chain = self._pool.find_chain(cert) if (chain.root is None) and (not self._args.allow_partial_chain): raise InvalidUsageException( "Could not build full chain for certificate %s and partial chain matches are disallowed." % (self._args.crtfile)) if self._args.outform == "rootonly": if chain.root is None: print("Root certificate output requested, but none found.", file=sys.stderr) sys.exit(1) certs = [chain.root] elif self._args.outform == "intermediates": certs = list(chain.chain) elif self._args.outform in ["fullchain", "multifile", "pkcs12"]: certs = list(chain.full_chain) elif self._args.outform == "all-except-root": certs = list(chain.full_chain) if chain.root is not None: certs = certs[:-1] else: raise NotImplementedError("outform", self._args.outform) if not self._args.order_leaf_to_root: certs = certs[::-1] for (cid, cert) in enumerate(certs): self._log.debug("Cert %d: %s", cid, cert) if self._args.outform == "multifile": for (cid, cert) in enumerate(certs): filename = self._args.outfile % (cid) with open(filename, "w") as f: print(cert.to_pem_data(), file=f) elif self._args.outform == "pkcs12": if self._args.private_key is not None: if self._args.pkcs12_no_passphrase: passphrase = None else: if self._args.pkcs12_passphrase_file is not None: with open(self._args.pkcs12_passphrase_file) as f: passphrase = f.readline() else: passphrase = PassphraseGenerator.non_ambiguous( ).gen_passphrase(80) print("Passphrase: %s" % (passphrase), file=sys.stderr) else: passphrase = None private_key_storage = PrivateKeyStorage( PrivateKeyStorageForm.PEM_FILE, filename=self._args.private_key) if (self._args.private_key is not None) else None pkcs12 = OpenSSLTools.create_pkcs12( certificates=certs, private_key_storage=private_key_storage, modern_crypto=not self._args.pkcs12_legacy_crypto, passphrase=passphrase) if self._args.outfile is None: # Write to stdout sys.stdout.buffer.write(pkcs12) else: # Write to file, binary with open(self._args.outfile, "wb") as f: f.write(pkcs12) else: if self._args.outfile is not None: with open(self._args.outfile, "w") as f: self._print_certs(f, certs) else: self._print_certs(sys.stdout, certs)
def from_tls_server(cls, hostname, port = 443): pem_data = OpenSSLTools.get_tls_server_cert_pem(hostname = hostname, port = port) certificates = cls.from_pem_data(pem_data) return certificates[0]
def signed_by(self, potential_issuer, verbose_failure = False): return OpenSSLTools.validate_signature(subject_certificate = self, issuer_certificate = potential_issuer, verbose_failure = verbose_failure)