Last Updated Aug 17, 2021

Purpose

Often devices that we use daily, such as raspberry pi hosted projects, UniFi controller, Firewall, NAS, etc, use SSL to secure communication but use self-signed certificates. While there is nothing wrong with the use of self-signed certificates per se, it is a bit annoying that you have to create security exceptions for each one on each of your user devices and despite that some vigilante browsers such as Chrome and Firefox still won’t be happy and would be displaying crossed-out the lock and claiming that the web site is not secure.

This is highly annoying, to say the least. There are two solutions to this inconvenience:

One - pay for commercial SSL DV (possibly wildcard) certificates and install them on all devices.

  • Pros: browsers will be happy, nothing to configure on user devices.
  • Cons: this costs money and wildcard certificates are even more expensive.

However, if only you and a bunch of other people are the only ones who use these devices services then there is no need to pay for a commercial certificate; Instead, you can create your own Certificate Authority, import it once to each device you use; set it to be trusted as Root CA and then keep issuing certificates from it to secure your devices.

  • Pros: It’s completely free, and provides the same security and visuals.
  • Cons: Because devices certificates are going to be issued from the CA that your systems know nothing about you would need to import the CA certificate and mark it as trusted explicitly on each device.

Now browsers will see that the certificates your devices and services use are non-self-signed anymore but use Certificate Authority that is trusted on your system and will happily show green lock. Voila.

Why Certificate Assistant and not easy-RSA or other PKI tools

Well, because it’s already there, it’s free, it is user-friendly, it stores certificates in your keychain by default, and just works. I think these are the reasons enough.

Why this blogpost, it was covered a million times on the Internet

Yes, it was, and yet every single tutorial and blogpost I found was missing some crucial details or was blatantly wrong. This blog post is an approach that worked for me and I successfully secured a bunch of appliances – such as UniFi controller and Synology DiskStation.

Creating Certificate Authority

TLDR

Follow the wizard with a few exceptions. Parts that are important to change or important to leave as is are in bold:

  • Choose to Override Details,
  • Disable extended key usage

Walk-through

  • Start Keychain Access.app.
  • Select Keychain Access -> Certificate Assistant -> Create Certificate Authority

Create Your Certificate Authority

  • Name: Choose a friendly name for your CA
  • Identity type: select Self Signed Root CA
  • User certificate: Does not matter, we’ll delete it later. SSL Server for now.
  • Let me Override Defaults: Check. Very important, you’ll see later why.
  • Email from: Select email
  • Make this CA as default: Up to you.

Certificate Information

  • Serial Number: Choose any number you like. I left it at 1.
  • Validity Period (days): No longer than 825 days
  • Create a CA web site: Unchecked.
  • Sign your invitation: Uncheck

Press Continue

  • Email address: Up to you
  • Name (Common Name): Select something telling, such as “My Home CA”
  • Organization, Unit, City, State, Country: Optional

Key Pair Information for This CA

  • Specify Key Pair Information For This CA: 2048/RSA or longer

Press Continue

  • Specify Key Pair Information For Users of This CA: 2048/RSA or longer

Press Continue

Key Usage Extension For This CA:

  • Include Key Usage Extensions: Checked
  • This extension is critical: Unchecked
  • Capabilities:
    • Signature: Checked
    • Certificate Signing: Checked

Key Usage Extension For Users of This CA:

  • Include Key Usage Extension: Checked
    • This Extension is Critical: Checked
    • Capabilities
      • Signature: Checked
      • Key Encipherment: Checked

Extended Key Usage Extension For This CA

  • Include Extended Key Usage Extension: Uncheck. In Catalina, this seems to be already unchecked by default.

This is to make Firefox happy. See more details here: https://bugzilla.mozilla.org/show_bug.cgi?id=1049176.

Extended Key Usage For Users of This CA

  • Same as above, Uncheck.

