Obtaining credentials
To use S/MIME, you’ll need a set of “credentials”, which is sometimes called an “identity”. A common type of credentials are usernames and passwords, but S/MIME uses a different type of credentials: certificates and private keys.
A certificate is a file in a special format containing a set of information. For S/MIME, it must contain the email address and a public key, but other information (e.g. your name) is optional. It is used to validate signatures you create, and to encrypt emails for you to decrypt.
A private key is used to sign emails you send, and to decrypt emails you receive.
S/MIME uses public-key cryptographic algorithms, which involves two related keys with special mathematical properties. The two keys are called a public key and a private key. The certificate (which contains the public key) can be shared with anybody. The private key must be kept secure—do not give it to anyone else.
A certificate needs to be obtained from an issuing authority.
Generate the key pair and Certificate Signing Request
First, generate the public key and private key.
Using the command line
A private key and Certificate Signing Request (CSR) can be generated with:
openssl req -newkey rsa:2048 -sha256 \
-keyout example.private -out example.csr \
-subj "/CN=account@example.com"
The req
argument generates a CSR. The -newkey rsa:2048
generates a
new 2048-bit key pair using the RSA public-key algorithm. The
-sha256
uses the SHA-256 algorithm to sign the CSR.
The private key is saved in the -keyout
file. For extra security,
the private key is encrypted using a passphrase. The private key is
not encrypted if the -nodes
option is used.
The CSR is saved in the -out
file. It contains a copy of the public
key that was generated and will be sent to the certificate issuer.
Other options, like -subj
, can be used to add other information to
the CSR. Most certificate issuers nowdays ignore the other information
in the CSR, using the information entered into their Web form used to
upload the CSR and request the certificate. Therefore, the values
don’t really matter.
To display the information in a CSR:
openssl req -in example.csr -text -noout
Using Keychain Access
A CSR can be also be generated using the Keychain Access application.
From the “Keychain Access” menu, select “Certificate Assistent” > “Request a Certificate from a Certificate Authority”.
Enter the user email address and common name.
Select the checkbox so the request is “Saved to disk”.
Press the “Continue” button.
Select a location to save the .certSigningRequest file.
Close the dialog by pressing the “Done” button.
The public key and private key will both be stored inside your keychain, using the common name as their names.
Obtain a certificate
Certificates signed by a certificate authority
Submit the CSR to a certificate issuer to obtain a certificate. Most certificates issuers provide Web server certificates for TLS or certificates for code signing, but you’ll need to use one that provides S/MIME email certificates.
An example S/MIME certificate provider is DigiCert. Their Website only mentions S/MIME certificates for enterprises and large companies, but they do sell individual S/MIME certificates (in 2021, a certificate with 1 year expiry costs US$45, or 3 years for US$126). Just register for a free account and then contact DigiCert sales with your account number (which found under a drop down menu at the top right corner of the CertCentral portal) to ask them to enable the “Class 1 S/MIME” client certificate product on your account. A “Class 1 S/MIME” certificate only requires proof that you have access to the email address.
The certificate issuer will take the CSR and generate a certificate containing a copy of the public key. That certificate will be signed by their intermediate certificate (sometimes called a Certificate Authority certificate). And that intermediate certificate is usually signed by the issuer’s root certificate. To distinguish it from the other certificates, the certificate containing your public key is sometimes qualified as the “client certificate”.
To display the contents of a certificate:
openssl x509 -in example.crt -text -noout
Creating a self-signed certificate with Keychain Access
A self-signed certificate can be used for testing. But since it is not issued by a trusted certificate issuer, the email signatures it creates will not be trusted by receivers (unless they manually add it to their set of trusted certificates).
Use the Keychain Access application to create a self-signed certificate. From the “Keychain Access” menu choose “Create a Certificate”. Enter a name for the certificate (e.g. the person’s name) and choose “Self-Signed Root” as the identity type and “S/MIME (Email)” as the certificate type. Always select the “Let me override defaults” checkbox, so the certificate’s email address can be entered. The certificate, public key and private key will be stored inside your keychain and is ready for use (i.e. you can skip the PKCS#12 importing steps).
Create a PKCS#12 file
To import the private key and certificate into a keychain file, you will need a PKCS#12 formatted file. If your certificate issuer has already provided a PKCS#12 file, you can use it, otherwise create one from the private key and the other certificates.
First create a file containing the client certificate and all the intermediary certificates:
cat example.crt intermediary-CA.crt > import.crts
Do not include the root certificate in the file, because it should already be in the macOS “System Roots” keychain. Commercial certificate issuers should have their root certificate already trusted by the operating system.
To create a PKCS#12 file with the private key and certificates:
openssl pkcs12 -export -legacy -inkey example.private -in import.crts \
-name "account@example.com S/MIME exp 20xx" -aes256 -out example.p12
The -legacy
option is needed for OpenSSL v3.x and newer. Otherwise,
it uses newer algorithms which produces a PKCS#12 file that are not
yet supported by macOS/iOS programs.
The private key is specified by the -inkey
option, and the
certificate chain with the -in
option.
The value passed to the -name
option is known as a “friendly
name”. It is optional, but it will be very useful for identifying the
private key when it is inside a keychain. Putting a year or date in it
is useful when there are multiple private keys for the same email
address (e.g. when the certificate is renewed).
The -aes256
option encrypts the private key in the PKCS#12 file
using the AES-256 algorithm.
When prompted, enter the passphrase to decrypt the private key input file. A non-empty passphrase must be provided to encrypt the private key in the PKCS#12 output file (while OpenSSL accepts an empty passphrase, Keychain Access will not).
Optional commands for using the PKCS#12 file
To display information about a PKCS#12 file:
openssl pkcs12 -in example.p12 -info
To extract the client certificate from a PKCS#12 file:
openssl pkcs12 -in example.p12 -clcerts -nokeys -out cert.crt
To extract the private key from a PKCS#12 file:
openssl pkcs12 -in example.p12 -nocerts -nodes -out privkey.private
Warning: the displayed/extracted private key is not encrypted.
File naming convention
For certificates, the “.crt” file extension is commonly used for a single certificate. The “.cer” extension may also be used.
There is no convention for a file containing multiple certificates. The above example uses the “.crts” file extension.
For PKCS#12 files, macOS recognises both “.p12” and “.pkcs12” extensions.
For Certificate Signing Requests, macOS recognises the “.certSigningRequest” file extension, but it is more conventional to use the “.csr” extension.
For private keys, there appears to be no convention on macOS. The above uses the “.private” file extension, because on macOS the “.key” extension is treated as a Keynote file and a “.pvt” extension is treated as a Pivot Stickfigure Animator file.