If you wish to run local web services, such as CalDAV, CardDAV, WebDAV, websites, etc., you may want to connect over SSL. Here are instructions on how to generate self-signed SSL certificates, on Mac OS X that have the CA flag set to TRUE, and which will be accepted my Android devices (which are particularly fussy about how an SSL certificate is cooked up).

As a give-my-private-data-to-questionable-private-cloud-service-companies non-believer, I run my own cloud and sync services locally. Three very handy services are CalDAV, CardDAV, and WebDAV (for sharing and syncing calendars, contacts, and files, respectively), all of which I can run locally on Mac OS X. This allows me to sync my OmniFocus data locally with Android devices, and to sync my contacts and calendars. The one catch is that I want to do all my syncing over encrypted SSL connections. That should be easy, and yet it’s taken me a great many hours to figure out.

The Challenge

The challenge is that although Mac OS X can generate self-signed SSL certificates fairly easily, it does not include a CA (certificate authority) flag in the certificate. For Android devices this flag needs to exist, and be set to True. After spending countless hours reading over forums where those before me had spent countless hours, and days, trying to generate a CA flagged True SSL certificate, and was about to throw in the towel. I have, however, stumbled upon the solution.

The Solution

1. Install OpenSSL

First off, if you have not already done so, you will need to install OpenSSL. If you have the package manager Homebrew installed, you can install OpenSSL with the following command:

brew install openssl

Otherwise, you’ll need to follow the instructions provided here. Or install Homebrew (it’s very handy), and then use it to install OpenSSL.

To install Homebrew, it’s as simple as running the following command in Terminal:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

2. Set your system up for generating SSL and CA

  • Create a directory in your home folder (or wherever else makes sense to you) called something like SSL. For instance, ~/SSL will do the trick. In Finder just hit ⇧⌘-G, and type in ~/
    That will take you to your home directory. Now create a new folder called something like SSL. In all the following instructions I will assume you create a directory at ~/SSL

In terminal type in: cd ~/ssl

  • In Terminal or in Finder (whichever you’re familiar with) create a text file in that folder and call it ca.cnf

Put the following in that file:

[ ca ]
default_ca = mypersonalca

[ mypersonalca ]
#
# WARNING: if you change that, change the default_keyfile in the [req] section below too
# Where everything is kept
dir = ./mypersonalca

# Where the issued certs are kept
certs = $dir/certs

# Where the issued crl are kept
crl_dir = $dir/crl

# database index file
database = $dir/index.txt

# default place for new certs
new_certs_dir = $dir/certs

#
# The CA certificate
certificate = $dir/certs/ca.pem

# The current serial number
serial = $dir/serial

# The current CRL
crl = $dir/crl/crl.pem

# WARNING: if you change that, change the default_keyfile in the [req] section below too
# The private key
private_key = $dir/private/ca.key

# private random number file
RANDFILE = $dir/private/.rand

# The extentions to add to the cert
x509_extensions = usr_cert

# how long to certify for
default_days = 365

# how long before next CRL
default_crl_days= 30

# which md to use; people in comments indicated to use sha1 here
default_md = sha1

# keep passed DN ordering
preserve = no

# Section names
policy = mypolicy
x509_extensions = certificate_extensions

[ mypolicy ]
# Use the supplied information
commonName = supplied
stateOrProvinceName = supplied
countryName = supplied
emailAddress = supplied
organizationName = supplied
organizationalUnitName = optional

[ certificate_extensions ]
# The signed certificate cannot be used as CA
basicConstraints = CA:false

[ req ]
# same as private_key
default_keyfile = ./mypersonalca/private/ca.key

# Which hash to use
default_md = sha1

# No prompts
prompt = no

# This is for CA
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
string_mask = utf8only
basicConstraints = CA:true
distinguished_name = root_ca_distinguished_name
x509_extensions = root_ca_extensions

[ root_ca_distinguished_name ]
# EDIT THOSE
commonName = My Personal CA
stateOrProvinceName = California
countryName = US
emailAddress = certs@example.com
organizationName = My Personal Certification Authority

[ root_ca_extensions ]
basicConstraints = CA:true
  • You might want to make some changes to this file. For instance you can change the default expiry of your certificates. Look for the parameter default_days = 365 and set that to however many days you want. Also, look for # EDIT THESE near the end of the file, and change those parameters to whatever works for you.
  • You need to set up the directories for your CA system to function within. Issue each of the following commands in Terminal:

mkdir -p mypersonalca/certs
mkdir -p mypersonalca/private
mkdir -p mypersonalca/crl
echo "01" > mypersonalca/serial
touch mypersonalca/index.txt

3. Generate your CA

Use the following command in Terminal:

OPENSSL=ca.cnf openssl req -x509 -nodes -days 3650 \
    -newkey rsa:2048 -out mypersonalca/certs/ca.pem \
    -outform PEM -keyout ./mypersonalca/private/ca.key

You will be asked for some information about the CA organisation. Enter something meaningful.
When that’s done, you should have a couple of new files:  ~/ssl/mypersonalca/certs/ca.pem and ~/ssl/mypersonalca/private/ca.key.

You should keep the ca.key file secret. This is not for public exposure. The ca.pem file is the one that goes public. This is the public certificate for your newly created Certificate Authority (CA). You can import that into your browser, and devices that you want to automatically trust your self-signed SSL certificates. There is, however, an additional step for using in on Android devices. We’ll cover that in a moment.

4. Generate your self-signed SSL certificate

Here we have two steps. First you create the SSL certificate, and next you certify it with your CA.

  • Use the following command to generate your 1024-bit private certificate:
openssl req -newkey rsa:1024 -nodes -sha1 \
   -keyout cert.key -keyform PEM -out cert.req -outform PEM

You will be asked similar questions as those you were asked previously when generation the CA. Use meaningful information, as this is what you, and other people (depending on your usage scenario) will see when asked to trust the certificate.
IMPORTANT: The most important detail you will be asked for is the Common name. This should be the domain name or host identifier you are planning to use this certificate on. Something like, mydomain.com or mymac.local or even localhost (that might work, but I can’t say for sure). You can also use a wild-card, like *.mydomain.com

Now you need to sign your new SSL with your CA. Use the following command:

OPENSSL_CONF=ca.cnf openssl ca -batch -notext -in cert.req -out cert.pem

If you ever need to view the text contents of this file, or make a record of them somewhere, use this command:

openssl x509 -in cert.pem -noout -text

5. Preparing your CA for Android

Android does not import ca.pem files. You need to convert them into a binary file format. To do this, use the following commands:

cd ~/SSL/mypersonalca/certs/
openssl x509 -inform PEM -outform DER -in CA.pem -out CA.crt

If you have your device plugged in and ready for DBA mode transfers, you can use the following command to push the file to your device:

adb push CA.crt /sdcard/

If you have a different path to your device storage, change that command accordingly. Otherwise, in my case I use BitTorrent Sync. So I just drag that CA.crt file into one of the folders that sync to my Android devices, and it automagically makes its way there in a few seconds (assuming BitTorrent Sync is active on each device in that moment).

Once done, you will be able to tell Android to install the CA file via Settings -> Security -> Credential Storage and selecting “Install from storage”, and then follow the prompts.

Image Alt
Image and Android instructions courtesy of Jethro Carr

Importing the CA that is already installed on a server

If you have already installed your SSL on a server, you can fetch it into Android using a neat little app call CADroid

Another option is to browse on your Android web browser to RealmB’s Android Certificate Installer and follow the instructions there. It provides a web page which you can upload the ca.pem file to, and it will install it on your device. I’ve not tried it, but I hear it works well.