Service Identity Verification
Service-identity provides robust service identity verification for Python applications using `pyOpenSSL` and `cryptography`. It ensures that a presented certificate matches the expected identity of the service being connected to, preventing common man-in-the-middle attacks. The current version is 24.2.0, with a release cadence that is irregular but typically sees major updates annually or as needed for security fixes and breaking changes.
Warnings
- breaking Since version 23.1.0, `service-identity` completely ignores the `commonName` field in certificates for identity verification. Certificates relying solely on `commonName` will fail verification, requiring `subjectAltName` for host identity.
- breaking As of version 24.1.0, if a certificate lacks any `subjectAltName` entries, `service_identity.CertificateError` is raised instead of `service_identity.VerificationError`. This change improves clarity but may require updates to error handling logic in existing applications.
- gotcha Ensure you use the correct `extract_patterns` function based on your certificate object type. Use `service_identity.cryptography.extract_patterns` for `cryptography.x509.Certificate` objects and `service_identity.pyopenssl.extract_patterns` for `pyOpenSSL.SSL.X509` objects. Mixing these will lead to `TypeError` or `AttributeError`.
Install
-
pip install service-identity
Imports
- verify_service_identity
from service_identity import verify_service_identity
- CertificateError
from service_identity.exceptions import CertificateError
- extract_patterns
from service_identity.cryptography import extract_patterns
- DNS_ID
from service_identity.patterns import DNS_ID
- DNSPattern
from service_identity.patterns import DNSPattern
Quickstart
from service_identity import verify_service_identity
from service_identity.patterns import DNS_ID, DNSPattern
from service_identity.exceptions import CertificateError
# --- Example 1: Successful verification ---
# In a real scenario, certificate_patterns would be extracted from an actual
# certificate object using service_identity.cryptography.extract_patterns()
# or service_identity.pyopenssl.extract_patterns().
certificate_patterns_ok = [
DNSPattern("example.com"),
DNSPattern("www.example.com")
]
service_identity_ok = DNS_ID("www.example.com")
try:
verify_service_identity(certificate_patterns_ok, service_identity_ok)
print(f"[SUCCESS] Service identity '{service_identity_ok.id}' verified.")
except CertificateError as e:
print(f"[FAILURE] Verification failed: {e}")
# --- Example 2: Failed verification (mismatched hostname) ---
certificate_patterns_mismatch = [DNSPattern("example.com")]
service_identity_mismatch = DNS_ID("wrong-host.com")
try:
verify_service_identity(certificate_patterns_mismatch, service_identity_mismatch)
print(f"[SUCCESS] Service identity '{service_identity_mismatch.id}' verified.")
except CertificateError as e:
print(f"[FAILURE] Verification failed: {e}")
# --- Example 3: Failed verification (simulated missing subjectAltName) ---
# This simulates a certificate that has no subjectAltName entries,
# which will always lead to a CertificateError.
certificate_patterns_no_san = []
service_identity_no_san = DNS_ID("anyhost.com")
try:
verify_service_identity(certificate_patterns_no_san, service_identity_no_san)
print(f"[SUCCESS] Service identity '{service_identity_no_san.id}' verified.")
except CertificateError as e:
print(f"[FAILURE] Verification failed (missing SAN): {e}")