def test_scan_certs_by_subject_finds_by_literal_wildcard(self):
        cert = certificate_pb2.X509Description()
        cert.der = "hello-wild"
        cert.subject.extend([name_attribute("com.example.*")])
        cert.sha256_hash = 'cert'
        self.db().store_cert_desc(cert, 0, 0)
        cert2 = certificate_pb2.X509Description()
        cert2.der = "hello"
        cert2.subject.extend([name_attribute("com.example.www")])
        cert.sha256_hash = 'cert2'
        self.db().store_cert_desc(cert2, 1, 0)

        matches = [c for c in self.db().scan_certs_by_subject("*.example.com")]
        self.assertEqual(1, len(matches))
        self.assertEqual("hello-wild", matches[0])
    def test_scan_certs_by_subject_ignores_wildcard_cert(self):
        for i in range(4):
            cert = certificate_pb2.X509Description()
            cert.der = "hello-%d" % i
            cert.subject.extend([name_attribute("com.example.%d" % i)])
            cert.sha256_hash = str(i)
            self.db().store_cert_desc(cert, i, 0)
        cert = certificate_pb2.X509Description()
        cert.der = "hello-wild"
        cert.subject.extend([name_attribute("com.example.*")])
        cert.sha256_hash = 'asdf'
        self.db().store_cert_desc(cert, 0, 0)

        matches = {c for c in self.db().scan_certs_by_subject("2.example.com")}
        self.assertEqual(1, len(matches))
        self.assertTrue("hello-2" in matches)
Ejemplo n.º 3
0
    def test_scan_certs_by_subject_ignores_longer(self):
        cert = certificate_pb2.X509Description()
        cert.der = "hello"
        cert.subject.extend([name_attribute("example.com")])
        self.db().store_cert_desc(cert, 0, 0)

        matches = {c for c in self.db().scan_certs_by_subject(
                "mail.example.com")}
        self.assertEqual(0, len(matches))
Ejemplo n.º 4
0
def from_cert(certificate, observations=[]):
    """Pulls out interesting fields from certificate, so format of data will
    be similar in every database implementation."""
    proto = certificate_pb2.X509Description()
    proto.der = certificate.to_der()
    try:
        for sub in [(type_.short_name,
                     to_unicode('.'.join(process_name(value.human_readable()))))
                    for type_, value in certificate.subject()]:
            proto_sub = proto.subject.add()
            proto_sub.type, proto_sub.value = sub
    except cert.CertificateError:
        pass

    try:
        for iss in [(type_.short_name,
                     to_unicode('.'.join(process_name(value.human_readable()))))
                    for type_, value in certificate.issuer()]:
            proto_iss = proto.issuer.add()
            proto_iss.type, proto_iss.value = iss
    except cert.CertificateError:
        pass

    try:
        for alt in certificate.subject_alternative_names():
            proto_alt = proto.subject_alternative_names.add()
            proto_alt.type, proto_alt.value = (alt.component_key(),
                                               to_unicode('.'.join(process_name(
                                      alt.component_value().human_readable()))))
    except cert.CertificateError:
        pass

    try:
        proto.version = str(certificate.version())
    except cert.CertificateError:
        pass

    try:
        proto.serial_number = str(certificate.serial_number().human_readable()
                                  .upper().replace(':', ''))
    except cert.CertificateError:
        pass

    proto.sha256_hash = hashlib.sha256(proto.der).digest()

    for observation in observations:
        proto_obs = proto.observations.add()
        if observation.description:
            proto_obs.description = observation.description
        if observation.reason:
            proto_obs.reason = observation.reason
        proto_obs.details = observation.details_to_proto()

    return proto
Ejemplo n.º 5
0
    def test_scan_certs_by_subject_honours_limit(self):
        for i in range(0, 4):
            cert = certificate_pb2.X509Description()
            cert.der = "hello-%d" % i
            cert.subject.extend([name_attribute("com.domain")])
            cert.sha256_hash = str(i)
            self.db().store_cert_desc(cert, i, 0)

        matches = {c for c in self.db().scan_certs_by_subject("domain.com",
                                                              limit=2)}
        self.assertEqual(2, len(matches))
Ejemplo n.º 6
0
    def test_scan_certs_by_subject_finds_by_all_names(self):
        cert = certificate_pb2.X509Description()
        cert.der = "hello"
        cert.subject.extend([name_attribute("com.%d" % i) for i in range(4)])
        cert.sha256_hash = 'asdf'
        self.db().store_cert_desc(cert, 0, 0)

        for i in range(4):
            matches = [c for c in self.db().scan_certs_by_subject("%d.com" % i)]
            self.assertEqual(1, len(matches))
            self.assertEqual("hello", matches[0])
Ejemplo n.º 7
0
    def test_scan_certs_by_subject_finds_by_prefix(self):
        for i in range(4):
            cert = certificate_pb2.X509Description()
            cert.der = "hello-%d" % i
            cert.subject.extend([name_attribute("com.example" + (".%d" % i)*i)])
            cert.sha256_hash = str(i)
            self.db().store_cert_desc(cert, i, 0)

        matches = {c for c in self.db().scan_certs_by_subject("example.com")}
        self.assertEqual(4, len(matches))
        for i in range(4):
            self.assertTrue("hello-%d" % i in matches)
