简体   繁体   中英

AFNetworking 2.2 SSL pinning with self-signed certificate

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!

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM