Creating and using self-signed SSL certs in iOS applications

If you find yourself having to use an SSL certificate – and even more specifically, a self-signed SSL certificate – in an app you’re developing, then this article is for you! (If you don’t know what this means, then I guess it’s not for you, but if you do make apps for a living, I’d suggest bookmarking it anyway, as you probably will need this information some day).

By the end of this article, you should be able to:

  • Create a public/private key and use it to sign your own SSL Certificate

  • Install the correct files in your local Apache server (I use OS X’s stock Apache, along with the VirtualHostX utility to help manage the system easily).

  • Convert and import the correct files into your iOS app to ensure it can talk to the same server.

  • Get on with your life.

There are people whose business it is to know and remember all of this, and then there are people like me: independent software developers whose job it is to know it THIS WEEK … and maybe again in 10 or 12 years when another client happens to need it again. In writing this up, I wanted to make sure I covered the whole process, so the next poor sap (whether that’s you or my future self) can get past this mess quickly and get back to actually developing apps again (For the past few days, it’s all I’ve done morning to midnight – trying to make an app talk to the %*@$!^# development server just so I could test a new API I’ve been wanting to try. Here’s hoping this writeup prevents you from doing the same).

The Big Picture

To begin, I’ll start with just enough overview to let you know what you’re going to be doing, and why. For all I know, I’ve got it all wrong in theory, but here’s the idea in a nutshell:

Basically, a successful SSL handshake requires of three things: Two copies of the same signed certificate (one for the Web server, and one for your client app – though perhaps not both in the same format) and a single private key that can “unlock” them both. The Web server holds both a copy of the certificate and the key, while the iOS app (the client) holds just the certificate. Here’s what happens:

  • When your app makes a request, the client (i.e., your app) and the server compare each other’s certificate to their own.

    • If they do not match, game over.

    • If they do match, however, we’re not finished…

  • The Web server also checks to make sure this is the same certificate that includes the public version of its own key, too.

    • If it does not match, game over.

    • If it does, though…

  • You are clear to access this SSL-enabled web site via your iOS app. Woohoo!

Again, the Web server holds both the private key and one copy of the certificate, while the client holds only a copy of the certificate.

Part I: Generate all the keys and certificates

Step 1

Create a PUBLIC/PRIVATE key pair (which you’ll often see referred to simply as the PRIVATE KEY, but note that it does in fact contain all the information needed to produce the PUBLIC KEY, too). Fortunately, OS X comes with the openSSL toolkit, which contains all you need to do this:

Open (or whatever application you prefer to interact with OS X’s underlying UNIX layer), and type the following (you may skip lines beginning with a pound (#) sign, as these are just comments for your own information):

Note Depending on your user permissions, you may (probably will) need to prepend each command below with sudo

# Change to the apache root directory (following is for plain-vanilla OS X Lion. Your mileage may vary with MAMP, etc. )
cd /private/etc/apache2/

# This creates a password-encrypted public/private key pair and stores it in a PEM-format file named privatekey.pem
openssl genrsa -des3 -out privatekey.pem 1024

You will get a series of prompts to which there really is no wrong answer, since this is for your own use anyway. Answer them as truthfully as you like.

Step 2

Now that you have the private key, you need a certificate signed with it. In production environments, you would probably get this by applying to a Certificate Authority (CA), but in this case (for a self-signed certificate), you’ll be able to accept the application yourself (In essence, you are now the Certificate Authority giving yourself the OK to trust you. I hope you’re sure about yourself). Even so, you still need to fill out the application, which in this case is called a Certificate Signing Request (CSR) and is used to provide a little more information about yourself. (OK, so actually, for a self-signed certificate, this step can be skipped, but doing so is not recommended, and I won’t bother showing how to create a “requestless” certificate. See the link to below, if you must know.) To generate the CSR:

# This will prompt you for more information and create a CSR in a file name signingrequest.csr.
# You will need the password you used to create the private key above
openssl req -new -key privatekey.pem -out signingrequest.csr

Step 3

Now that you have both your private key and the signing request, you can generate your own certificate. Note that the resulting certificate is signed with your private key but contains only a copy of your PUBLIC KEY hidden within it. This is the thing that will be distributed within your application bundle

# This uses the private key and the signing request to generate an SSL certificate for use on your Web server.
# Use the same password you used for your private key above.
openssl x509 -req -days 365 -in signingrequest.csr -signkey privatekey.pem -out selfsignedcertificate.crt

Step 4

Chances are you do not wish to enter your password each time Apache restarts, so you should create a version of your private key file without it. This is the key you will tell Apache to use later.

#This generates yet another file, `privatekey.nopassword.pem`
openssl rsa -in privatekey.pem -out privatekey.nopassword.pem

Step 5

Although we will not use it in this example, you can also generate a public key from the key file. Note that this is NOT necessary (remember, your signed certificate already contains this public key!), and I include it here just for reference later, if you (or I) need it.

#This generates the public key file
openssl rsa -in privatekey.pem -pubout > mypublickey.pem

Step 6

And now the magic sauce that is seldom mentioned when discussing SSL certificates on iOS: The certificate you generated above is absolutely worthless inside your iOS project – so far. The selfsignedcertificate.crt file you made above is in a format called PEM, or Privacy-Enhanced Mail, which is Base64 encoded (If you take a look at it in a text editor, you’ll see it is simply a string of characters beginning and ending with the lines -----BEGIN CERTIFICATE----- and -----END CERTIFICATE-----, respectively). Your iOS project cannot use this text file, however, and must include a binary format known as the DER, or Distinguished Encoding Rules, format. Converting it via openssl is simple enough, however:

# This reads in the base64-encoded selfsignedcertificate.crt file and outputs the binary selfsignedcertificate.der version
openssl x509 -in selfsignedcertificate.crt -inform PEM -out selfsignedcertificate.der -outform DER

You are now ready to set up your server and app to use the certificates you just generated.

Part II: Add both certificate and private key to Web Server

1 Edit Apache config to support SSL (in Lion, this is found at /private/etc/apache2/httpd.conf ). To do so, edit the file and uncomment (by removing the preceding #) or add the line beginning with Include below:

# Secure (SSL/TLS) connections
Include /private/etc/apache2/extra/httpd-ssl.conf

2 If using VirtualHostX, back up your current configuration and then add the custom directives to the virtual host you want to use and ensure that the host is set to listen on port 443:

SSLEngine on
SSLCertificateFile /private/etc/apache2/selfsignedcertificate.crt
SSLCertificateKeyFile /private/etc/apache2/privatekey.pem

3 Restart Apache. You can do this using VirtualHostX, or by turning “Web sharing” off and on again in System Preferences>Sharing. Or by entering the following line in Terminal:

sudo apachectl restart

If Apache has trouble restarting, check your error logs (Google it if you need to), and make sure you did not make any typos in the items above. You can now test the installation by pointing your browser to your https URL. You may get a browser warning saying the certificate was not signed by a trusted authority, but as long as you’re willing to trust yourself, all is well. If the URL fails entirely, though, recheck your Apache configuration work above.

Part III: Include your certificate within your Xcode project

I assume if you’re trying to figure out how to include certificates within an iOS app, then you probably already know how to add any other file to the resources of your application bundle… but just in case: The easiest way is to drag the file from the Finder into your Project navigator, and then choose to Copy items into destination group’s folder (if needed) and select the target to which you wish to add the certificate (This is important, as otherwise you will need to manually add the file to the Copy Bundle Resources section of your target’s Build Phases panel later).

You can also use File > Add Files to project… to do the same.

And you’re done!

Both the server and your app now have matching copies of your signed SSL Certificate, which includes both the identity information you included in your CSR, and your public key. The server also contains a copy of your private key with which to verify the certificates. Between the two of them, you’ll find they now have all they need to communicate across a secure SSL channel.

Of course, actually making URL requests with Objective-C is a whole different topic, but this should at least open the channels of communication to get you started. Now that you have all the pieces in place, you can start making the requests you need (perhaps following Wings of Hermes’ SSL-based NSURLConnection How-To to get you going).

Special thanks go to the following:

  • Yellow Robot Studios for explaining how to use openssl to create the certificates and keys needed (and integrating them with the excellent VirtualHostX utility).

  • GregS, Raam and c2h2 at StackOverflow for helping me get my head around the differences between public and private keys (and why I never seemed to need both).

  • Richard Levitte of for an excellent primer on how, why and when to self-sign SSL certificates.

  • rduke15 at for opening the heavens to reveal the magic (and necessity) of DER-encoding when dealing with iOS and SSL certificates.

  • SSLShopper has a handy list of commands to convert various SSL certificate formats from one to another. This was only useful once I’d grasped the concepts above, of course.

  • Wings of Hermes’ write-up on how to actually handle the certificate authentication within your iOS (or OS X) code.

blog comments powered by Disqus