SSL Certificate Pinning Implementation Guide 2025

📅 Published: December 1, 2025 | ⏱️ 11 min read | ✍️ Mobile Security Team
SSL Certificate Pinning

SSL certificate pinning is a critical security technique that protects mobile applications and sensitive communications from man-in-the-middle attacks by validating that the server's certificate matches a known, trusted certificate or public key. In 2025, with increasing sophistication of network-based attacks and the prevalence of compromised networks, certificate pinning has become an essential security control for high-security applications.

This comprehensive guide covers everything you need to know about implementing SSL certificate pinning, including strategies for iOS and Android, backup pin management, certificate rotation, and operational best practices.

Understanding SSL Certificate Pinning

What is Certificate Pinning?

Certificate pinning is a security mechanism where an application validates that the server's SSL certificate matches a pre-defined certificate or public key that has been "pinned" within the application. This prevents attackers from using fraudulent certificates, even if they're signed by a trusted Certificate Authority.

Why Certificate Pinning Matters

Traditional SSL/TLS validation relies on the system's trust store, which contains hundreds of trusted Certificate Authorities. If any of these CAs are compromised or issue fraudulent certificates, attackers can perform man-in-the-middle attacks. Certificate pinning mitigates this risk by:

  • Reducing Attack Surface: Limits trust to specific certificates rather than all CAs in the system trust store
  • Preventing MITM Attacks: Blocks attacks using rogue certificates, even if signed by trusted CAs
  • Protecting Sensitive Data: Essential for banking apps, healthcare apps, and applications handling sensitive user data
  • Compliance Requirements: Required by many security standards for high-risk applications
  • Defense in Depth: Adds an additional security layer beyond standard SSL/TLS validation

Types of Certificate Pinning

There are several approaches to certificate pinning, each with different trade-offs:

  • Certificate Pinning: Pin the entire certificate. Simple but requires app updates when certificates are renewed.
  • Public Key Pinning: Pin only the public key. More flexible as the same key can be used across certificate renewals.
  • Subject Public Key Info (SPKI) Pinning: Pin the hash of the Subject Public Key Info. Most recommended approach in 2025.
  • Certificate Authority Pinning: Pin the CA certificate. Less restrictive but still more secure than trusting all CAs.

🎯 Recommended Approach for 2025

SPKI (Subject Public Key Info) pinning is the recommended approach. It provides the right balance of security and operational flexibility, allowing certificate renewals without app updates as long as the same key pair is used.

Implementing Certificate Pinning on iOS

iOS Native Implementation

iOS provides built-in support for certificate pinning through URLSession and App Transport Security (ATS):

// Swift Implementation - URLSessionDelegate class PinningDelegate: NSObject, URLSessionDelegate { let pinnedPublicKeyHash = "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { guard let serverTrust = challenge.protectionSpace.serverTrust else { completionHandler(.cancelAuthenticationChallenge, nil) return } // Evaluate server trust let policy = SecPolicyCreateSSL(true, challenge.protectionSpace.host as CFString) SecTrustSetPolicies(serverTrust, policy) var secResult = SecTrustResultType.invalid let status = SecTrustEvaluate(serverTrust, &secResult) guard status == errSecSuccess else { completionHandler(.cancelAuthenticationChallenge, nil) return } // Get server certificate guard let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else { completionHandler(.cancelAuthenticationChallenge, nil) return } // Extract public key let serverPublicKey = SecCertificateCopyKey(serverCertificate) let serverPublicKeyData = SecKeyCopyExternalRepresentation(serverPublicKey!, nil)! as Data // Calculate hash let serverHash = sha256(data: serverPublicKeyData) // Compare with pinned hash if serverHash == pinnedPublicKeyHash { let credential = URLCredential(trust: serverTrust) completionHandler(.useCredential, credential) } else { completionHandler(.cancelAuthenticationChallenge, nil) } } }

Using TrustKit for iOS

TrustKit is a popular open-source library that simplifies certificate pinning on iOS:

// TrustKit Configuration let trustKitConfig = [ kTSKSwizzleNetworkDelegates: false, kTSKPinnedDomains: [ "api.example.com": [ kTSKPublicKeyHashes: [ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=" // Backup pin ], kTSKEnforcePinning: true, kTSKIncludeSubdomains: true ] ] ] as [String: Any] TrustKit.initSharedInstance(withConfiguration: trustKitConfig)

iOS Best Practices

  • Always include backup pins to prevent app lockout during certificate rotation
  • Use SPKI pinning rather than certificate pinning for flexibility
  • Implement proper error handling and fallback mechanisms
  • Test thoroughly with both valid and invalid certificates
  • Consider using certificate transparency for additional validation

Implementing Certificate Pinning on Android

Android Network Security Configuration

Android provides declarative certificate pinning through Network Security Configuration:

api.example.com AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=

Android Programmatic Implementation

For more control, implement pinning programmatically using OkHttp:

// Kotlin Implementation with OkHttp val certificatePinner = CertificatePinner.Builder() .add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") .add("api.example.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=") .build() val client = OkHttpClient.Builder() .certificatePinner(certificatePinner) .build() // Make request val request = Request.Builder() .url("https://api.example.com/data") .build() client.newCall(request).execute()

