def test(self): leaf_path = os.path.join(os.path.dirname(__file__), '..', 'utils', 'github.com.pem') with open(leaf_path, 'rb') as leaf_file: leaf_pem = leaf_file.read() certificate = load_pem_x509_certificate(leaf_pem, default_backend()) self.assertIsNone( CertificateUtils.matches_hostname(certificate, 'www.github.com')) with self.assertRaises(ssl.CertificateError): self.assertFalse( CertificateUtils.matches_hostname(certificate, 'notgithub.com')) self.assertEqual( CertificateUtils.get_common_names(certificate.subject), ['github.com']) self.assertEqual( CertificateUtils.get_dns_subject_alternative_names(certificate), ['github.com', 'www.github.com']) self.assertEqual( CertificateUtils.get_printable_name(certificate.issuer), 'DigiCert SHA2 Extended Validation Server CA')
def _certificate_chain_to_xml(certificate_chain: List[Certificate]) -> List[Element]: cert_xml_list = [] for certificate in certificate_chain: cert_xml = Element('certificate', attrib={ 'sha1Fingerprint': binascii.hexlify(certificate.fingerprint(hashes.SHA1())).decode('ascii'), 'hpkpSha256Pin': CertificateUtils.get_hpkp_pin(certificate) }) # Add the PEM cert cert_as_pem_xml = Element('asPEM') cert_as_pem_xml.text = certificate.public_bytes(Encoding.PEM).decode('ascii') cert_xml.append(cert_as_pem_xml) # Add some of the fields of the cert elem_xml = Element('subject') elem_xml.text = CertificateUtils.get_name_as_text(certificate.subject) cert_xml.append(elem_xml) elem_xml = Element('issuer') elem_xml.text = CertificateUtils.get_name_as_text(certificate.issuer) cert_xml.append(elem_xml) elem_xml = Element('serialNumber') elem_xml.text = str(certificate.serial_number) cert_xml.append(elem_xml) elem_xml = Element('notBefore') elem_xml.text = certificate.not_valid_before.strftime("%Y-%m-%d %H:%M:%S") cert_xml.append(elem_xml) elem_xml = Element('notAfter') elem_xml.text = certificate.not_valid_after.strftime("%Y-%m-%d %H:%M:%S") cert_xml.append(elem_xml) elem_xml = Element('signatureAlgorithm') elem_xml.text = certificate.signature_hash_algorithm.name cert_xml.append(elem_xml) key_attrs = {'algorithm': CertificateUtils.get_public_key_type(certificate)} public_key = certificate.public_key() key_attrs['size'] = str(public_key.key_size) if isinstance(public_key, EllipticCurvePublicKey): key_attrs['curve'] = public_key.curve.name else: key_attrs['exponent'] = str(public_key.public_numbers().e) elem_xml = Element('publicKey', attrib=key_attrs) cert_xml.append(elem_xml) dns_alt_names = CertificateUtils.get_dns_subject_alternative_names(certificate) if dns_alt_names: san_xml = Element('subjectAlternativeName') for dns_name in dns_alt_names: dns_xml = Element('DNS') dns_xml.text = dns_name san_xml.append(dns_xml) cert_xml.append(san_xml) cert_xml_list.append(cert_xml) return cert_xml_list
def _get_basic_certificate_text(self) -> List[str]: certificate = self.certificate_chain[0] public_key = self.certificate_chain[0].public_key() text_output = [ self._format_field('SHA1 Fingerprint:', binascii.hexlify(certificate.fingerprint(hashes.SHA1())).decode('ascii')), self._format_field('Common Name:', CertificateUtils.get_name_as_short_text(certificate.subject)), self._format_field('Issuer:', CertificateUtils.get_name_as_short_text(certificate.issuer)), self._format_field('Serial Number:', certificate.serial_number), self._format_field('Not Before:', certificate.not_valid_before), self._format_field('Not After:', certificate.not_valid_after), self._format_field('Signature Algorithm:', certificate.signature_hash_algorithm.name), self._format_field('Public Key Algorithm:', CertificateUtils.get_public_key_type(certificate))] if isinstance(public_key, EllipticCurvePublicKey): text_output.append(self._format_field('Key Size:', public_key.curve.key_size)) text_output.append(self._format_field('Curve:', public_key.curve.name)) elif isinstance(public_key, RSAPublicKey): text_output.append(self._format_field('Key Size:', public_key.key_size)) text_output.append(self._format_field('Exponent:', '{0} (0x{0:x})'.format(public_key.public_numbers().e))) else: # DSA Key? https://github.com/nabla-c0d3/sslyze/issues/314 pass try: # Print the SAN extension if there's one text_output.append(self._format_field('DNS Subject Alternative Names:', str(CertificateUtils.get_dns_subject_alternative_names(certificate)))) except KeyError: pass return text_output
def _get_basic_certificate_text(self) -> List[str]: certificate = self.certificate_chain[0] public_key = self.certificate_chain[0].public_key() text_output = [ self._format_field('SHA1 Fingerprint:', binascii.hexlify(certificate.fingerprint(hashes.SHA1())).decode('ascii')), self._format_field('Common Name:', CertificateUtils.get_name_as_short_text(certificate.subject)), self._format_field('Issuer:', CertificateUtils.get_name_as_short_text(certificate.issuer)), self._format_field('Serial Number:', certificate.serial_number), self._format_field('Not Before:', certificate.not_valid_before), self._format_field('Not After:', certificate.not_valid_after), self._format_field('Signature Algorithm:', certificate.signature_hash_algorithm.name), self._format_field('Public Key Algorithm:', CertificateUtils.get_public_key_type(certificate))] if isinstance(public_key, EllipticCurvePublicKey): text_output.append(self._format_field('Key Size:', public_key.curve.key_size)) text_output.append(self._format_field('Curve:', public_key.curve.name)) elif isinstance(public_key, RSAPublicKey): text_output.append(self._format_field('Key Size:', public_key.key_size)) text_output.append(self._format_field('Exponent:', '{0} (0x{0:x})'.format(public_key.public_numbers().e))) else: # DSA Key? https://github.com/nabla-c0d3/sslyze/issues/314 pass try: # Print the SAN extension if there's one text_output.append(self._format_field('DNS Subject Alternative Names:', str(CertificateUtils.get_dns_subject_alternative_names(certificate)))) except KeyError: pass return text_output
def _object_to_json_dict(obj): """Convert an object to a dictionary suitable for the JSON output. """ if isinstance(obj, Enum): # Properly serialize Enums (such as OpenSslVersionEnum) result = obj.name elif isinstance(obj, x509._Certificate): # Properly serialize certificates certificate = obj result = { # Add general info 'as_pem': obj.public_bytes(Encoding.PEM).decode('ascii'), 'hpkp_pin': CertificateUtils.get_hpkp_pin(obj), # Add some of the fields of the cert 'subject': CertificateUtils.get_name_as_text(certificate.subject), 'issuer': CertificateUtils.get_name_as_text(certificate.issuer), 'serialNumber': str(certificate.serial_number), 'notBefore': certificate.not_valid_before.strftime("%Y-%m-%d %H:%M:%S"), 'notAfter': certificate.not_valid_after.strftime("%Y-%m-%d %H:%M:%S"), 'signatureAlgorithm': certificate.signature_hash_algorithm.name, 'publicKey': { 'algorithm': CertificateUtils.get_public_key_type(certificate) }, } dns_alt_names = CertificateUtils.get_dns_subject_alternative_names( certificate) if dns_alt_names: result['subjectAlternativeName'] = {'DNS': dns_alt_names} # Add some info about the public key public_key = certificate.public_key() if isinstance(public_key, EllipticCurvePublicKey): result['publicKey']['size'] = str(public_key.curve.key_size) result['publicKey']['curve'] = public_key.curve.name else: result['publicKey']['size'] = str(public_key.key_size) result['publicKey']['exponent'] = str( public_key.public_numbers().e) elif isinstance(obj, object): if hasattr(obj, '__dict__'): result = {} for key, value in obj.__dict__.items(): # Remove private attributes if key.startswith('_'): continue result[key] = _object_to_json_dict(value) else: # Simple object like a string result = obj else: raise TypeError('Unknown type: {}'.format(repr(obj))) return result
def _certificate_chain_to_xml(certificate_chain: List[Certificate]) -> List[Element]: cert_xml_list = [] for certificate in certificate_chain: cert_xml = Element('certificate', attrib={ 'sha1Fingerprint': binascii.hexlify(certificate.fingerprint(hashes.SHA1())).decode('ascii'), 'hpkpSha256Pin': CertificateUtils.get_hpkp_pin(certificate) }) # Add the PEM cert cert_as_pem_xml = Element('asPEM') cert_as_pem_xml.text = certificate.public_bytes(Encoding.PEM).decode('ascii') cert_xml.append(cert_as_pem_xml) # Add some of the fields of the cert elem_xml = Element('subject') elem_xml.text = CertificateUtils.get_name_as_text(certificate.subject) cert_xml.append(elem_xml) elem_xml = Element('issuer') elem_xml.text = CertificateUtils.get_name_as_text(certificate.issuer) cert_xml.append(elem_xml) elem_xml = Element('serialNumber') elem_xml.text = str(certificate.serial_number) cert_xml.append(elem_xml) elem_xml = Element('notBefore') elem_xml.text = certificate.not_valid_before.strftime("%Y-%m-%d %H:%M:%S") cert_xml.append(elem_xml) elem_xml = Element('notAfter') elem_xml.text = certificate.not_valid_after.strftime("%Y-%m-%d %H:%M:%S") cert_xml.append(elem_xml) elem_xml = Element('signatureAlgorithm') elem_xml.text = certificate.signature_hash_algorithm.name cert_xml.append(elem_xml) key_attrs = {'algorithm': CertificateUtils.get_public_key_type(certificate)} public_key = certificate.public_key() key_attrs['size'] = str(public_key.key_size) if isinstance(public_key, EllipticCurvePublicKey): key_attrs['curve'] = public_key.curve.name else: key_attrs['exponent'] = str(public_key.public_numbers().e) elem_xml = Element('publicKey', attrib=key_attrs) cert_xml.append(elem_xml) dns_alt_names = CertificateUtils.get_dns_subject_alternative_names(certificate) if dns_alt_names: san_xml = Element('subjectAlternativeName') for dns_name in dns_alt_names: dns_xml = Element('DNS') dns_xml.text = dns_name san_xml.append(dns_xml) cert_xml.append(san_xml) cert_xml_list.append(cert_xml) return cert_xml_list
def _object_to_json_dict(obj: Any) -> Union[bool, int, float, str, Dict[str, Any]]: """Convert an object to a dictionary suitable for the JSON output. """ if isinstance(obj, Enum): # Properly serialize Enums (such as OpenSslVersionEnum) result = obj.name elif isinstance(obj, x509._Certificate): # Properly serialize certificates certificate = obj result = { # type: ignore # Add general info 'as_pem': obj.public_bytes(Encoding.PEM).decode('ascii'), 'hpkp_pin': CertificateUtils.get_hpkp_pin(obj), # Add some of the fields of the cert 'subject': CertificateUtils.get_name_as_text(certificate.subject), 'issuer': CertificateUtils.get_name_as_text(certificate.issuer), 'serialNumber': str(certificate.serial_number), 'notBefore': certificate.not_valid_before.strftime("%Y-%m-%d %H:%M:%S"), 'notAfter': certificate.not_valid_after.strftime("%Y-%m-%d %H:%M:%S"), 'signatureAlgorithm': certificate.signature_hash_algorithm.name, 'publicKey': { 'algorithm': CertificateUtils.get_public_key_type(certificate) }, } dns_alt_names = CertificateUtils.get_dns_subject_alternative_names(certificate) if dns_alt_names: result['subjectAlternativeName'] = {'DNS': dns_alt_names} # type: ignore # Add some info about the public key public_key = certificate.public_key() if isinstance(public_key, EllipticCurvePublicKey): result['publicKey']['size'] = str(public_key.curve.key_size) # type: ignore result['publicKey']['curve'] = public_key.curve.name # type: ignore else: result['publicKey']['size'] = str(public_key.key_size) result['publicKey']['exponent'] = str(public_key.public_numbers().e) elif isinstance(obj, object): # Some objects (like str) don't have a __dict__ if hasattr(obj, '__dict__'): result = {} for key, value in obj.__dict__.items(): # Remove private attributes if key.startswith('_'): continue result[key] = _object_to_json_dict(value) else: # Simple object like a bool result = obj else: raise TypeError('Unknown type: {}'.format(repr(obj))) return result
def test(self): leaf_path = Path(__file__).absolute().parent / '..' / 'utils' / 'github.com.pem' leaf_pem = leaf_path.read_bytes() certificate = load_pem_x509_certificate(leaf_pem, default_backend()) assert CertificateUtils.matches_hostname(certificate, 'www.github.com') is None with pytest.raises(ssl.CertificateError): assert not CertificateUtils.matches_hostname(certificate, 'notgithub.com') assert CertificateUtils.get_common_names(certificate.subject) == ['github.com'] assert CertificateUtils.get_dns_subject_alternative_names(certificate) == [ 'github.com', 'www.github.com' ] expected_name = 'DigiCert SHA2 Extended Validation Server CA' assert CertificateUtils.get_name_as_short_text(certificate.issuer) == expected_name
def test(self): leaf_path = os.path.join(os.path.dirname(__file__), '..', 'utils', 'github.com.pem') with open(leaf_path, 'rb') as leaf_file: leaf_pem = leaf_file.read() certificate = load_pem_x509_certificate(leaf_pem, default_backend()) self.assertIsNone(CertificateUtils.matches_hostname(certificate, 'www.github.com')) with self.assertRaises(ssl.CertificateError): self.assertFalse(CertificateUtils.matches_hostname(certificate, 'notgithub.com')) self.assertEqual(CertificateUtils.get_common_names(certificate.subject), ['github.com']) self.assertEqual(CertificateUtils.get_dns_subject_alternative_names(certificate), ['github.com', 'www.github.com']) self.assertEqual(CertificateUtils.get_name_as_short_text(certificate.issuer), 'DigiCert SHA2 Extended Validation Server CA')
def _get_basic_certificate_text(self): certificate = self.certificate_chain[0] public_key = self.certificate_chain[0].public_key() text_output = [ self._format_field( 'SHA1 Fingerprint:', binascii.hexlify(certificate.fingerprint( hashes.SHA1())).decode('ascii')), self._format_field( 'Common Name:', CertificateUtils.get_printable_name(certificate.subject)), self._format_field( 'Issuer:', CertificateUtils.get_printable_name(certificate.issuer)), self._format_field('Serial Number:', certificate.serial_number), self._format_field('Not Before:', certificate.not_valid_before), self._format_field('Not After:', certificate.not_valid_after), self._format_field('Signature Algorithm:', certificate.signature_hash_algorithm.name), self._format_field('Public Key Algorithm:', public_key.__class__.__name__), self._format_field('Key Size:', public_key.key_size) ] try: # Print the Public key exponent if there's one; EC public keys don't have one for example text_output.append( self._format_field( 'Exponent:', '{0} (0x{0:x})'.format(public_key.public_numbers().e))) except KeyError: pass try: # Print the SAN extension if there's one text_output.append( self._format_field( 'DNS Subject Alternative Names:', str( CertificateUtils.get_dns_subject_alternative_names( certificate)))) except KeyError: pass return text_output
def test(self): leaf_path = Path( __file__).absolute().parent / '..' / 'utils' / 'github.com.pem' leaf_pem = leaf_path.read_bytes() certificate = load_pem_x509_certificate(leaf_pem, default_backend()) assert CertificateUtils.matches_hostname(certificate, 'www.github.com') is None with pytest.raises(ssl.CertificateError): assert not CertificateUtils.matches_hostname( certificate, 'notgithub.com') assert CertificateUtils.get_common_names( certificate.subject) == ['github.com'] assert CertificateUtils.get_dns_subject_alternative_names( certificate) == ['github.com', 'www.github.com'] expected_name = 'DigiCert SHA2 Extended Validation Server CA' assert CertificateUtils.get_name_as_short_text( certificate.issuer) == expected_name
def default(self, obj: Any) -> Union[bool, int, float, str, Dict[str, Any]]: result: Union[bool, int, float, str, Dict[str, Any]] if isinstance(obj, Enum): result = obj.name elif isinstance(obj, ObjectIdentifier): result = obj.dotted_string elif isinstance(obj, x509._Certificate): certificate = obj result = { # Add general info "as_pem": obj.public_bytes(Encoding.PEM).decode("ascii"), "hpkp_pin": CertificateUtils.get_hpkp_pin(obj), # Add some of the fields of the cert "subject": CertificateUtils.get_name_as_text(certificate.subject), "issuer": CertificateUtils.get_name_as_text(certificate.issuer), "serialNumber": str(certificate.serial_number), "notBefore": certificate.not_valid_before.strftime("%Y-%m-%d %H:%M:%S"), "notAfter": certificate.not_valid_after.strftime("%Y-%m-%d %H:%M:%S"), "signatureAlgorithm": certificate.signature_hash_algorithm.name, "publicKey": { "algorithm": CertificateUtils.get_public_key_type(certificate) }, } dns_alt_names = CertificateUtils.get_dns_subject_alternative_names( certificate) if dns_alt_names: result["subjectAlternativeName"] = { "DNS": dns_alt_names } # type: ignore # Add some info about the public key public_key = certificate.public_key() if isinstance(public_key, EllipticCurvePublicKey): result["publicKey"]["size"] = str( public_key.curve.key_size) # type: ignore result["publicKey"][ "curve"] = public_key.curve.name # type: ignore else: result["publicKey"]["size"] = str(public_key.key_size) result["publicKey"]["exponent"] = str( public_key.public_numbers().e) elif isinstance(obj, Path): result = str(obj) elif isinstance(obj, object): # Some objects (like str) don't have a __dict__ if hasattr(obj, "__dict__"): result = {} for key, value in obj.__dict__.items(): # Remove private attributes if key.startswith("_"): continue result[key] = self.default(value) else: # Simple object like a bool result = obj # type: ignore else: raise TypeError("Unknown type: {}".format(repr(obj))) return result