#!/Hash/Bang/Wallop

How To Use S/MIME Certificates For Email On Apple Devices

Introduction

A lot of folk use GPG for signing and encrypting emails but GPG is notoriously complex for folk who are not geeks and can often be a pain to use even by seasoned tech folk. On Apple macOS you can use GPG with the standard Mail.app via GPG Suite but note that the Mail integration is paid for and Apple sometimes pull the rug and it takes them a while to get it working again with the latest versions. The 'native' built-in way to sign emails and/or encrypt is via S/MIME certificates, the good thing with this method is the UI will show a cert has been used and it also works with other devices such as iPads and iPhones, with GPG it is impossible to get it working with those devices.

Screenshot of an S/MIME signed email in Apple Mail.app.
Figure 1: An S/MIME signed email in Apple Mail.app

Note that to get a certificate that is trusted you need to buy it the same as any other SSL/TLS certificate, the cost is minimal though, I use SSLTrust for my S/MIME certs and pay £11.03 for a year.

Generate CSR

First create a Certificate Signing Request (CSR), this will be what needs to be submitted to your chosen SSL/TLS vendor.

Rather than using a million openssl argument flags a bunch of stuff can be added to a config file, this makes the command simpler but also makes it easier to do renewals in future. This is what my csr.conf file looks like:

# Config for generating a CSR with openssl for an S/MIME certificate.
# openssl req -newkey rsa:2048 -keyout me_rosstimson_com.key -out me_rosstimson_com.csr -config csr.conf

[req]
prompt = no
distinguished_name = dn
req_extensions = ext

[dn]
C = GB
CN = me@rosstimson.com
emailAddress = me@rosstimson.com

[ext]
subjectAltName = email:me@rosstimson.com
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = emailProtection

To generate the CSR using the config file run the command:

openssl req -newkey rsa:2048 \
        -keyout me_rosstimson_com.key \
        -out me_rosstimson_com.csr \
        -config csr.conf

This will output the CSR to provide to the vendor as well as the secret key.

Note: DigiCert - OpenSSL CSR Wizard is handy for helping create the command needed for generating a CSR if you don't wish to us a config file.

Prepare Bundle For Usage

Once the vendor has created the S/MIME certificate it can be downloaded along with the intermediate and root certificates. We need to bundle them all together along with the private key in PKCS#12 (.p12) format.

I have the following files in my working directory now:

.rw-r--r--@ 5.0k rosstimson staff 29 Apr 21:36 bundled.pem
.rw-rw-r--@ 1.7k rosstimson staff 30 Apr 06:36 me_rosstimson_com.crt
.rw-r--r--@  443 rosstimson staff 25 Apr 21:32 csr.conf
.rw-rw-r--@ 2.0k rosstimson staff 30 Apr 06:36 intermediate-0.crt
.rw-r--r--@ 1.1k rosstimson staff 25 Apr 21:14 me_rosstimson_com.csr
.rw-------@ 1.9k rosstimson staff 25 Apr 21:14 me_rosstimson_com.key
.rw-rw-r--@ 1.3k rosstimson staff 30 Apr 06:36 root-certificate.crt

The me_rosstimson_com.crt is the issued certificate. To create the bundle ready for usage with Apple devices use the following command:

/usr/bin/openssl pkcs12 -export -out me_rosstimson_com_bundle.p12 \
                 -inkey me_rosstimson_com.key \
                 -in me_rosstimson_com.crt \
                 -certfile intermediate-0.crt \
                 -certfile root-certificate.crt \
                 -passout pass:"SOME_SECRET"
Enter pass phrase for me_rosstimson_com.key:

The command will prompt for the passphrase used when the private key was created during CSR generation. The command would normally ask for a password for the outputted .p12 bundle too but here the -passout argument is used as when cut 'n' pasting from my password manager I was getting the error Can't read Password, so rather than painstakingly typing out a long password it is supplied with the command; weirdly the private key password can be read when pasted in.

Import The Certificate Into Keychain

You can do this via Finder by just double-clicking on the .p12 file or by opening Keychain.app and using the import menu item but it's easier to use the command line:

$ security import me_rosstimson_com_bundle.p12 -k ~/Library/Keychains/login.keychain-db
1 identity imported.
1 certificate imported.

Note: If following these steps to renew a certificate then you should remove the existing, soon to expire, certificate from Keychain.app before trying to import the new one.

Once successfully imported you should be able to see it within Keychain.app within 'login -> certificates', this is what mine looks like:

Screenshot of Keychain.app on macOS showing an imported S/MIME certificate.
Figure 2: An imported S/MIME certificate within Keychain.app

Testing

If the certificate is in Keychain.app and showing as valid then try sending a message to yourself, you should see a signing option like this when composing an email:

Screenshot of Keychain.app of email compose in Mail.app on macOS with the S/MIME signing option.
Figure 3: Composing an email with the S/MIME signing option

When you receive the email you should be able to see that the email is signed like the screenshot in the introduction and if you click on it you can double check the validity and expiry of the certificate:

Screenshot of the certificate details of a signed email that has been received.
Figure 4: Checking the validity and expiry of an S/MIME certificate from a received email

iPad and iPhone

If you use iCloud and trust it to store the .p12 which of course includes the private key then place it somewhere in there and then access it from the Files.app from iOS or iPadOS. By tapping on the .p12 file the device will prompt about installing it. The alternative is to email the p12 file to yourself and then access it from the mail client on any mobile devices.

Once installed the cert weirdly 'lives' within Settings -> General -> VPN & Device Management, again if renewing you can delete a soon to expire cert from here too. This is what mine looked like, you can then click onto the 'Configuration Profile' to check the details of the cert.

Screenshot of installed S/MIME certificates within iPhone settings.
Figure 5: Installed S/MIME certificates within iPhone settings

Issues

I have the latest version of OpenSSL installed via Homebrew on my mac and when generating the CSR and creating the p12 bundle I was using the Homebrew installed version of the openssl command as they come first in my $PATH. However, when it then came to installing the p12 bundle into Keychain.app I was getting all sorts of misleading errors about it being invalid or about the passphrase being wrong. What was actually wrong is a mismatch between the versions of OpenSSL, this is why in the .p12 creation command I've used the full path to the macOS system version /usr/bin/openssl, when you create the .p12 with that one then it will install into Keychain.app fine. This confused me and had me banging my head against the wall for over an hour, hopefully this note saves you some time and confusion.