def test_issuer_and_root_issuer_populated_from_chain(self): self.assertEqual(3, len(CHAIN_DERS)) report = self.CertificateReportBase() report.scan_der_certs([(0, CHAIN_DERS[0], CHAIN_DERS[1:], client_pb2.X509_ENTRY)]) results = report.report() self.assertEqual(len(results), 1) issuer_cert = cert_desc.from_cert(cert.Certificate(CHAIN_DERS[1])) root_cert = cert_desc.from_cert(cert.Certificate(CHAIN_DERS[2])) self.assertEqual(readable_dn(results[0].issuer), 'C=US,O=Google Inc,CN=Google Internet Authority') self.assertEqual(readable_dn(results[0].root_issuer), 'C=US,O=Equifax,OU=Equifax Secure Certificate Authority')
def _scan_der_cert(der_certs): current = -1 result = [] for log_index, der_cert, der_chain, entry_type in der_certs: try: current = log_index certificate = None strict_failure = False try: certificate = cert.Certificate(der_cert) except error.Error as e: try: certificate = cert.Certificate(der_cert, strict_der=False) except error.Error as e: strict_failure = True if not strict_failure: desc = cert_desc.from_cert(certificate) else: desc = certificate_pb2.X509Description() desc.der = der_cert desc.sha256_hash = hashlib.sha256(der_cert).digest() desc.entry_type = entry_type root = None if der_chain: try: issuer = cert.Certificate(der_chain[0], strict_der=False) except error.Error: pass else: desc.issuer_pk_sha256_hash = issuer.key_hash(hashfunc="sha256") try: root = cert.Certificate(der_chain[-1], strict_der=False) except error.Error: pass else: # No chain implies this is a root certificate. # Note that certificate may be None. root = certificate if root: for iss in [(type_.short_name, cert_desc.to_unicode( '.'.join(cert_desc.process_name(value.human_readable())))) for type_, value in root.issuer()]: proto_iss = desc.root_issuer.add() proto_iss.type, proto_iss.value = iss result.append((desc, log_index)) except: batch_start_index, batch_end_index = ( der_certs[0][0], der_certs[-1][0]) logging.exception( "Error scanning certificate %d in batch <%d, %d> - it will " "be excluded from the scan results", current, batch_start_index, batch_end_index) return result
def test_issuer_and_root_issuer_populated_from_chain(self): self.assertEqual(3, len(CHAIN_DERS)) report = self.CertificateReportBase() report.scan_der_certs([(0, CHAIN_DERS[0], CHAIN_DERS[1:], client_pb2.X509_ENTRY)]) results = report.report() self.assertEqual(len(results), 1) issuer_cert = cert_desc.from_cert(cert.Certificate(CHAIN_DERS[1])) root_cert = cert_desc.from_cert(cert.Certificate(CHAIN_DERS[2])) self.assertEqual(readable_dn(results[0].issuer), 'C=US,O=Google Inc,CN=Google Internet Authority') self.assertEqual( readable_dn(results[0].root_issuer), 'C=US,O=Equifax,OU=Equifax Secure Certificate Authority')
def test_from_cert(self): observations = [] for check in all_checks.ALL_CHECKS: observations += check.check(CERT) or [] observations.append( observation.Observation("AE", u'ćę©ß→æ→ćąßę-ß©ąńśþa©ęńć←', (u'əꔹłęµ', u'…łą↓ð→↓ś→ę'))) proto = cert_desc.from_cert(CERT, observations) self.assertEqual(proto.der, CERT.to_der()) subject = [(att.type, att.value) for att in proto.subject] cert_subject = [(type_.short_name, cert_desc.to_unicode('.'.join( cert_desc.process_name(value.human_readable())))) for type_, value in CERT.subject()] self.assertItemsEqual(cert_subject, subject) issuer = [(att.type, att.value) for att in proto.issuer] cert_issuer = [(type_.short_name, cert_desc.to_unicode('.'.join( cert_desc.process_name(value.human_readable())))) for type_, value in CERT.issuer()] self.assertItemsEqual(cert_issuer, issuer) subject_alternative_names = [ (att.type, att.value) for att in proto.subject_alternative_names ] cert_subject_alternative_names = [ (san.component_key(), cert_desc.to_unicode('.'.join( cert_desc.process_name( san.component_value().human_readable())))) for san in CERT.subject_alternative_names() ] self.assertItemsEqual(cert_subject_alternative_names, subject_alternative_names) self.assertEqual(proto.version, str(CERT.version().value)) self.assertEqual( proto.serial_number, str(CERT.serial_number().human_readable().upper().replace(':', ''))) self.assertEqual(time.gmtime(proto.validity.not_before / 1000), CERT.not_before()) self.assertEqual(time.gmtime(proto.validity.not_after / 1000), CERT.not_after()) observations_tuples = [(unicode(obs.description), unicode(obs.reason) if obs.reason else u'', obs.details_to_proto()) for obs in observations] proto_obs = [(obs.description, obs.reason, obs.details) for obs in proto.observations] self.assertItemsEqual(proto_obs, observations_tuples)
def assert_description_matches_source(self, source, expect_ca_true): proto = cert_desc.from_cert(source) self.assertEqual(proto.der, source.to_der()) self.assert_description_subject_matches_source(proto, source) self.assert_description_issuer_matches_source(proto, source) self.assert_description_alt_subject_names_match_source(proto, source) self.assertEqual(proto.version, str(source.version().value)) self.assert_description_serial_number_matches_source(proto, source) self.assert_description_validity_dates_match_source(proto, source) self.assert_description_signature_matches_source(proto, source) self.assertEqual(proto.basic_constraint_ca, expect_ca_true)
def _scan_der_cert(der_certs, checks): current = -1 try: result = [] for log_index, der_cert, der_chain in der_certs: current = log_index partial_result = [] strict_failure = False try: certificate = cert.Certificate(der_cert) except error.Error as e: try: certificate = cert.Certificate(der_cert, strict_der=False) except error.Error as e: partial_result.append(asn1.All()) strict_failure = True else: if isinstance(e, error.ASN1IllegalCharacter): partial_result.append( asn1.Strict(reason=e.args[0], details=(e.string, e.index))) else: partial_result.append(asn1.Strict(reason=str(e))) if not strict_failure: for check in checks: partial_result += check.check(certificate) or [] desc = cert_desc.from_cert(certificate, partial_result) else: desc = certificate_pb2.X509Description() desc.der = der_cert desc.sha256_hash = hashlib.sha256(der_cert).digest() try: root = cert.Certificate(der_chain[-1], strict_der=False) except error.Error: pass else: for iss in [ (type_.short_name, cert_desc.to_unicode('.'.join( cert_desc.process_name(value.human_readable())))) for type_, value in root.issuer() ]: proto_iss = desc.root_issuer.add() proto_iss.type, proto_iss.value = iss result.append((desc, log_index, partial_result)) return result except Exception: _, exception, exception_traceback = sys.exc_info() exception_traceback = traceback.format_exc(exception_traceback) raise PoolException((exception, exception_traceback, der_certs[0][0], der_certs[-1][0], current))
def _scan_der_cert(der_certs, checks): current = -1 try: result = [] for log_index, der_cert, der_chain, entry_type in der_certs: current = log_index partial_result = [] strict_failure = False try: certificate = cert.Certificate(der_cert) except error.Error as e: try: certificate = cert.Certificate(der_cert, strict_der=False) except error.Error as e: partial_result.append(asn1.All()) strict_failure = True else: if isinstance(e, error.ASN1IllegalCharacter): partial_result.append(asn1.Strict(reason=e.args[0], details=(e.string, e.index))) else: partial_result.append(asn1.Strict(reason=str(e))) if not strict_failure: for check in checks: partial_result += check.check(certificate) or [] desc = cert_desc.from_cert(certificate, partial_result) else: desc = certificate_pb2.X509Description() desc.der = der_cert desc.sha256_hash = hashlib.sha256(der_cert).digest() desc.entry_type = entry_type try: root = cert.Certificate(der_chain[-1], strict_der=False) except error.Error: pass else: for iss in [(type_.short_name, cert_desc.to_unicode( '.'.join(cert_desc.process_name(value.human_readable())))) for type_, value in root.issuer()]: proto_iss = desc.root_issuer.add() proto_iss.type, proto_iss.value = iss result.append((desc, log_index, partial_result)) return result except Exception: _, exception, exception_traceback = sys.exc_info() exception_traceback = traceback.format_exc(exception_traceback) raise PoolException((exception, exception_traceback, der_certs[0][0], der_certs[-1][0], current))
def test_from_cert(self): observations = [] for check in all_checks.ALL_CHECKS: observations += check.check(CERT) or [] observations.append(observation.Observation( "AE", u'ćę©ß→æ→ćąßę-ß©ąńśþa©ęńć←', (u'əꔹłęµ', u'…łą↓ð→↓ś→ę'))) proto = cert_desc.from_cert(CERT, observations) self.assertEqual(proto.der, CERT.to_der()) subject = [(att.type, att.value) for att in proto.subject] cert_subject = [(type_.short_name, cert_desc.to_unicode('.'.join( cert_desc.process_name(value.human_readable())))) for type_, value in CERT.subject()] self.assertItemsEqual(cert_subject, subject) issuer = [(att.type, att.value) for att in proto.issuer] cert_issuer = [(type_.short_name, cert_desc.to_unicode('.'.join( cert_desc.process_name(value.human_readable())))) for type_, value in CERT.issuer()] self.assertItemsEqual(cert_issuer, issuer) subject_alternative_names = [(att.type, att.value) for att in proto.subject_alternative_names] cert_subject_alternative_names = [(san.component_key(), cert_desc.to_unicode('.'.join( cert_desc.process_name( san.component_value().human_readable())))) for san in CERT.subject_alternative_names()] self.assertItemsEqual(cert_subject_alternative_names, subject_alternative_names) self.assertEqual(proto.version, str(CERT.version().value)) self.assertEqual(proto.serial_number, str(CERT.serial_number().human_readable() .upper().replace(':', ''))) self.assertEqual(time.gmtime(proto.validity.not_before / 1000), CERT.not_before()) self.assertEqual(time.gmtime(proto.validity.not_after / 1000), CERT.not_after()) observations_tuples = [(unicode(obs.description), unicode(obs.reason) if obs.reason else u'', obs.details_to_proto()) for obs in observations] proto_obs = [(obs.description, obs.reason, obs.details) for obs in proto.observations] self.assertItemsEqual(proto_obs, observations_tuples)
def test_cert_with_mangled_utf8(self): cert = BAD_UTF8_CERT is_ca_cert = False with time_utils.timezone("UTC"): self.assert_description_matches_source(cert, is_ca_cert) # Test in non-UTC timezones, to detect timezone issues with time_utils.timezone("America/Los_Angeles"): self.assert_description_matches_source(cert, is_ca_cert) with time_utils.timezone("Asia/Shanghai"): self.assert_description_matches_source(cert, is_ca_cert) proto = cert_desc.from_cert(cert, self.get_observations(cert))
def test_cert_with_mangled_utf8(self): cert = BAD_UTF8_CERT is_ca_cert = False with time_utils.timezone("UTC"): self.assert_description_matches_source(cert, is_ca_cert) # Test in non-UTC timezones, to detect timezone issues with time_utils.timezone("America/Los_Angeles"): self.assert_description_matches_source(cert, is_ca_cert) with time_utils.timezone("Asia/Shanghai"): self.assert_description_matches_source(cert, is_ca_cert) proto = cert_desc.from_cert(cert)
def test_does_not_reverse_domain_names_in_o_component(self): ou = [t for t in cert_desc.from_cert(DOMAIN_IN_O_COMPONENT).subject if t.type == "O"][0] self.assertEqual("go-greenevents.com", ou.value)
def test_does_not_reverse_domain_names_in_ou(self): ou = [t for t in cert_desc.from_cert(DOMAIN_IN_ISSUER_CERT).issuer if t.type == "OU"][0] self.assertEqual("www.digicert.com", ou.value)
def test_from_cert(self): for test_case in [(CERT, False), (DSA_SHA256_CERT, False), (CA_CERT, True)]: (source, expect_ca_true) = test_case observations = [] for check in all_checks.ALL_CHECKS: observations += check.check(source) or [] observations.append(observation.Observation( "AE", u'ćę©ß→æ→ćąßę-ß©ąńśþa©ęńć←', (u'əꔹłęµ', u'…łą↓ð→↓ś→ę'))) proto = cert_desc.from_cert(source, observations) self.assertEqual(proto.der, source.to_der()) subject = [(att.type, att.value) for att in proto.subject] cert_subject = [(type_.short_name, cert_desc.to_unicode('.'.join( cert_desc.process_name(value.human_readable())))) for type_, value in source.subject()] self.assertItemsEqual(cert_subject, subject) issuer = [(att.type, att.value) for att in proto.issuer] cert_issuer = [(type_.short_name, cert_desc.to_unicode('.'.join( cert_desc.process_name(value.human_readable())))) for type_, value in source.issuer()] self.assertItemsEqual(cert_issuer, issuer) subject_alternative_names = [(att.type, att.value) for att in proto.subject_alternative_names] cert_subject_alternative_names = [(san.component_key(), cert_desc.to_unicode('.'.join( cert_desc.process_name( san.component_value().human_readable())))) for san in source.subject_alternative_names()] self.assertItemsEqual(cert_subject_alternative_names, subject_alternative_names) self.assertEqual(proto.version, str(source.version().value)) self.assertEqual(proto.serial_number, str(source.serial_number().human_readable() .upper().replace(':', ''))) self.assertEqual(time.gmtime(proto.validity.not_before / 1000), source.not_before()) self.assertEqual(time.gmtime(proto.validity.not_after / 1000), source.not_after()) observations_tuples = [(unicode(obs.description), unicode(obs.reason) if obs.reason else u'', obs.details_to_proto()) for obs in observations] proto_obs = [(obs.description, obs.reason, obs.details) for obs in proto.observations] self.assertItemsEqual(proto_obs, observations_tuples) self.assertEqual(proto.tbs_signature.algorithm_id, source.signature()["algorithm"].long_name) self.assertEqual(proto.cert_signature.algorithm_id, source.signature_algorithm()["algorithm"].long_name) self.assertEqual(proto.tbs_signature.algorithm_id, proto.cert_signature.algorithm_id) if source.signature()["parameters"]: self.assertEqual(proto.tbs_signature.parameters, source.signature()["parameters"]) else: self.assertFalse(proto.tbs_signature.HasField('parameters')) if source.signature_algorithm()["parameters"]: self.assertEqual(proto.cert_signature.parameters, source.signature_algorithm()["parameters"]) else: self.assertFalse(proto.cert_signature.HasField('parameters')) self.assertEqual(proto.tbs_signature.parameters, proto.cert_signature.parameters) self.assertEqual(proto.basic_constraint_ca, expect_ca_true)
def _scan_der_cert(der_certs, checks): current = -1 result = [] for log_index, der_cert, der_chain, entry_type in der_certs: try: current = log_index partial_result = [] certificate = None strict_failure = False try: certificate = cert.Certificate(der_cert) except error.Error as e: try: certificate = cert.Certificate(der_cert, strict_der=False) except error.Error as e: partial_result.append(asn1.All()) strict_failure = True else: if isinstance(e, error.ASN1IllegalCharacter): partial_result.append(asn1.Strict(reason=e.args[0], details=(e.string, e.index))) else: partial_result.append(asn1.Strict(reason=str(e))) if not strict_failure: for check in checks: partial_result += check.check(certificate) or [] desc = cert_desc.from_cert(certificate, partial_result) else: desc = certificate_pb2.X509Description() desc.der = der_cert desc.sha256_hash = hashlib.sha256(der_cert).digest() desc.entry_type = entry_type root = None if der_chain: try: issuer = cert.Certificate(der_chain[0], strict_der=False) except error.Error: pass else: desc.issuer_pk_sha256_hash = issuer.key_hash(hashfunc="sha256") try: root = cert.Certificate(der_chain[-1], strict_der=False) except error.Error: pass else: # No chain implies this is a root certificate. # Note that certificate may be None. root = certificate if root: for iss in [(type_.short_name, cert_desc.to_unicode( '.'.join(cert_desc.process_name(value.human_readable())))) for type_, value in root.issuer()]: proto_iss = desc.root_issuer.add() proto_iss.type, proto_iss.value = iss result.append((desc, log_index, partial_result)) except: batch_start, batch_end = der_certs[0][0], der_certs[-1][0] logging.exception( "Error scanning certificate %d in batch <%d, %d> - it will " "be excluded from the scan results", current, batch_start, batch_end) return result
def _scan_der_cert(der_certs): current = -1 result = [] for log_index, der_cert, der_chain, entry_type in der_certs: try: current = log_index certificate = None strict_failure = False try: certificate = cert.Certificate(der_cert) except error.Error as e: try: certificate = cert.Certificate(der_cert, strict_der=False) except error.Error as e: strict_failure = True if not strict_failure: desc = cert_desc.from_cert(certificate) else: desc = certificate_pb2.X509Description() desc.der = der_cert desc.sha256_hash = hashlib.sha256(der_cert).digest() desc.entry_type = entry_type root = None if der_chain: try: issuer = cert.Certificate(der_chain[0], strict_der=False) except error.Error: pass else: desc.issuer_pk_sha256_hash = issuer.key_hash( hashfunc="sha256") try: root = cert.Certificate(der_chain[-1], strict_der=False) except error.Error: pass else: # No chain implies this is a root certificate. # Note that certificate may be None. root = certificate if root: for iss in [ (type_.short_name, cert_desc.to_unicode('.'.join( cert_desc.process_name(value.human_readable())))) for type_, value in root.issuer() ]: proto_iss = desc.root_issuer.add() proto_iss.type, proto_iss.value = iss result.append((desc, log_index)) except: batch_start_index, batch_end_index = (der_certs[0][0], der_certs[-1][0]) logging.exception( "Error scanning certificate %d in batch <%d, %d> - it will " "be excluded from the scan results", current, batch_start_index, batch_end_index) return result