Ejemplo n.º 8
0
    def test_scan_certs_by_subject_finds_by_common_name(self):
        for i in range(4):
            cert = certificate_pb2.X509Description()
            cert.der = "hello-%d" % i
            cert.subject.extend([name_attribute("Trusty CA %d" % i)])
            cert.sha256_hash = str(i)
            self.db().store_cert_desc(cert, i, 0)

        for i in range(4):
            matches = [c for c in self.db().scan_certs_by_subject(
                                                            "Trusty CA %d" % i)]
            self.assertEqual(1, len(matches))
            self.assertEqual("hello-%d" % i, matches[0])
Ejemplo n.º 9
0
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))
Ejemplo n.º 10
0
    def test_store_cert_desc_ignores_duplicate(self):
        self.db().store_cert_desc(SAMPLE_CERT, 0, 0)
        sha256_hash = hashlib.sha256("hello\x00").digest()
        cert = self.db().get_cert_by_sha256_hash(sha256_hash)
        self.assertEqual("hello\x00", cert)

        # Store again
        hello2 = certificate_pb2.X509Description()
        hello2.der = SAMPLE_CERT.der
        hello2.subject.extend([name_attribute("com.example2")])
        hello2.sha256_hash = sha256_hash
        self.db().store_cert_desc(hello2, 1, 0)
        certs = [c for c in self.db().scan_certs_by_subject("example.com")]
        self.assertEqual(1, len(certs))
        self.assertEqual(SAMPLE_CERT.der, certs[0])
        certs = [c for c in self.db().scan_certs_by_subject("example2.com")]
        self.assertEqual(0, len(certs))
Ejemplo n.º 11
0
def from_cert(certificate, observations=[]):
    """Pulls out interesting fields from certificate, so format of data will
    be similar in every database implementation."""
    proto = certificate_pb2.X509Description()
    proto.der = certificate.to_der()
    try:
        for sub in [(type_.short_name,
                     to_unicode('.'.join(
                         process_name(value.human_readable(),
                                      type_.short_name == 'CN'))))
                    for type_, value in certificate.subject()]:
            proto_sub = proto.subject.add()
            proto_sub.type, proto_sub.value = sub
    except cert.CertificateError:
        pass

    try:
        for iss in [
            (type_.short_name,
             to_unicode('.'.join(process_name(value.human_readable(), False))))
                for type_, value in certificate.issuer()
        ]:
            proto_iss = proto.issuer.add()
            proto_iss.type, proto_iss.value = iss
    except cert.CertificateError:
        pass

    try:
        for alt in certificate.subject_alternative_names():
            proto_alt = proto.subject_alternative_names.add()
            proto_alt.type, proto_alt.value = (
                alt.component_key(),
                to_unicode('.'.join(
                    process_name(alt.component_value().human_readable()))))
    except cert.CertificateError:
        pass

    try:
        proto.version = str(certificate.version())
    except cert.CertificateError:
        pass

    try:
        proto.serial_number = str(
            certificate.serial_number().human_readable().upper().replace(
                ':', ''))
    except cert.CertificateError:
        pass

    try:
        tbs_alg = certificate.signature()["algorithm"]
        if tbs_alg:
            proto.tbs_signature.algorithm_id = tbs_alg.long_name

        tbs_params = certificate.signature()["parameters"]
        if tbs_params:
            proto.tbs_signature.parameters = tbs_params.value

        cert_alg = certificate.signature_algorithm()["algorithm"]
        if cert_alg:
            proto.cert_signature.algorithm_id = cert_alg.long_name

        cert_params = certificate.signature_algorithm()["parameters"]
        if cert_params:
            proto.cert_signature.parameters = cert_params.value
    except cert.CertificateError:
        pass

    try:
        proto.basic_constraint_ca = bool(certificate.basic_constraint_ca())
    except cert.CertificateError:
        pass

    try:
        proto.validity.not_before, proto.validity.not_after = (
            1000 * int(calendar.timegm(certificate.not_before())),
            1000 * int(calendar.timegm(certificate.not_after())))
    except cert.CertificateError:
        pass

    proto.sha256_hash = hashlib.sha256(proto.der).digest()

    for observation in observations:
        proto_obs = proto.observations.add()
        if observation.description:
            proto_obs.description = observation.description
        if observation.reason:
            proto_obs.reason = observation.reason
        proto_obs.details = observation.details_to_proto()

    return proto
Ejemplo n.º 12
0
import abc
import hashlib
from ct.proto import certificate_pb2


def name_attribute(name):
    att = certificate_pb2.DNAttribute()
    att.type, att.value = "CN", name
    return att


SAMPLE_CERT = certificate_pb2.X509Description()
SAMPLE_CERT.der = "hello\x00"
SAMPLE_CERT.subject.extend([name_attribute("com.example")])
SAMPLE_CERT.sha256_hash = hashlib.sha256("hello\x00").digest()
FOUR_CERTS = []
for i in range(0, 4):
    tmp = certificate_pb2.X509Description()
    tmp.der = "hello-%d" % i
    tmp.subject.extend([name_attribute("com.domain-%d" % i)])
    tmp.sha256_hash = hashlib.sha256("hello-%d" % i).digest()
    FOUR_CERTS.append((tmp, i))


# This class provides common tests for all cert database implementations.
# It only inherits from object so that unittest won't attempt to run the test_*
# methods on this class. Derived classes should use multiple inheritance
# from CertDBTest and unittest.TestCase to get test automation.
class CertDBTest(object):
    """All cert database tests should derive from this class as well as
    unittest.TestCase."""
Ejemplo n.º 13
0
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