Android Best Practices

  • Use Network Security Configuration for declarative pinning when possible
  • Set appropriate expiration dates for pin sets
  • Include multiple backup pins for certificate rotation
  • Test on different Android versions and devices
  • Implement certificate transparency validation

Certificate Rotation and Backup Pins

The Backup Pin Strategy

Always include backup pins to prevent application lockout during certificate rotation:

  • Primary Pin: Current certificate's public key hash
  • Backup Pin 1: Next certificate's public key hash (pre-generated key pair)
  • Backup Pin 2: CA certificate public key hash or another backup key

⚠️ Critical Warning

Never deploy an app with only a single pin. If that certificate needs to be revoked or rotated unexpectedly, all app instances will be locked out with no recovery option except releasing a new app version.

Certificate Rotation Process

Follow this process for smooth certificate rotation:

  1. Pre-generate Keys: Generate the next certificate's key pair before current certificate expires
  2. Add Backup Pin: Include the new certificate's public key hash as a backup pin in the app
  3. Deploy App Update: Release app version with both current and new pins
  4. Wait for Adoption: Allow sufficient time for users to update (typically 3-6 months)
  5. Rotate Certificate: Deploy new certificate on servers
  6. Monitor: Watch for pinning failures and user reports
  7. Remove Old Pin: In next app version, remove the old pin and add next backup pin

Calculating Public Key Hashes

Generate SPKI hashes for pinning:

# Extract public key from certificate openssl x509 -in certificate.pem -pubkey -noout > pubkey.pem # Calculate SHA-256 hash of SPKI openssl pkey -pubin -in pubkey.pem -outform der | openssl dgst -sha256 -binary | openssl enc -base64 # Output: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=

Testing and Validation

Testing Strategies

Comprehensive testing is essential for certificate pinning:

  • Valid Certificate Test: Verify app works with correctly pinned certificate
  • Invalid Certificate Test: Confirm app rejects certificates with wrong pins
  • Expired Certificate Test: Test behavior with expired certificates
  • Self-Signed Certificate Test: Verify rejection of self-signed certificates
  • MITM Proxy Test: Use tools like Charles Proxy or mitmproxy to simulate attacks
  • Certificate Rotation Test: Validate smooth transition during certificate updates

Testing Tools

  • Charles Proxy: SSL proxy for testing MITM scenarios
  • mitmproxy: Open-source SSL proxy for automated testing
  • Burp Suite: Security testing tool with SSL interception
  • Frida: Dynamic instrumentation for testing pinning implementation

Monitoring in Production

Implement monitoring to detect pinning issues:

  • Log pinning failures with error details
  • Track pinning failure rates and trends
  • Alert on sudden increases in pinning failures
  • Monitor certificate expiration dates
  • Track app version distribution for rotation planning

Common Pitfalls and Solutions

Pitfall 1: Single Pin Deployment

Problem: Deploying with only one pin creates risk of app lockout.

Solution: Always include at least two backup pins. Pre-generate key pairs for future certificates.

Pitfall 2: Pinning Leaf Certificates

Problem: Pinning entire certificates requires app updates for every renewal.

Solution: Use public key pinning (SPKI) instead, allowing certificate renewal with same key pair.

Pitfall 3: Insufficient Testing

Problem: Inadequate testing leads to production issues.

Solution: Implement comprehensive test suite covering all scenarios including MITM attacks.

Pitfall 4: No Rotation Plan

Problem: Lack of certificate rotation strategy causes emergency situations.

Solution: Develop and document certificate rotation procedures. Schedule rotations well in advance.

Pitfall 5: Ignoring Certificate Transparency

Problem: Missing additional validation opportunities.

Solution: Implement certificate transparency validation alongside pinning for defense in depth.

Advanced Considerations

Dynamic Pinning

For advanced use cases, consider dynamic pin updates:

  • Fetch updated pins from secure API endpoint
  • Implement secure pin update mechanism with signature verification
  • Use as fallback for emergency certificate rotation
  • Requires careful security design to prevent attacks

Certificate Transparency Integration

Enhance security by validating certificates against CT logs:

  • Verify certificates are logged in public CT logs
  • Detect mis-issued certificates quickly
  • Combine with pinning for comprehensive validation
  • Use libraries like TrustKit that support CT validation

Compliance Considerations

Certificate pinning may be required by:

  • Financial services regulations (PSD2, PCI DSS)
  • Healthcare compliance (HIPAA)
  • Government security standards
  • Industry-specific security requirements

Conclusion

SSL certificate pinning is a powerful security technique that significantly reduces the risk of man-in-the-middle attacks in mobile applications. When implemented correctly with proper backup pins, rotation procedures, and comprehensive testing, certificate pinning provides an essential additional layer of security for applications handling sensitive data.

The key to successful certificate pinning lies in careful planning, thorough testing, and operational discipline. Always include backup pins, develop clear rotation procedures, and monitor pinning behavior in production. With these practices in place, certificate pinning becomes a manageable and highly effective security control.

As mobile security threats continue to evolve in 2025, certificate pinning remains a critical defense mechanism for protecting user data and maintaining trust in mobile applications.

🔧 SSL Pinning Tools

Use our tools to help with certificate pinning: