AFNetworking: secure handshake no longer works after certificate renewal - ios

My app uses AFNetworking.
What type of certificate extension does AFNetworking look for?
I was given a .crt file by GeoTrust but I have read here that AFNetworking specifically looks for .cer files.
I ask because my https in a browser works fine with my new certificate chain, and using a tool called SSLDetective I can see that the whole chain is trusted, but for some reason my app no longer accepts the bundle for a trusted handshake. Any other time I had issues, SSLDetective showed me that a part of the chain was not trusted. In this case, I can't seem to find anything wrong. Not much changed in my ssl certificate configuration other than overwriting the old key and crt files with the new files with the exact same name. Help is appreciated. Thanks!
EDIT:
I now know for sure that AFNetworking does use and automatically detects .cer files in the app bundle. I also know that the certificate attached in the bundle must match the same public key as the certificate on my web server. With public key pinning, AFNetworking simply extracts the public key from the local certificate and compares it to the one on the server. If the one on the server matches, it uses the server's certificate.
In my case, in the beginning, the keys did not match, but now I made sure that they do. The chain is still trusted and good according to SSLDetective. I downloaded a .cer version of the certificate from the server using SSLDetective and attached it to my app bundle. However, now that I know for sure the public keys match as well, I still can't seem to get a secure handshake. This question is somewhat related to the question asked here.

Related

iOS - how do I get server certificate into iOS client keychain for pinning

TL;DR version: Is there any way to pass a Server certificate to an iOS client that doesn't involve also passing along the Server's private key?
I have written an iOS client app that communicates with my macOS server app (so I have control over both ends). I have implemented certificate pinning using a self-signed certificate to make things more secure. To accomplish this during development, I hardcoded the Server cert into the iOS client app and told the client to only connect to a server that gives you that exact cert during the TLS handshake. Everything is working great.
However in the real world I am selling this system as a set (1 Server, multiple clients to each customer), so I cannot hardcode a Server cert into the iOS client. My plan is to instead deliver the Server cert out of band (via email) to the iOS client like mentioned here: Making Certificates and Keys Available To Your App:
Apps can only access keychain items in their own keychain access groups.
To use digital identities in your own apps, you will need to write code to import them. This typically means reading in a PKCS#12-formatted blob and then importing the contents of the blob into the app's keychain using the function SecPKCS12Import
One way to provision an identity is via email. When you provision a device, send the associated user an email with their client identity attached as a PKCS#12 file.
My problem is that a .p12 file contains the certificate and the private key of the server - this seems very wrong to pass the private key along as well.
Is there any other way to pass the Server certificate to the iOS client that doesn't involve also passing along the Server's private key?
Thanks!!!
I was overthinking things here, the solution is actually pretty simple.
I just needed to email the Server's public certificate out of band to the client device with a custom extension like cert.myCustomExt1234. This is because the .crt extension is already claimed by iOS so you have to register your app to handle custom extensions (see apple docs here). Then in my app I can do all the logic of cert pinning using that out of band delivered Server public cert.
The key was changing the file extension to something not already claimed by iOS.

Difference between SSL pinning and certificate validating

Can someone explain the difference between validating a certificate like described with a self-signed certificate here:
https://jetforme.org/2013/05/validating-a-self-signed-ssl-certificate-in-ios-and-os-x-against-a-changing-host-name/
and SSL pinning like described here:
https://infinum.co/the-capsized-eight/how-to-make-your-ios-apps-more-secure-with-ssl-pinning
What does SecPolicyCreateSSL means?
What in detail is SecTrustEvaluate doing?
Is the procedure in the first link including SSL pinning?
If not, is it a good idea to implement both?
Thanks
First let's clarify the terminology in the Cocoa world:
A SecPolicyRef is a policy that defines the rules when validating a certificate chain: the things to check for in the certificates within the chain (signature, expiration date, etc.), which determine whether the certificate chain is valid/trusted or not.
A SecTrustRef object is the combination of a certificate chain (basically an array of SecCertificateRef) and a SecPolicyRef. This object represents all the things needed to validate a certificate chain (the certificates + the policy).
Validating a server's certificate chain involves two steps:
The certificate path needs to be validated (the signatures, the expiration date, etc.) to ensure that the server certificate was issued by a trusted CA.
The name for which the server certificate was issued (Common Name or Subject Alternative Name) needs to match the name of the server the App is trying to connect to.
These steps are expressed by a SecPolicyRef:
SecPolicyCreateBasicX509() returns a policy that has all the things to check for 1; this is there for historical reasons but it should never be used.
SecPolicyCreateSSL() returns a policy that has all the rules for both 1 and 2; this is the one you must use.
You then use SecTrustEvaluate() to validate the server's SecTrustRef. The result will tell you if the server's certificate chain is trusted based on the SecPolicyRef that was passed.
Lastly, SSL pinning means adding a third step to this whole process:
The certificate chain must contain a specific key or certificate. This ensures that only the certificate you know you deployed on your servers will be accepted by the App, instead of any certificate issued by any CA for your domain.
I would advise against writing your own implementation of SSL validation (with or without pinning) as, you can tell, the APIs are extremely complex and there is a big potential for huge mistakes that would make your extremely App insecure.
I have worked on a library to make it easy to do SSL pinning; it's available at https://github.com/datatheorem/TrustKit and takes care of all the heavy lifting.

