79247877

Date: 2024-12-03 13:57:00
Score: 1.5
Natty:
Report link

For you first point i.e. How to generate SHA256 hex string from PEM file

Method 1:

Get public key via terminal command-

Step 1: If you have the pem file with you please use the below openSSL command to get the public key.

openssl rsa -in inputPemFile.pem -pubout -out outputPublicKey.pem

Here, please do make sure your PEM file is in correct format which contains the private key.

Step 2: Now, use below command to extract/read the public key from outputPublicKey.pem file

cat public_key.pem

Method 2:

Direct method

Step 1: Open Qualys SSL Labs

Step 2: Enter your domain hostname from which you want to extract the public key e.g. https://www.google.com/ and press submit button Hostname reference image

Step 3: In the next screen you will get your SHA256 public key, see reference image below sha256 key reference image

==========================================================================

For you second point i.e. Implement root certificate public key pinning?

Now, if you are using url session then use URL session delegate method i.e. // User defined variables

private let rsa2048Asn1Header:[UInt8] = [
    0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
    0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00
]

private let yourPublicKey: "Your Public Key"

// MARK: URL session delegate:

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    // your code logic
}

Find below the logic which I basically used:

    //MARK:- SSL Pinning with URL Session
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    
    var res = SecTrustResultType.invalid
    guard
        challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
        let serverTrust = challenge.protectionSpace.serverTrust,
        SecTrustEvaluate(serverTrust, &res) == errSecSuccess,
        let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
        completionHandler(.cancelAuthenticationChallenge, nil)
        return
    }
    
    if #available(iOS 12.0, *) {
        if let serverPublicKey = SecCertificateCopyKey(serverCert), let serverPublicKeyData = SecKeyCopyExternalRepresentation(serverPublicKey, nil) {
            
            let data: Data = serverPublicKeyData as Data
            let serverHashKey = sha256(data: data)
            print(serverHashKey, serverHashKey.toSHA256())
            //comparing server and local hash keys
            if serverHashKey.toSHA256() == yourPublicKey {
                print("Public Key pinning is successfull")
                completionHandler(.useCredential, URLCredential(trust: serverTrust))
            } else {
                print("Public Key pinning is failed")
                completionHandler(.cancelAuthenticationChallenge, nil)
            }
        }
    } else {
        // Fallback on earlier versions
        if let serverPublicKey = SecCertificateCopyPublicKey(serverCert), let serverPublicKeyData = SecKeyCopyExternalRepresentation(serverPublicKey, nil) {
            
            let data: Data = serverPublicKeyData as Data
            let serverHashKey = sha256(data: data)
            print(serverHashKey, serverHashKey.toSHA256())
            //comparing server and local hash keys
            if serverHashKey.toSHA256() == yourPublicKey {
                print("Public Key pinning is successfull")
                completionHandler(.useCredential, URLCredential(trust: serverTrust))
            } else {
                print("Public Key pinning is failed.")
                completionHandler(.cancelAuthenticationChallenge, nil)
            }
        }
    }
}

Helper function to convert server certificate to SHA256

private func sha256(data : Data) -> String {
    var keyWithHeader = Data(rsa2048Asn1Header)
    keyWithHeader.append(data)
    var hash = [UInt8](repeating: 0,  count: Int(CC_SHA256_DIGEST_LENGTH))
    
    keyWithHeader.withUnsafeBytes {
        _ = CC_SHA256($0.baseAddress, CC_LONG(keyWithHeader.count), &hash)
    }
    return Data(hash).base64EncodedString()
}

If you are using Alamofire, then pass the domain path in the evaluators data in your alamofire session like below

    let evaluators: [String: ServerTrustEvaluating] = [
    "your.domain.com": PublicKeysTrustEvaluator(
        performDefaultValidation: false,
        validateHost: false
    )
]
let serverTrustManager = ServerTrustManager(evaluators: evaluators)
let session = Session(serverTrustManager: serverTrustManager)

Now use this session while calling your alamofire network request.

Hope, I will be able to help you here.

Thanks and regards.

Reasons:
  • Blacklisted phrase (0.5): Thanks
  • Blacklisted phrase (1): regards
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
  • Filler text (0.5): ==========================================================================
  • Low reputation (0.5):
Posted by: Satish Thakur