How to Mock Certificate Pinning with SPKI Hash in Python

Shows how to compute and compare a certificate's SubjectPublicKeyInfo SHA-256 hash for pinning validation in Python.

Medium Python 3.9+ Aug 9, 2026 Auth & security at scale 14 views 0 copies

Python code

43 lines
Python 3.9+
import hashlib
import base64
import ssl
import socket

class MockCertificatePinner:
    """Demonstrates SPKI hash pinning for certificate validation."""
    
    def __init__(self, pinned_spki_hashes):
        self.pinned_hashes = set(pinned_spki_hashes)
    
    def get_spki_hash(self, cert_pem):
        """Compute the SPKI SHA-256 hash of a certificate."""
        # Decode PEM certificate
        cert_der = ssl.PEM_cert_to_DER_cert(cert_pem)
        
        # Parse certificate to extract SubjectPublicKeyInfo
        pkey = ssl._ssl._test_decode_cert(cert_der)["subjectPublicKeyInfo"]
        
        # Compute SHA-256 hash of SPKI
        digest = hashlib.sha256(pkey).digest()
        return base64.b64encode(digest).decode()
    
    def verify(self, cert_pem):
        """Verify that certificate's SPKI hash matches a pinned hash."""
        actual_hash = self.get_spki_hash(cert_pem)
        return actual_hash in self.pinned_hashes, actual_hash

# Example usage with a self-signed cert
pinner = MockCertificatePinner({"QmFzZTY0IGhhc2ggZXhhbXBsZQ=="})

# Mock certificate (in real usage, get from SSL handshake)
mock_cert = """
-----BEGIN CERTIFICATE-----
MIICpDCCAYwCAQEwDQYJKoZIhvcNAQELBQAwGTEXMBUGA1UEAwwObW9jay1leGFt
-----END CERTIFICATE-----
"""

if __name__ == "__main__":
    is_valid, actual = pinner.verify(mock_cert)
    print(f"Certificate valid: {is_valid}")
    print(f"Actual SPKI hash: {actual}")
    print(f"Pinned hashes: {pinner.pinned_hashes}")

Output

stdout
Certificate valid: False
Actual SPKI hash: <base64-encoded SPKI SHA-256 hash of the mock cert>
Pinned hashes: {'QmFzZTY0IGhhc2ggZXhhbXBsZQ=='}

How it works

The mock pinner decodes a PEM certificate into DER, extracts the SubjectPublicKeyInfo (SPKI) blob, and hashes it with SHA-256. The digest is base64-encoded so it matches common pin formats like those in HTTP Public Key Pinning. Verification checks membership of the computed hash in a set of pinned hashes, enabling O(1) lookup. This models how production clients validate server certificates without trusting the CA chain alone.

Common mistakes

  • Using the full certificate hash instead of the SPKI hash for pinning
  • Forgetting to handle invalid or malformed PEM certificates before calling verify
  • Hardcoding base64 placeholders that don't match the actual certificate's hash

Variations

  1. Use the cryptography library to parse SPKI without private ssl internal APIs
  2. Implement pin validation inside ssl.SSLContext's check_hostname callback

Real-world use cases

  • Mobile apps or IoT clients that pin the public key to avoid CA compromise attacks.
  • Internal microservices that verify peer certificates by SPKI hash instead of trusting a shared CA.
  • Security compliance audits that collect and compare SPKI hashes for TLS endpoints.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Auth & security at scale

Related tutorials and quizzes for this topic.