Thursday, June 13, 2013

iOS authenticate HTTPS with self-signed certificate

1. Generate self-signed certificate on Mac OS X
  • Open Keychain Access -> Keychain Access menu -> Certificate Assistent -> Create a Certificate
  • Pick a name for the certificate. We will choose "localhost" since the certificate name will be used as the subject of the certificate which is generally the FQDN(eg. www.google.com). Later in the connection:willSendRequestForAuthenticationChallenge: delegate method the code will validate the certificate by matching the site you are visiting against the subject of the received trust.
  • Set the identity type to "Self Signed Root"
  • Select "SSL Server" for the Certificate type
  • Generate the certificate, you will find a certificate named "localhost" in My Certificates section.
  • Draw the certificate to the Desktop, you will get a file called "localhost.cer" which is the public key.
  • Right click on the certificate in Keychain -> export the certificate as .p12 format. You will be asked to enter a protection password for the certificate. Type "123" for the password. After that you will get a "local.p12"file which includes the private key.
  • Open a terminal, go to the directory where your local.p12 resides. Use the command below to convert it to the java keystore format.
keytool -importkeystore -srckeystore localhost.p12 -srcstoretype pkcs12 -srcalias localhost -destkeystore localhost.jks -deststoretype jks -deststorepass 123 -destalias localhost
  • Eventually, You will get a localhost.jks file.
2. Setup https in Tomcat 7
  • Locate your tomcat server setting file which is $CATALINA_BASE/conf/server.xml.
  • Uncomment and modify the https connector to the conf below.

<Connector

           protocol="HTTP/1.1"

           port="8443" maxThreads="200"

           scheme="https" secure="true" SSLEnabled="true"

           keystoreFile="[path to localhost.jks]" keystorePass="123"

           clientAuth="false" sslProtocol="TLS"/>


  • Start your tomcat server.
  • Open a browser type https://localhost:8443, your browser might warn you that the certificate is not trustworthy. Ignore that and visit the page anyway. If you see the home page of the tomcat server, it means your tomcat server is running https with the certificate you created.
3. Authenticate the self-signed certificate in the iOS
  • Create a xcode project.
  • Import the "localhost.cer" certificate to the project. The certificate contains the public key, it will be used to evaluate the received trust inside the NSURLAuthenticationChallenge.
  • Setup a NSURLConnectionDelegate, add the following code to your connection:willSendRequestForAuthenticationChallenge: delegate method. What the code does is creating certificate from the .cer file you just added to the project, set the newly created certificate as the anchor certificate. After that, when your call the SecTrustEvaluate method the certificate u just created will be used to evaluate the trust.

SecTrustRef trust = challenge.protectionSpace.serverTrust;
NSError *error;
NSString *path = [[NSBundle mainBundle] pathForResource:@"localhost" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:path options:0 error:&error];
SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData);
if (certificate == NULL)
    NSLog(@"Failed to create certificate");
CFArrayRef certs = CFArrayCreate(NULL,
                                 (const void**)&certificate,
                                 1,
                                 &kCFTypeArrayCallBacks);
    
SecTrustSetAnchorCertificates(trust, certs);
SecTrustSetAnchorCertificatesOnly(trust, false);
CFRelease(certs);
CFRelease(certificate);

OSStatus status = SecTrustEvaluate(trust, &result);

  • Initiate a NSURLConnection in your code, set the NSURL of the NSURLRequest to https://localhost:8443. 
  • The connection:willSendRequestForAuthenticationChallenge: delegate method will be called by the URL Loading System. The status returned by SecTrustEvaluate(trust, &result) is kSecTrustResultUnspecified which means the certificate is valid and the user did not specify a trust setting. Generally it indicates success. 

No comments:

Post a Comment