API#

Note

So far, public high-level APIs are only available for host names (RFC 6125) and IP addresses (RFC 2818). All IDs specified by RFC 6125 are already implemented though. If you’d like to play with them and provide feedback have a look at the verify_service_identity function in the hazmat module.

PyCA cryptography#

service_identity.cryptography.verify_certificate_hostname(certificate, hostname)#

Verify whether certificate is valid for hostname.

Note

Nothing is verified about the authority of the certificate; the caller must verify that the certificate chains to an appropriate trust root themselves.

Parameters:
  • certificate (Certificate) – A cryptography X509 certificate object.

  • hostname (str) – The hostname that certificate should be valid for.

Raises:

Changed in version 24.1.0: CertificateError is raised if the certificate contains no subjectAltNames instead of VerificationError.

service_identity.cryptography.verify_certificate_ip_address(certificate, ip_address)#

Verify whether certificate is valid for ip_address.

Note

Nothing is verified about the authority of the certificate; the caller must verify that the certificate chains to an appropriate trust root themselves.

Parameters:
  • certificate (Certificate) – A cryptography X509 certificate object.

  • ip_address (str) – The IP address that connection should be valid for. Can be an IPv4 or IPv6 address.

Raises:

New in version 18.1.0.

Changed in version 24.1.0: CertificateError is raised if the certificate contains no subjectAltNames instead of VerificationError.

service_identity.cryptography.extract_patterns(cert)#

Extract all valid ID patterns from a certificate for service verification.

Parameters:

cert (Certificate) – The certificate to be dissected.

Returns:

List of IDs.

Return type:

Sequence[SRVPattern | URIPattern | DNSPattern | IPAddressPattern]

Changed in version 23.1.0: commonName is not used as a fallback anymore.

pyOpenSSL#

service_identity.pyopenssl.verify_hostname(connection, hostname)#

Verify whether the certificate of connection is valid for hostname.

Parameters:
  • connection (Connection) – A pyOpenSSL connection object.

  • hostname (str) – The hostname that connection should be connected to.

Raises:

Changed in version 24.1.0: CertificateError is raised if the certificate contains no subjectAltNames instead of VerificationError.

In practice, this may look like the following:

import argparse
import pprint
import socket

import idna

from OpenSSL import SSL

import service_identity


parser = argparse.ArgumentParser(
    description="Connect to HOST, inspect its certificate "
    "and verify if it's valid for its hostname."
)
parser.add_argument("HOST")
args = parser.parse_args()
hostname = args.HOST

ctx = SSL.Context(SSL.TLSv1_2_METHOD)
ctx.set_verify(SSL.VERIFY_PEER, lambda conn, cert, errno, depth, ok: bool(ok))
ctx.set_default_verify_paths()

conn = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
conn.set_tlsext_host_name(idna.encode(hostname))
conn.connect((hostname, 443))

try:
    conn.do_handshake()

    if cert := conn.get_peer_certificate():
        print("Server certificate is valid for the following patterns:\n")
        pprint.pprint(service_identity.pyopenssl.extract_patterns(cert))

    try:
        service_identity.pyopenssl.verify_hostname(conn, hostname)
    except service_identity.VerificationError:
        print(f"\nPresented certificate is NOT valid for {hostname}.")
    finally:
        conn.shutdown()
except SSL.Error as e:
    print(f"TLS Handshake failed: {e!r}.")
finally:
    conn.close()
service_identity.pyopenssl.verify_ip_address(connection, ip_address)#

Verify whether the certificate of connection is valid for ip_address.

Parameters:
  • connection (Connection) – A pyOpenSSL connection object.

  • ip_address (str) – The IP address that connection should be connected to. Can be an IPv4 or IPv6 address.

Raises:

New in version 18.1.0.

Changed in version 24.1.0: CertificateError is raised if the certificate contains no subjectAltNames instead of VerificationError.

service_identity.pyopenssl.extract_patterns(cert)#

Extract all valid ID patterns from a certificate for service verification.

Parameters:

cert (X509) – The certificate to be dissected.

Returns:

List of IDs.

Return type:

Sequence[SRVPattern | URIPattern | DNSPattern | IPAddressPattern]

Changed in version 23.1.0: commonName is not used as a fallback anymore.

Hazardous Materials#

Danger

The following APIs require reader’s discretion. They are stable and they’ve been using internally by service-identity for years, but you need to know what you’re doing.

Pattern Objects#

The following are the objects return by the extract_patterns functions. They each carry the attributes that are necessary to match an ID of their type.

service_identity.hazmat.CertificatePattern#

A Union of all possible patterns that can be extracted from a certificate.

It includes all of those that follow now.

class service_identity.hazmat.DNSPattern(pattern)#

A DNS pattern as extracted from certificates.

pattern: bytes#

The pattern.

class service_identity.hazmat.IPAddressPattern(pattern)#

An IP address pattern as extracted from certificates.

pattern: IPv4Address | IPv6Address#

The pattern.

class service_identity.hazmat.URIPattern(protocol_pattern, dns_pattern)#

An URI pattern as extracted from certificates.

dns_pattern: DNSPattern#

The pattern for the DNS part.

protocol_pattern: bytes#

The pattern for the protocol part.

class service_identity.hazmat.SRVPattern(name_pattern, dns_pattern)#

An SRV pattern as extracted from certificates.

dns_pattern: DNSPattern#

The pattern for the DNS part.

name_pattern: bytes#

The pattern for the name part.

Universal Errors and Warnings#

exception service_identity.VerificationError(errors)#

Service identity verification failed.

exception service_identity.CertificateError#

Certificate contains invalid or unexpected data.

This includes the case where s certificate contains no subjectAltNames.

exception service_identity.SubjectAltNameWarning#

This warning is not used anymore and will be removed in a future version.

Formerly:

Server Certificate does not contain a SubjectAltName.

Hostname matching is performed on the CommonName which is deprecated.

Deprecated since version 23.1.0.