Basic Constraints Extension For This CA

  • Include Basic Constraints Extension: Checked
    • `Use this certificate as a certificate authority: Checked
    • Path Length Constraint Present: Unchecked

Basic Constraints Extension For Users fo This CA

  • Include Basic Constraints Extension: Unchecked

Subject Alternate Name Extension for This CA

  • Include Subject Alternate Name Extension: Unchecked, Unless you have good reason to provide alternate names

Select Alternate Name for Users of This CA

  • Include Subject Alternate Name Extensions: Unchecked, unless you have a good reason otherwise

Specify a Location for the certificate

You can decide to save your certificate authority to Login or System keychain. If you select System then before finalizing the certificate creation you would need to go back to the Keychain Access app, right-click on the System keychain and Unlock it. Otherwise, the certificate assistant will fail with an incomprehensible error message.

  • Keychain: System
  • Trust certificates signed by this CA on this machine: Check

Now press Create and provide your password a bunch of times - to import into the system keychain and to mark it as trusted.

Now we have the Certificate Authority. We can now issue certificates from it.

Distributing Root CA to clients

Export the CA certificate and distribute it to clients.

On a macOS

Double click the certificate to import it into Keychain. Find it there and mark as Trusted.

On Windows

See this post: https://stackoverflow.com/questions/23869177/import-certificate-to-trusted-root-but-not-to-personal-command-line

On iOS

AirDrop or mail yourself the certificate. Open it to install it. Then go to Settings -> General -> About -> Certificate Trust Settings and turn on Enable trust for that Root CA

Creating certificate issued from this authority

As an example, we will create and verify a certificate for a web server running in a docker container on the local machine. To facilitate this please add the following few hostnames to your /etc/hosts file:

    127.0.0.1       localtestserver
    127.0.0.1       localtestserver.local
    127.0.0.1       localtestserver.example.com

We will create a certificate that will be valid for these hostnames.

Walk-through

  • Start Keychain Access
  • Optionally, highlight the private key or certificate of the CA we created on the previews step
  • Select Keychain Access -> Certificate Assistant -> Create a certificate

Create your certificate

  • Name: Choose a name for your certificate
  • Identity Type: change it to Leaf
  • Certificate Type: SSL Server
  • Let me override defaults: Check

Certificate information

  • Select Serial Number: 1
  • Validity Period: 825 days or shorter

Note, for the certificates issued after June 2019 new requirements are in effect: https://support.apple.com/en-us/HT210176. This limits maximum validity to 825 days, amount other things.

Press Continue

  • Email: up to you
  • Common name: up to you

Choose an Issuer

  • Identity: Select Certificate authority we have created on step one. Likely this will be the only one offered.

Key Pair Information

Leave at Defaults

Key Usage Extension

Leave at Defaults

Extended Key Usage

  • Extension is Critical: Checked
  • SSL Server Authentication: Checked

Basic Constraints

Leave at Defaults

Subject ALternate Name Extension

  • Include Subject Alternate Name Extension: Checked
    • This extension is critical: Unchecked.
    • Extension Values
      • rfc822Name: Empty
      • URI: Empty
      • DNSName: Specify space-separated list of hostnames: localtestserver localtestserver.local localtestserver.example.com
      • IPAddress: 127.0.0.1

Specify the keychain

Does not matter. Complete the wizard.

Testing the certificate in a local webserver

Export keys

Open Keychain, search for a newly created certificate by hostname. You will see three entries: Certificate, Public key, and Private key.

  • Select Certificate and export it to certificate.cer file.
  • Select Private Key and export it to certificate.p12 file, with some pass-phrase.

Conver to plain-text

openssl x509 -inform der -in certificate.cer -out server.crt
openssl pkcs12 -in certificate.p12 -out server.key -nodes

You will be prompted for the private key pass-phrase (that you specified during an export on the previous step) by the second OpenSSL invocation. If you don’t want to type it in, you can specify it on a command line like so

openssl pkcs12 -in certificate.p12 -out server.key -nodes -password pass:Pa$$w0Rd

Starting apache in the docker

Install Docker. Then create Dockerfile in the same directory where you have your keys with the following content:

FROM httpd:2.4

RUN sed -i \
        -e 's/^#\(Include .*httpd-ssl.conf\)/\1/'           \
        -e 's/^#\(LoadModule .*mod_ssl.so\)/\1/'            \
        -e 's/^#\(LoadModule .*mod_socache_shmcb.so\)/\1/'  \
        conf/httpd.conf

RUN mkdir -p /usr/local/apache2/htdocs/public-html/      && \
    echo "<html><body>It Works!</body></html>" >                \
        /usr/local/apache2/htdocs/public-html/index.html

COPY ./server.crt /usr/local/apache2/conf/server.crt    
COPY ./server.key /usr/local/apache2/conf/server.key

This configures httpd container, turns on SSL extensions, and uploads our certificates into the right places. It also creates a simple HTML file that prints “It Works!”.

Now build and run your container:

docker build -t my-test-webserver-image .
docker run -itd                 \
        -p 8080:80              \
        -p 443:443              \
        my-test-webserver-container

Then fire up Safari and and visit https://localtestmachine or https://localtestserver.local or https://localtestserver.example.com. You should be greeted with “It Works”. Click on the lock and confirm that the certificate is trusted and issued from your CA.

Note, you would need to import the CA certificate into the trusted root list in Firefox separately since it keeps a separate trust chain: Firefox -> Preferences -> Privacy and Security -> Certificates -> View Certificates -> Import…

History

February 26, 2019 Initial publication
November 27, 2019 Updated to reflect new certificate requirements
July 06, 2020 Added advice to unlock the System keychain before importing the certificate. Fixed typos. Formatted hyperlinks.
Aug 17, 2021 Added missing extra step after “Extended Key Usage Extension For This CA”. Kudos to the reader who pointed this out.