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 test_load_system_certs(self): dirname = "/etc/ssl/certs/" for filename in os.listdir(dirname): if filename.endswith(".pem"): fullfilename = dirname + filename cert = X509Certificate.read_pemfile(fullfilename)[0] _ = cert.issuer.rfc2253_str + cert.subject.rfc2253_str
def test_pem_load(self): x509_text = pkgutil.get_data( "x509sak.tests.data", "certs/ok/johannes-bauer.com.pem").decode("ascii") cert = X509Certificate.from_pem_data(x509_text) self.assertEqual(len(cert), 1) cert = cert[0] self.assertEqual(cert.to_pem_data() + "\n", x509_text)
def _load_certificates(self): sources = [ ] for crt_filename in self._args.infiles: if self._args.in_format == "pemcrt": self._log.debug("Reading PEM certificate from %s", crt_filename) crts = X509Certificate.read_pemfile(crt_filename) elif self._args.in_format == "dercrt": self._log.debug("Reading DER certificate from %s", crt_filename) crts = [ X509Certificate.read_derfile(crt_filename) ] elif self._args.in_format == "host": host_port = crt_filename.split(":", maxsplit = 1) if len(host_port) == 1: host_port.append("443") (host, port) = host_port port = int(port) self._log.debug("Querying TLS server at %s port %d", host, port) crts = [ X509Certificate.from_tls_server(host, port) ] else: raise NotImplementedError(self._args.in_format) source = CertificateAnalyzer.CertSource(source = crt_filename, crts = crts, source_type = self._args.in_format) sources.append(source) return sources
def __init__(self, cmdname, args): BaseAction.__init__(self, cmdname, args) if self._args.parent_certificate is None: parent_ca_cert = None else: if self._args.in_format == "dercrt": # CA cert in DER form if host certificate is also in DER form crt = X509Certificate.read_derfile(self._args.parent_certificate) else: # CA cert in PEM form for all other cases crt = X509Certificate.read_pemfile(self._args.parent_certificate)[0] parent_ca_cert = CertificateAnalyzer.CertSource(source = self._args.parent_certificate, source_type = "pemcrt" if (self._args.in_format != "dercrt") else "dercrt", crts = [ crt ]) if self._args.in_format in [ "pemcrt", "dercrt", "host" ]: crt_sources = self._load_certificates() analysis_params = { "include_raw_data": self._args.include_raw_data, "fast_rsa": self._args.fast_rsa, "purposes": self._args.purpose, "entity_name": self._args.server_name, } if (len(analysis_params["purposes"]) == 0) and (self._args.in_format == "host") and (not self._args.no_automatic_host_check): analysis_params["purposes"].append("tls-server") if (analysis_params["entity_name"] is None) and (self._args.in_format == "host") and (not self._args.no_automatic_host_check): hostname = crt_sources[0].source.split(":")[0] analysis_params["entity_name"] = hostname crt_analyzer = CertificateAnalyzer(**analysis_params) analysis = crt_analyzer.analyze(crt_sources, parent_ca_cert) elif self._args.in_format == "json": analysis = self._read_json() else: raise NotImplementedError(self._args.in_format) output = self._args.output or "-" with FileWriter(output, "w") as f: self._show_analysis(f, analysis)
def __init__(self, cmdname, args): BaseAction.__init__(self, cmdname, args) certs = X509Certificate.read_pemfile(self._args.crt_filename) if not certs[0].is_selfsigned: raise InvalidInputException("First certificate in chain (%s) is not self-signed." % (certs[0])) for (cert_id, (issuer, subject)) in enumerate(zip(certs, certs[1:]), 1): if not subject.signed_by(issuer): raise InvalidInputException("Certificate %d in file (%s) is not issuer for certificate %d (%s)." % (cert_id, issuer, cert_id + 1, subject)) self._log.debug("Chain of %d certificates to forge.", len(certs)) self._forge_cert(0, certs[0], 0, certs[0]) for (cert_subject_id, (issuer, subject)) in enumerate(zip(certs, certs[1:]), 1): self._forge_cert(cert_subject_id - 1, issuer, cert_subject_id, subject)
def _read_certificate(self, filename): if not self._args.der: return X509Certificate.read_pemfile(filename) else: return [ X509Certificate.read_derfile(filename) ]
def _load_crt(self, crtname): x509_text = self._load_text("certs/" + crtname + ".pem") cert = X509Certificate.from_pem_data(x509_text)[0] return cert
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)