We’ve been having a hard time securing our app’s network connections with SSL using AFNetworking 2.5.0.
We use a self-signed certificate authority and implemented a
- (AFSecurityPolicy *)securityPolicy {
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"*.something.co.in" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
[securityPolicy setAllowInvalidCertificates:YES];
[securityPolicy setPinnedCertificates:@[certData]];
[securityPolicy setValidatesDomainName:NO];
[securityPolicy setValidatesCertificateChain:NO];
return securityPolicy;
}
This worked for me for some reason. Still not sure how this changes things because other connections in my app work without taking all these steps.
This is what the error generating security policy looks like -
- (AFSecurityPolicy *)securityPolicy {
NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"*.something.co.in" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:cerPath];
AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
[securityPolicy setAllowInvalidCertificates:NO];
[securityPolicy setPinnedCertificates:@[certData]];
[securityPolicy setValidatesDomainName:YES];
return securityPolicy;
}
Now sticking to the "Don't fix if it ain't broken" rule
Having dealt with a similar issue, it is common for things seem normal via browser HTTPS connections, as many browsers cache certificate files from third parties so that they don't always need to be loaded. Therefore, it could very well be that your certificate chain is not fully trusted as you may have been led to believe.
In other words, it may seem fine to connect securely with a browser, but depending on your AFNetworking settings, your app won't actually accept your certificate chain. After you are sure your settings are appropriate, the next step is to make sure your certificate chain is actually as good as you think it is. Download an app called SSL Detective and query your server. You can also use www.ssldecoder.org. Make sure there are no red (untrusted) items in your chain. If there are, change your cert setup on the server.
Given that your AFNetworking settings are as follows:
[securityPolicy setAllowInvalidCertificates:NO];
[securityPolicy setValidatesCertificateChain:NO];
It may not like your certificate chain because it is self signed. You might also have to switch those to YES.
I tried all of these but nothing helped then I searched for this line
'NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning.");'
and below this line I changed
'return NO;'
to
'return YES;'
and it did the magic.
Thanks.
After reading through the AFNetworking code & and checking the change logs, here's what I had to do to get this working.
Create your AFSecurityPolicy object with AFSSLPinningModeCertificate:
AFSecurityPolicy* policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
By default, AFNetworking will validate the domain name of the certificate. Our certificates are generated on a per-server basis, and not all of them will have a domain name, so we need to disable that:
[policy setValidatesDomainName:NO];
Since the certificates are self-signed, they are technically 'invalid', so we need to allow that as well:
[policy setAllowInvalidCertificates:YES];
Lastly, AFNetworking will attempt to validate the certificate all the way up the certificate chain, which to me seems like it would only go up the chain to OUR CA, but for whatever reason it doesn't, so we have to disable that too:
[policy setValidatesCertificateChain:NO];
And that's it! Set the security policy in your request manager like you're already doing and it should work fine.
So, recap, all you really need to change in the code you posted is this:
A) As David Caunt mentioned, change your pinning mode from AFSSLPinningModeNone
to AFSSLPinningModeCertificate
and
B) Add the line to disable validating the domain name: [policy setValidatesDomainName:NO]
Another note, AFNetworking now automatically checks your bundle for .cer files, so if you were to rename your certificate to have a .cer extension, you can eliminate the code to get the certificate data out of the bundle and set the pinned certificates.
I was getting this error, Error Domain=NSURLErrorDomain Code=-1012 NSErrorFailingURLStringKey
The below change alone got it working for me.
self.validatesDomainName = NO;
If you just want to silence the warning without having a client certificate, the policy should look like this:
AFSecurityPolicy* policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
[policy setValidatesDomainName:YES];
[policy setAllowInvalidCertificates:NO];