Beispiel #1
0
 def test_integration_dns_id_fail(self):
     """
     Raise VerificationError if no certificate id matches the supplied
     service ids.
     """
     i = DNS_ID(u"wrong.host")
     with pytest.raises(VerificationError) as e:
         verify_service_identity(
             DNS_IDS, obligatory_ids=[i], optional_ids=[]
         )
     assert [DNSMismatch(mismatched_id=i)] == e.value.errors
Beispiel #2
0
def _verify_hostname(certificate, hostname):
    """
    Verify whether *certificate* has a valid certificate chain for *hostname*.
    """
    # Using private APIs here because service_identity doesn't *quite* have the
    # right public API.
    verify_service_identity(
        cert_patterns=extract_ids(certificate),
        obligatory_ids=[DNS_ID(hostname)],
        optional_ids=[],
    )
Beispiel #3
0
 def test_integration_dns_id_fail(self):
     """
     Raise VerificationError if no certificate id matches the supplied
     service ids.
     """
     i = DNS_ID(u"wrong.host")
     with pytest.raises(VerificationError) as e:
         verify_service_identity(DNS_IDS,
                                 obligatory_ids=[i],
                                 optional_ids=[])
     assert [DNSMismatch(mismatched_id=i)] == e.value.errors
 def test_obligatory_mismatch(self):
     """
     Raise if one of the obligatory IDs doesn't match.
     """
     i = DNS_ID(u"example.net")
     with pytest.raises(VerificationError) as e:
         verify_service_identity(
             [SRVPattern(b"_mail.example.net"), DNSPattern(b"example.com")],
             obligatory_ids=[SRV_ID(u"_mail.example.net"), i],
             optional_ids=[],
         )
     assert [DNSMismatch(mismatched_id=i)] == e.value.errors
Beispiel #5
0
 def test_obligatory_mismatch(self):
     """
     Raise if one of the obligatory IDs doesn't match.
     """
     i = DNS_ID(u"example.net")
     with pytest.raises(VerificationError) as e:
         verify_service_identity(
             [SRVPattern(b"_mail.example.net"), DNSPattern(b"example.com")],
             obligatory_ids=[SRV_ID(u"_mail.example.net"), i],
             optional_ids=[],
         )
     assert [DNSMismatch(mismatched_id=i)] == e.value.errors
 def test_optional_mismatch(self):
     """
     Raise VerificationError if an ID from optional_ids does not match
     a pattern of respective type even if obligatory IDs match.
     """
     i = SRV_ID(u"_xmpp.example.com")
     with pytest.raises(VerificationError) as e:
         verify_service_identity(
             [DNSPattern(b"example.net"), SRVPattern(b"_mail.example.com")],
             obligatory_ids=[DNS_ID(u"example.net")],
             optional_ids=[i],
         )
     assert [SRVMismatch(mismatched_id=i)] == e.value.errors
Beispiel #7
0
 def test_optional_mismatch(self):
     """
     Raise VerificationError if an ID from optional_ids does not match
     a pattern of respective type even if obligatory IDs match.
     """
     i = SRV_ID(u"_xmpp.example.com")
     with pytest.raises(VerificationError) as e:
         verify_service_identity(
             [DNSPattern(b"example.net"), SRVPattern(b"_mail.example.com")],
             obligatory_ids=[DNS_ID(u"example.net")],
             optional_ids=[i],
         )
     assert [SRVMismatch(mismatched_id=i)] == e.value.errors
Beispiel #8
0
 def match(self, value):
     # This is somewhat terrible. Probably can be better after
     # pyca/service_identity#14 is resolved.
     target_ids = [
         DNSPattern(target_name.encode('utf-8'))
         for target_name in (value.extensions.get_extension_for_oid(
             ExtensionOID.SUBJECT_ALTERNATIVE_NAME).value.
                             get_values_for_type(x509.DNSName))
     ]
     ids = [DNS_ID(self.name)]
     try:
         verify_service_identity(cert_patterns=target_ids,
                                 obligatory_ids=ids,
                                 optional_ids=[])
     except VerificationError:
         return Mismatch('{!r} is not valid for {!r}'.format(
             value, self.name))
Beispiel #9
0
 def match(self, value):
     # This is somewhat terrible. Probably can be better after
     # pyca/service_identity#14 is resolved.
     target_ids = [
         DNSPattern(target_name.encode('utf-8'))
         for target_name
         in (
             value.extensions
             .get_extension_for_oid(
                 ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
             .value
             .get_values_for_type(x509.DNSName)
         )]
     ids = [DNS_ID(self.name)]
     try:
         verify_service_identity(
             cert_patterns=target_ids, obligatory_ids=ids, optional_ids=[])
     except VerificationError:
         return Mismatch(
             '{!r} is not valid for {!r}'.format(value, self.name))
Beispiel #10
0
 def test_optional_missing(self):
     """
     Optional IDs may miss as long as they don't conflict with an existing
     pattern.
     """
     p = DNSPattern(b"mail.foo.com")
     i = DNS_ID(u"mail.foo.com")
     rv = verify_service_identity(
         [p], obligatory_ids=[i], optional_ids=[SRV_ID(u"_mail.foo.com")]
     )
     assert [ServiceMatch(cert_pattern=p, service_id=i)] == rv
Beispiel #11
0
 def test_dns_id_success(self):
     """
     Return pairs of certificate ids and service ids on matches.
     """
     rv = verify_service_identity(DNS_IDS,
                                  [DNS_ID(u"twistedmatrix.com")],
                                  [])
     assert [
         ServiceMatch(cert_pattern=DNSPattern(b"twistedmatrix.com"),
                      service_id=DNS_ID(u"twistedmatrix.com"),),
     ] == rv
Beispiel #12
0
 def test_optional_missing(self):
     """
     Optional IDs may miss as long as they don't conflict with an existing
     pattern.
     """
     p = DNSPattern(b"mail.foo.com")
     i = DNS_ID(u"mail.foo.com")
     rv = verify_service_identity([p],
                                  obligatory_ids=[i],
                                  optional_ids=[SRV_ID(u"_mail.foo.com")])
     assert [ServiceMatch(cert_pattern=p, service_id=i)] == rv
 def test_dns_id_success(self):
     """
     Return pairs of certificate ids and service ids on matches.
     """
     rv = verify_service_identity(extract_ids(CERT_DNS_ONLY),
                                  [DNS_ID(u"twistedmatrix.com")],
                                  [])
     assert [
         ServiceMatch(cert_pattern=DNSPattern(b"twistedmatrix.com"),
                      service_id=DNS_ID(u"twistedmatrix.com"),),
     ] == rv
Beispiel #14
0
 def test_vsi_dns_id_success(self):
     """
     Return pairs of certificate ids and service ids on matches.
     """
     rv = verify_service_identity(extract_ids(CERT_DNS_ONLY),
                                  [DNS_ID(u("twistedmatrix.com"))])
     self.assertEqual(
         [
             (DNSPattern(b"twistedmatrix.com"),
              DNS_ID(u("twistedmatrix.com")),),
         ], rv
     )
Beispiel #15
0
 def test_vsi_contains_srvs_and_matches(self):
     """
     If a matching SRV-ID is found, return the tuple within the returned
     list and don't raise an error.
     """
     p = SRVPattern(b"_mail.example.net")
     i = SRV_ID(u("_mail.example.net"))
     rv = verify_service_identity(
         [DNSPattern(b"example.net"), p],
         [DNS_ID(u("example.net")), i],
     )
     self.assertEqual((p, i), rv[1])
Beispiel #16
0
 def test_vsi_contains_uris_and_matches(self):
     """
     If a matching URI-ID is found, return the tuple within the returned
     list and don't raise an error.
     """
     p = URIPattern(b"sip:example.net")
     uri_id = URI_ID(u("sip:example.net"))
     rv = verify_service_identity(
         [DNSPattern(b"example.net"), p],
         [DNS_ID(u("example.net")), uri_id],
     )
     self.assertEqual((p, uri_id), rv[1])
Beispiel #17
0
 def test_contains_optional_and_matches(self):
     """
     If an optional ID is found, return the match within the returned
     list and don't raise an error.
     """
     p = SRVPattern(b"_mail.example.net")
     i = SRV_ID(u"_mail.example.net")
     rv = verify_service_identity(
         [DNSPattern(b"example.net"), p],
         obligatory_ids=[DNS_ID(u"example.net")],
         optional_ids=[i],
     )
     assert ServiceMatch(cert_pattern=p, service_id=i) == rv[1]
 def test_contains_optional_and_matches(self):
     """
     If an optional ID is found, return the match within the returned
     list and don't raise an error.
     """
     p = SRVPattern(b"_mail.example.net")
     i = SRV_ID(u"_mail.example.net")
     rv = verify_service_identity(
         [DNSPattern(b"example.net"), p],
         obligatory_ids=[DNS_ID(u"example.net")],
         optional_ids=[i],
     )
     assert ServiceMatch(cert_pattern=p, service_id=i) == rv[1]
Beispiel #19
0
    def test_ip_address_success(self):
        """
        IP addresses patterns are matched against IP address IDs.
        """
        ip4 = ipaddress.ip_address(u"2.2.2.2")
        ip6 = ipaddress.ip_address(u"2a00:1c38::53")
        id4 = IPAddress_ID(six.text_type(ip4))
        id6 = IPAddress_ID(six.text_type(ip6))
        rv = verify_service_identity(extract_ids(CERT_EVERYTHING), [id4, id6],
                                     [])

        assert [
            ServiceMatch(id4, IPAddressPattern(ip4)),
            ServiceMatch(id6, IPAddressPattern(ip6)),
        ] == rv
Beispiel #20
0
    def test_ip_address_success(self):
        """
        IP addresses patterns are matched against IP address IDs.
        """
        ip4 = ipaddress.ip_address(u"2.2.2.2")
        ip6 = ipaddress.ip_address(u"2a00:1c38::53")
        id4 = IPAddress_ID(six.text_type(ip4))
        id6 = IPAddress_ID(six.text_type(ip6))
        rv = verify_service_identity(
            extract_ids(CERT_EVERYTHING), [id4, id6], []
        )

        assert [
            ServiceMatch(id4, IPAddressPattern(ip4)),
            ServiceMatch(id6, IPAddressPattern(ip6)),
        ] == rv
Beispiel #21
0
def verifyHostname(connection, hostname):
    if _is_ip_address(hostname):
        hostname_id = IPADDRESS_ID(hostname)
    else:
        hostname_id = DNS_ID(hostname)

    cert = connection.get_peer_certificate()
    ids = []

    # Basically the same as service_identity.pyopenssl.extract_ids, but with
    # subjectAltName support for iPAddress IDs and IP Addresses stuck in dNSName ids
    for i in range(cert.get_extension_count()):
        ext = cert.get_extension(i)
        if ext.get_short_name() == b"subjectAltName":
            names, _ = decode(ext.get_data(), asn1Spec=GeneralNames())
            for n in names:
                name_string = n.getName()

                if name_string == "iPAddress":
                    ids.append(IPADDRESSPattern(n.getComponent().asOctets()))

                elif name_string == "dNSName" and _is_ip_address(
                        n.getComponent().asOctets().strip()):
                    # If an IP Address is passed as a dNSName, it will
                    # cause service_identity to throw an exception, as
                    # it doesn't consider this valid.   From reading the
                    # RFCs, i think it's a gray area, so i'm going to
                    # allow it, since we've seen it happen with a customer.
                    try:
                        ip_string = n.getComponent().asOctets().strip()
                        if ":" in ip_string:
                            value = inet_pton(AF_INET6, ip_string)
                        else:
                            value = inet_pton(AF_INET, ip_string)

                        ids.append(IPADDRESSPattern(value))
                    except CertificateError as e:
                        log.warning(
                            "Ignoring invalid dNSName record in subjectAltName: %s",
                            e)

                # Normal behavior below:
                elif name_string == "dNSName":
                    ids.append(DNSPattern(n.getComponent().asOctets()))
                elif name_string == "uniformResourceIdentifier":
                    ids.append(URIPattern(n.getComponent().asOctets()))
                elif name_string == "otherName":
                    comp = n.getComponent()
                    oid = comp.getComponentByPosition(0)
                    if oid == ID_ON_DNS_SRV:
                        srv, _ = decode(comp.getComponentByPosition(1))
                        if isinstance(srv, IA5String):
                            ids.append(SRVPattern(srv.asOctets()))
                        else:  # pragma: nocover
                            raise CertificateError(
                                "Unexpected certificate content.")

    if not ids:
        # http://tools.ietf.org/search/rfc6125#section-6.4.4
        # A client MUST NOT seek a match for a reference identifier of CN-ID if
        # the presented identifiers include a DNS-ID, SRV-ID, URI-ID, or any
        # application-specific identifier types supported by the client.
        warnings.warn(
            "Certificate has no `subjectAltName`, falling back to check for a "
            "`commonName` for now.  This feature is being removed by major "
            "browsers and deprecated by RFC 2818.", SubjectAltNameWarning)
        ids = [
            DNSPattern(c[1]) for c in cert.get_subject().get_components()
            if c[0] == b"CN"
        ]

    verify_service_identity(
        cert_patterns=ids,
        obligatory_ids=[hostname_id],
        optional_ids=[],
    )
Beispiel #22
0
def verifyHostname(connection, hostname):
    if _is_ip_address(hostname):
        hostname_id = IPADDRESS_ID(hostname)
    else:
        hostname_id = DNS_ID(hostname)

    cert = connection.get_peer_certificate()
    ids = []

    # Basically the same as service_identity.pyopenssl.extract_ids, but with
    # subjectAltName support for iPAddress IDs and IP Addresses stuck in dNSName ids
    for i in range(cert.get_extension_count()):
        ext = cert.get_extension(i)
        if ext.get_short_name() == b"subjectAltName":
            names, _ = decode(ext.get_data(), asn1Spec=GeneralNames())
            for n in names:
                name_string = n.getName()

                if name_string == "iPAddress":
                    ids.append(IPADDRESSPattern(n.getComponent().asOctets()))

                elif name_string == "dNSName" and _is_ip_address(n.getComponent().asOctets().strip()):
                    # If an IP Address is passed as a dNSName, it will
                    # cause service_identity to throw an exception, as
                    # it doesn't consider this valid.   From reading the
                    # RFCs, i think it's a gray area, so i'm going to
                    # allow it, since we've seen it happen with a customer.
                    try:
                        ip_string = n.getComponent().asOctets().strip()
                        if ":" in ip_string:
                            value = inet_pton(AF_INET6, ip_string)
                        else:
                            value = inet_pton(AF_INET, ip_string)

                        ids.append(IPADDRESSPattern(value))
                    except CertificateError as e:
                        log.warning(
                            "Ignoring invalid dNSName record in subjectAltName: %s", e)

                # Normal behavior below:
                elif name_string == "dNSName":
                    ids.append(DNSPattern(n.getComponent().asOctets()))
                elif name_string == "uniformResourceIdentifier":
                    ids.append(URIPattern(n.getComponent().asOctets()))
                elif name_string == "otherName":
                    comp = n.getComponent()
                    oid = comp.getComponentByPosition(0)
                    if oid == ID_ON_DNS_SRV:
                        srv, _ = decode(comp.getComponentByPosition(1))
                        if isinstance(srv, IA5String):
                            ids.append(SRVPattern(srv.asOctets()))
                        else:  # pragma: nocover
                            raise CertificateError(
                                "Unexpected certificate content.")

    if not ids:
        # http://tools.ietf.org/search/rfc6125#section-6.4.4
        # A client MUST NOT seek a match for a reference identifier of CN-ID if
        # the presented identifiers include a DNS-ID, SRV-ID, URI-ID, or any
        # application-specific identifier types supported by the client.
        warnings.warn(
            "Certificate has no `subjectAltName`, falling back to check for a "
            "`commonName` for now.  This feature is being removed by major "
            "browsers and deprecated by RFC 2818.",
            SubjectAltNameWarning
        )
        ids = [DNSPattern(c[1])
               for c
               in cert.get_subject().get_components()
               if c[0] == b"CN"]

    verify_service_identity(
        cert_patterns=ids,
        obligatory_ids=[hostname_id],
        optional_ids=[],
    )