예제 #1
0
	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)
예제 #2
0
 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
예제 #3
0
 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)
예제 #4
0
	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
예제 #5
0
	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)
예제 #6
0
	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)
예제 #7
0
	def _read_certificate(self, filename):
		if not self._args.der:
			return X509Certificate.read_pemfile(filename)
		else:
			return [ X509Certificate.read_derfile(filename) ]
예제 #8
0
	def _load_crt(self, crtname):
		x509_text = self._load_text("certs/" + crtname + ".pem")
		cert = X509Certificate.from_pem_data(x509_text)[0]
		return cert
예제 #9
0
    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)