5

I want to prevent my app/server communication from a MITM attack so I am trying to setup SSL pinning, but I am having problems getting it working with AFNetworking 2.2, using a self-signed certificate. I think it's mostly a problem with how I am generating the certificate.

I first tried generating a self-signed certificate according to these instructions:

Generating the private key:

sudo openssl genrsa -des3 -out server.key 2048

Generating the Signing Request, and using the domain name when asked for the Common Name:

sudo openssl req -new -key server.key -out server.csr

Generating the certificate:

sudo openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Finally, converting it to der format (since AFNetworking requires it)

sudo openssl x509 -outform der -in server.crt -out server.der

The server is Ubuntu 12.04, running ngninx+passenger to serve up a Rails 4 app. Here is the bit of my nginx server config to turn on SSL:

server {
  listen 80;
  listen 443;
  server_name myapp.com;
  passenger_enabled on;
  root /var/www/myapp/current/public;
  rails_env production;
  ssl on;
  ssl_certificate /etc/nginx/ssl/server.crt;
  ssl_certificate_key /etc/nginx/ssl/server.key;
}

After restarting nginx, downloading the der file, adding it to my project, and renaming it "server.cer" (since AFNetworking requires the certificate to use the .cer extension), I use this code to turn on SSL pinning for my AFHTTPSessionManager subclass:

client.securityPolicy = [AFSecurityPolicy 
                          policyWithPinningMode:AFSSLPinningModeCertificate];

Then, with the first request to the server AFNetworking attempts to verify that the "trust is valid in the AFServerTrustIsValid function:

static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) {
    SecTrustResultType result = 0;

    OSStatus status = SecTrustEvaluate(serverTrust, &result);
    NSCAssert(status == errSecSuccess, @"SecTrustEvaluate error: %ld", (long int)status);

    return (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed);
}

If I put a breakpoint at the return, I can see that the result is always kSecTrustResultRecoverableTrustFailure.

If I skip the AFServerTrustIsValid function by setting allowInvalidCertificates to YES on the security policy, then the request succeeds. But I don't really want to allow invalid certificates if I don't have to.

Back to the drawing board, this SO question lead me to this tutorial on creating a self-signed cert with also creating a CA. I setup my openssl.cnf file like so:

[ req ]
default_md = sha1
distinguished_name = req_distinguished_name

[ req_distinguished_name ]
countryName = United Kingdon
countryName_default = UK
countryName_min = 2
countryName_max = 2
localityName = Locality
localityName_default = London
organizationName = Organization
organizationName_default = Eric Organization
commonName = Common Name
commonName_max = 64

[ certauth ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:true
crlDistributionPoints = @crl

[ server ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
nsCertType = server
subjectAltName = DNS:myapp.com
crlDistributionPoints = @crl

[ crl ]
URI=http://testca.local/ca.crl

And then used these commands to generate everything. First the CA stuff:

sudo openssl req -config ./openssl.cnf -newkey rsa:2048 -nodes -keyform PEM -keyout ca.key -x509 -days 3650 -extensions certauth -outform PEM -out ca.cer

Then again the server's private key:

sudo openssl genrsa -out server.key 2048

The signing request:

sudo openssl req -config ./openssl.cnf -new -key server.key -out server.req

The certificate:

sudo openssl x509 -req -in server.req -CA ca.cer -CAkey ca.key -set_serial 100 -extfile openssl.cnf -extensions server -days 365 -outform PEM -out server.cer

And finally the der file:

sudo openssl x509 -outform der -in server.cer -out stopcastapp.com.der

When I update and restart nginx,, download and add the server.der to my project (making sure to rename it to server.cer and to reset the Simulator), I get the same exact result.

The dreaded kSecTrustResultRecoverableTrustFailure rears its ugly head again.

What am I doing wrong? Am I like WAY off on how this all works, or do I need to tweak just one little thing to get it all working? If you could help in any way I would really, really appreciate it (I've been on this problem for two days now). Thanks!

Community
  • 1
  • 1
Eric Allam
  • 197
  • 3
  • 11
  • For now I got this to work using Keychain Assistant on Mac OS X and by overriding how AFNetworking 2.2 does pinning for self-signed certificates. [I wrote about it here](http://initwithfunk.com/blog/2014/03/12/afnetworking-ssl-pinning-with-self-signed-certificates/). Note that certificate pinning in AFNetworking for self-signed certs is going to be fixed pretty soon. I'll update this post when it does. – Eric Allam Mar 14 '14 at 17:18
  • 1
    is it Afnetworking issue? Any luck? – Almas Adilbek May 03 '14 at 10:35
  • Any news on this? – Jonny Nov 08 '18 at 09:08

1 Answers1

-2

Somewhere in your code you need to specify this, or something similar. You need to tell the code to accept invalid certificates (AKA self signed).

self.allowsInvalidSSLCertificate = YES;
Marcel Gruber
  • 6,668
  • 6
  • 34
  • 60