I'm trying to add SSL pinning to my app, with a self-signed certificate, but I can't seem to get it to work. I have tried everything I could find on the internet with no success, and not being an expert at how SSL works doesn't help.
I'm using objective-c with the latest version of AFNetworking.
I made a very simple piece of code to test my API calls (I'm using a placeholder URL for this post) :
NSString *url = @"https://api.example.net/webservice";
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"example.net" ofType:@"der"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:url]];
manager.requestSerializer = [AFJSONRequestSerializer new];
manager.responseSerializer = [AFJSONResponseSerializer new];
AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
[policy setAllowInvalidCertificates:YES];
[policy setValidatesDomainName:NO];
policy.pinnedCertificates = [NSSet setWithObject:certData];
manager.securityPolicy = policy;
[manager POST:url parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
NSLog(@"SUCCESS");
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
NSLog(@"FAILURE : %@", error.localizedDescription);
}];
Every time I try executing this code, I get a failure with the following error :
Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “api.example.net” which could put your confidential information at risk."
I tried using different formats for my certificate (.der, .cer, ...), but I still always get the same error.
I tried using NSAllowsArbitraryLoads in my info.plist but nothing changes.
To make sure I'm using working code, I also downloaded the example project from a Ray Wenderlich tutorial, but my own certificate is still invalid (in the tutorial they use the stackexchange certificate, this one works).
I have been researching this issue for days and haven't found a solution yet.
The same certificate works perfectly on our Android app, as well as Postman.
Is this because I use a self-signed certificate and iOS doesn't like it? Is there anything obvious I missed in my code or in my app configuration? Is there something specific to implement server-side to make sure it works with iOS? Do I have to export my certificate in a very specific format?
Any information is welcome.
Thanks!
I'm looking at an old project where I used self signed certificates without a problem. These are just comments that may help - I make them here because I have more space and can format them better.
The
derversion worked.In
Info.plistyou need something like the following.Note your error message - it is complaining about the server certificate, so maybe the problem is in the DNS or server certificate. Both needs to be correct and the name you use e.g.
server1.localmust match the DNS name of the server as well as theCNof the certificate for iOS to work.I added both the CA and the server certificates to the chain in iOS.
I trust this will help you.
FWIW my implementation did not use AFNetworking but I used
SecTrustSetAnchorCertificatesinsideURLSession:didReceiveChallenge:completionHandler:in theNSURLSessionDelegatethat I used to support a normalNSURLRequest.Here is that piece of code.
Here
fhWebSupportDelegate.serverCertificatesreturns an array with the CA as well as the server certificate. Also I was extremely lenient in when I granted trust to the server as can be seen in the code.