Certificate pinning and Public key pinning
Tags: swift, apple
Published: 2023-02-28 02:21:03

 ![Certificate pinning and Public key pinning](https://needone.app/content/images/2023/02/certificate-pinning.png)

Certificate pinning and public key pinning are both techniques that are used to enhance the security of a network connection by ensuring that the client trusts only a specific certificate or public key.

## Certificate pinning

Certificate pinning is a security technique that is used to ensure that an app is communicating with the correct server. Certificate pinning works by associating a specific certificate or public key with a server, and checking that the certificate or key is being used when the app communicates with the server.

## Public key pinning

Public key pinning, on the other hand, is a technique in which the client stores the public key of a trusted server and verifies that the public key presented by the server during the SSL/TLS handshake is the same as the stored public key. If the public key presented by the server does not match the stored public key, the connection is terminated.

## Difference between Certificate pinning and Public key pinning

- Both used to prevent man-in-the-middle (MITM) attacks, in which an attacker intercepts the communication between the client and the server and presents a fake certificate or public key in an attempt to impersonate the server.
- Certificate pinning may be more effective in some cases, as it verifies the entire certificate chain and all of its associated trust relationships. Public key pinning, on the other hand, only verifies the public key of the server and does not take into account the trust relationships between the server and other certificate authorities.
- Public key pinning might be more flexible which only required to check the public key which can be static. With certificate pinning, we need to replace certificates in the app every time when renew them.

## Implement certificate pinning

To implement certificate pinning in Swift, you can use the `URLSession` class and the `serverTrustPolicy` property of the `ServerTrustPolicy` enum to configure the trust policy of the session, and the `URLSessionDelegate` protocol and the `urlSession(_:didReceive:completionHandler:)` method to evaluate the server trust. Here is an example of how to do this:

```swift
import Foundation

class PinningDelegate: NSObject, URLSessionDelegate {
    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust {
            let serverTrust = challenge.protectionSpace.serverTrust
            let certificate = SecTrustGetCertificateAtIndex(serverTrust!, 0)

            if let serverCertificateData = SecCertificateCopyData(certificate!) as Data? {
                // Compare the server certificate data with the trusted certificate data
                if serverCertificateData == trustedCertificateData {
                    let credential = URLCredential(trust: serverTrust!)
                    completionHandler(.useCredential, credential)
                    return
                }
            }
        }

        // Cancel the connection if the server certificate is not trusted
        completionHandler(.cancelAuthenticationChallenge, nil)
    }
}

let delegate = PinningDelegate()

let session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil)
let url = URL(string: "https://www.example.com")!
let task = session.dataTask(with: url) { data, response, error in
    // Handle the response here
}
task.resume()

```

In this example, the `PinningDelegate` class is a delegate of the `URLSession` class that implements the `urlSession(_:didReceive:completionHandler:)` method. The method is called when the session receives an authentication challenge from the server, and it is used to evaluate the server trust. The method retrieves the server trust and the server certificate from the challenge, and it compares the server certificate data with the trusted certificate data. If the server certificate is trusted, the method creates a `URLCredential` object with the server trust and returns it to the session, and the session continues the connection. If the server certificate is not trusted, the method cancels the connection and returns `nil`

## Implement public key pinning

To implement certificate pinning in a Swift app, you can use the `ServerTrustPolicyManager` and `ServerTrustPolicy` classes from the Alamofire library. The `ServerTrustPolicyManager` class allows you to specify a set of trusted certificates or public keys, and the `ServerTrustPolicy` class allows you to specify the certificate pinning policy for a particular server.

Here is an example of how to use the `ServerTrustPolicyManager` and `ServerTrustPolicy` classes to pin a certificate in a Swift app:

```swift
import Alamofire

let certificateData = Data(base64Encoded: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")!
let certificate = SecCertificateCreateWithData(nil, certificateData as CFData)!
let trustedCertificates = [certificate]
let serverTrustPolicy = ServerTrustPolicy.pinCertificates(certificates: trustedCertificates, validateCertificateChain: true, validateHost: true)
let serverTrustPolicyManager = ServerTrustPolicyManager(policies: ["example.com": serverTrustPolicy])

AF.Session(serverTrustPolicyManager: serverTrustPolicyManager).request("https://example.com").response { response in
    // Handle the response
}

```

In this example, we use the `SecCertificateCreateWithData` function to create a `SecCertificate` object from the certificate data, and add it to an array of trusted certificates. We then use the `ServerTrustPolicy.pinCertificates` method to create a `ServerTrustPolicy` object that trusts the specified certificates, and validate the certificate chain and host. We then create a `ServerTrustPolicyManager` with the `ServerTrustPolicy` just created.

## Further read

Certificate pinning and Public key pinning in Kotlin.

Ref: https://needone.app/certifate-pinning-public-key-pinning/