def test_dns(self):
     """
     Returns the correct DNSPattern from a certificate.
     """
     rv = extract_ids(CERT_DNS_ONLY)
     assert [
         DNSPattern(b"www.twistedmatrix.com"),
         DNSPattern(b"twistedmatrix.com"),
     ] == rv
    def test_ip(self):
        """
        Returns IP patterns.
        """
        rv = extract_ids(CERT_EVERYTHING)

        assert [
            DNSPattern(pattern=b"service.identity.invalid"),
            DNSPattern(pattern=b"*.wildcard.service.identity.invalid"),
            DNSPattern(pattern=b"service.identity.invalid"),
            DNSPattern(pattern=b"single.service.identity.invalid"),
            IPAddressPattern(pattern=ipaddress.IPv4Address(u"1.1.1.1")),
            IPAddressPattern(pattern=ipaddress.IPv6Address(u"::1")),
            IPAddressPattern(pattern=ipaddress.IPv4Address(u"2.2.2.2")),
            IPAddressPattern(pattern=ipaddress.IPv6Address(u"2a00:1c38::53")),
        ] == rv
Пример #3
0
 def test_invalid_wildcard(self):
     """
     Integration test with _validate_pattern: catches double wildcards thus
     is used if an wildward is present.
     """
     with pytest.raises(CertificateError):
         DNSPattern(b"*.foo.*")
Пример #4
0
 def test_cn_ids_are_used_as_fallback(self):
     """
     CNs are returned as DNSPattern if no other IDs are present
     and a warning is raised.
     """
     with pytest.warns(SubjectAltNameWarning):
         rv = extract_ids(X509_CN_ONLY)
     assert [DNSPattern(b"www.microsoft.com")] == rv
Пример #5
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
Пример #6
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
Пример #7
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
Пример #8
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]
Пример #9
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
    def test_cn_ids_are_used_as_fallback(self):
        """
        CNs are returned as DNSPattern if no other IDs are present
        and a warning is raised.
        """
        with pytest.warns(SubjectAltNameWarning) as ws:
            rv = extract_ids(CERT_CN_ONLY)

        msg = ws[0].message.args[0]

        assert [DNSPattern(b"www.microsoft.com")] == rv
        assert msg.startswith(
            "Certificate with CN 'www.microsoft.com' has no `subjectAltName`")
        assert msg.endswith(
            "service-identity will remove the support for it in mid-2018.")
Пример #11
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))
Пример #12
0
 def test_simple_mismatch(self):
     """
     Simple integration test with _hostname_matches with a mismatch.
     """
     assert not DNS_ID(u"foo.com").verify(DNSPattern(b"bar.com"))
Пример #13
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=[],
    )
Пример #14
0
 def test_catches_ip_address(self):
     """
     IP addresses are invalid and raise a :class:`CertificateError`.
     """
     with pytest.raises(CertificateError):
         DNSPattern(b"192.168.0.0")
Пример #15
0
 def test_catches_NULL_bytes(self):
     """
     Raise :class:`CertificateError` if a NULL byte is in the hostname.
     """
     with pytest.raises(CertificateError):
         DNSPattern(b"www.google.com\0nasty.h4x0r.com")
Пример #16
0
 def test_catches_empty(self):
     """
     Empty DNS-IDs raise a :class:`CertificateError`.
     """
     with pytest.raises(CertificateError):
         DNSPattern(b" ")
Пример #17
0
 def test_enforces_bytes(self):
     """
     Raise TypeError if unicode is passed.
     """
     with pytest.raises(TypeError):
         DNSPattern(u"foo.com")