Retrieve Client ios app certificate

I want to proxy traffic from an ios application to Fiddler (or Burp). It looks like the application sends a client certificate to the server.
I will need to retrieve this cert from the phone(it's jailbroken) and import it to my proxy. Is there a way to do that ?
The client certificate is used to identify the client. If the programmer of the app made his job well, you will face difficulties (hopefully). Likely, and most secure, the private key and identity resides in the key-chain. Less secure, it resides in a secured archive (.p12, .pkcs12, .pfx) in the bundle, whose password resides in the key-chain.
If the programmer did his job not so well, you might find the password of the secured archive in the clear somewhere in the apps binary (there're actually floating samples around which do exactly this).

How to compare SSL certificates using AFNetworking

In my iPhone app I'm using an https connection with a self-signed SSL certificate to download sensible data (username and password) from a server.
This app is for private use only, it is not meant for production.
I'm using AFNetworking to manage the https connection but, since my certificate isn't signed from a CA, in order to make it work I had to add the following to the header of the AFURLConnectionOperation class:
#define _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ 1
But with this my app will allow any certificate.
Is there a way to allow only the certificate from my server maybe bundling it in the app and comparing it with the certificate provided by the server in the https connection?
And if it were possible, would there be any significant advantage in terms of security?
I'm very new to security and I'm kind of confused.
The term you're looking for is SSL Pinning, where the app verifies that a known certificate or public key matches one presented by a remote server.
AFNetworking supports both pinning with certificates or public keys. You'll need to add the certificate(s) or public key(s) to your app's Bundle, and enable the feature by setting either the defaultSSLPinningMode property on AFHttpClient or the SSLPinningMode property on AFURLConnectionOperation.
You can pin using AFSSLPinningModePublicKey or AFSSLPinningModeCertificate. AFSSLPinningModeCertificate means that the server's certificate must exactly match one of those in the bundle.
AFSSLPinningModePublicKey is more liberal and means that the server's certificate must match for any public key in the bundle, or any public key attached to certificates in the bundle.
There's an example of setting the pinning mode in the AppDotNet example.
To expand a bit on David's answer with respect to AFSSLPinningModePublicKey versus AFSSLPinningModeCertificate. Ideally, you would pin the public key and not the certificate. That's because some sites and services, like Google, rotate their certificates every 30 days or so. But they re-certify the same public key.
The certificates are rotated frequently to keep the size of the CRL small for mobile clients. But they re-certify the same public key (rather than creating a new one) to allow for key continuity testing.
Public key pinning is why tools like Certificate Patrol miss the mark. The certificate is expected to change; the public key is not.
Public key pinning is a lot like SSH's StrictHostKeyChecking, if you are familiar with it.
OWASP has a write-up on it too at Certificate and Public Key Pinning.

Adding pem certificate to project

I have a project, where I make a request to a server (https). The server has only a self-signed certificate, so I get an error: 'The certificate for this server is invalid. You might be connecting to a server that is pretending to be ...'. The problem is, that I have no access to the NSURLConnectionDataDelegate, because it is in a framework (I cannot even see the header of the class that implements the protocol).
I have the pem certificate of the server. Is there a way to add it somehow to my project, and the server to be considered safe? For now, I need it to work only in simulator, so if I could add it only to the simulator, that would also be great. Thanks in advance
Better you start to check out the MKNetworkKit. As far as I know support pem. It is released under attribution license, or you can pay it. Here is the link MKNetworkKit

Resources