iOS Certificate Pinning with Swift and Nsurlsession

iOS certificate pinning with Swift and NSURLSession

Swift 3+ Update:

Just define a delegate class for NSURLSessionDelegate and implement the didReceiveChallenge function (this code is adapted from the objective-c OWASP example):

class NSURLSessionPinningDelegate: NSObject, URLSessionDelegate {

func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Swift.Void) {

// Adapted from OWASP https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#iOS

if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
if let serverTrust = challenge.protectionSpace.serverTrust {
let isServerTrusted = SecTrustEvaluateWithError(serverTrust, nil)

if(isServerTrusted) {
if let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) {
let serverCertificateData = SecCertificateCopyData(serverCertificate)
let data = CFDataGetBytePtr(serverCertificateData);
let size = CFDataGetLength(serverCertificateData);
let cert1 = NSData(bytes: data, length: size)
let file_der = Bundle.main.path(forResource: "certificateFile", ofType: "der")

if let file = file_der {
if let cert2 = NSData(contentsOfFile: file) {
if cert1.isEqual(to: cert2 as Data) {
completionHandler(URLSession.AuthChallengeDisposition.useCredential, URLCredential(trust:serverTrust))
return
}
}
}
}
}
}
}

// Pinning failed
completionHandler(URLSession.AuthChallengeDisposition.cancelAuthenticationChallenge, nil)
}

}

(you can find a Gist for Swift 2 here - from the initial answer)

Then create the .der file for your website using openssl

openssl s_client -connect my-https-website.com:443 -showcerts < /dev/null | openssl x509 -outform DER > my-https-website.der

and add it to the xcode project. Double check that it's present in the Build phases tab, inside the Copy Bundle Resources list. Otherwise drag and drop it inside this list.

Finally use it in your code to make URL requests:

if let url = NSURL(string: "https://my-https-website.com") {

let session = URLSession(
configuration: URLSessionConfiguration.ephemeral,
delegate: NSURLSessionPinningDelegate(),
delegateQueue: nil)

let task = session.dataTask(with: url as URL, completionHandler: { (data, response, error) -> Void in
if error != nil {
print("error: \(error!.localizedDescription): \(error!)")
} else if data != nil {
if let str = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) {
print("Received data:\n\(str)")
} else {
print("Unable to convert data to text")
}
}
})

task.resume()
} else {
print("Unable to create NSURL")
}

Public Key pinning with NSURLSession

You can have a look at https://github.com/datatheorem/TrustKit . It's an iOS library that makes it easy to do public key pinning, and it works with NSURLSession.

SSL pinning not working (Objective-C, using NSURLSession)

  • I figured out the issue .

    • You must always download ssl certificate when you are out of your local office network or wifi . Because if you download your
      certificate within vpn / office LAN / office wifi , your certificate
      will be tempered / overwritten .
    • Thus when you will pin the certificate which you downloaded in your secure private office network then , then it will never match
      the remote certificate as remote certificate is always public.

      Therefore , download the certificate from open wifi or your own data plan :) and then pin this certificate in your code and i am sure
      then it will match the remote certificate.

Public Key Pinning in Swift 2

The following code might be helpful: link

 import UIKit
import Foundation
class ViewController: UIViewController, NSURLSessionDelegate {

override func viewDidLoad() {
super.viewDidLoad()
httpGet(NSMutableURLRequest(URL: NSURL(string: "https://example.com")!))
}

func httpGet(request: NSMutableURLRequest!) {

let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in

}).resume()
}

func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}

}

Alamofire, ssl pinning on subdomain address

class WildcardServerTrustPolicyManager: ServerTrustManager {
override func serverTrustEvaluator(forHost host: String) throws -> ServerTrustEvaluating? {
if let policy = evaluators[host] {
return policy
}
var domainComponents = host.split(separator: ".")
if domainComponents.count > 2 {
domainComponents[0] = "*"
let wildcardHost = domainComponents.joined(separator: ".")
return evaluators[wildcardHost]
}
return nil
}
}

Implementation:

 let evaluators: [String: ServerTrustEvaluating] = [
"*.airmacau.com.mo": evaluator
]

let manager = WildcardServerTrustPolicyManager(evaluators: evaluators)

Session Manager Config:

sessionManager = Session(configuration: URLSessionConfiguration.default, delegate: SessionDelegate(), serverTrustManager: manager)

How do I accept a self-signed SSL certificate using iOS 7's NSURLSession and its family of delegate methods for development purposes?

This works for me:

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:Nil];
...
...
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler{
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){
if([challenge.protectionSpace.host isEqualToString:@"mydomain.example"]){
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
}
}
}


Related Topics



Leave a reply



Submit