From ae186ff1975f118f7476509146d3d58576126711 Mon Sep 17 00:00:00 2001 From: Adam Veldhousen Date: Sat, 28 Jan 2023 20:34:55 -0600 Subject: [PATCH] first draft --- content/posts/create-your-own-ca-cert.md | 141 ++++++++++++++--------- 1 file changed, 84 insertions(+), 57 deletions(-) diff --git a/content/posts/create-your-own-ca-cert.md b/content/posts/create-your-own-ca-cert.md index 46bfd4a..f95cddc 100644 --- a/content/posts/create-your-own-ca-cert.md +++ b/content/posts/create-your-own-ca-cert.md @@ -7,95 +7,122 @@ tags: draft: false --- -Even though there are plenty of free SSL certificate options, you may need to manage your own SSL certs for various reasons. +Even though there are plenty of options available for obtaining an SSL certificate, you may want to issue your certificates +and check their validity using your own CA. This is useful for internal domains or doing mTLS for services in your networks. -Below is how to create a CA certificate and issue certs signed with it, as well as some validation steps to make sure you did everything right. +Below is how to create a CA certificate and issue certs with it, and how to verify that a certificate was issued with +the CA you generated. -All examples here use the [openssl](https://www.openssl.org/docs/man1.1.1/man1/) cli tool. +All examples here use the [OpenSSL command-line tool](https://www.openssl.org/docs/man1.1.1/man1/). +## Creating the Certificate Authority Certificate and Keys -## Creating the Certificate Authority's Certificate and Keys +First generate the private key and Root CA certificate that we will use to issue certs. 1. Generate a private key for the CA: -```sh -$ openssl genrsa 4096 > ca-key.pem +```sh {linenos=false} +openssl genrsa 4096 > ca-key.pem ``` -2. Generate the X509 certificate for the CA: -```sh - $ openssl req -new -x509 -nodes -days 3650 -sha256 \ - -subj "/C=US/ST=CO/O=My Org, Inc./OU=Engineering/CN=ca.example.internal" \ - -key ca-key.pem \ - -out ca-cert.pem +2. Generate the X509 CA certificate. Note that if you exclude `-subj` you will get an interactive prompt instead: +```sh {linenos=false} +openssl req -new -x509 -nodes -days 3650 -sha256 \ + -subj "/C=US/O=My Org, Inc./OU=R&D/CN=MyOrgCA" \ + -key ca-key.pem \ + -out ca-cert.pem ``` +If you want to pass more options to `-subj` the following are the available attribute strings - from [RFC4514 Page 6](https://www.rfc-editor.org/rfc/rfc4514): +```text {linenos=false} + String X.500 AttributeType + ------ -------------------------------------------- + CN commonName (2.5.4.3) + L localityName (2.5.4.7) + ST stateOrProvinceName (2.5.4.8) + O organizationName (2.5.4.10) + OU organizationalUnitName (2.5.4.11) + C countryName (2.5.4.6) + STREET streetAddress (2.5.4.9) + DC domainComponent (0.9.2342.19200300.100.1.25) + UID userId (0.9.2342.19200300.100.1.1) +``` + +At this point you can view the CA certificate in a pretty format: +```sh {linenos=false} +$ openssl x509 -in mydomain.com.crt -text -noout +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 25:28:31:d4:81:a4:1e:74:36:9c:50:e2:3e:dd:d0:a5:be:c9:d3:25 + Signature Algorithm: sha256WithRSAEncryption + Issuer: C = US, O = "My Org, Inc.", OU = R&D, CN = MyOrgCA + Validity + Not Before: Jan 29 02:06:59 2023 GMT + Not After : Jan 26 02:06:59 2033 GMT + Subject: C = US, O = "My Org, Inc.", OU = R&D, CN = MyOrgCA + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (4096 bit) + Modulus: + ... +``` + + ## Creating the Server's Certificate and Keys +Now that we have our Root CA certificate we can issue certs for our servers to use. To do this you must first generate a +certificate request, and then sign it with your Root CA cert to generate the final certificate. + 1. Generate the private key and certificate request: -```sh -$ openssl req -newkey rsa:4096 -nodes -days 3650 -sha256 \ # -newkey if you need a new private key - -subj "/CN=mysite.example.internal" \ # exclude this and you will get interactive prompts +```sh {linenos=false} +openssl req -newkey rsa:4096 -nodes -sha256 \ + -subj "/CN=mysite.myorg.internal" \ -keyout server-key.pem \ -out server-req.pem +``` -# if you already have a private key -$ openssl req -new -nodes -days 3650 -sha256 \ - -subj "/CN=mysite.example.internal" \ - -key server-key.pem \ - -out server-req.pem - -# if you want to add SANs -$ openssl req -new -nodes -days 3650 -sha256 \ +If you want to add Subject Alternative Names (SANs) to make your cert valid for multiple DNS names, you can use the encantation below: +```sh {linenos=false} +openssl req -newkey rsa:4096 -nodes -days 3650 -sha256 \ -subj "/CN=mydomain.com" \ -reqexts SAN \ - -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:test.example.internal,DNS:www.example.internal")) \ # to add SANs + -config <(cat /etc/ssl/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:site1.myorg.internal,DNS:site2.myorg.internal")) \ -key server-key.pem \ -out server-req.pem ``` - 2. Generate the X509 certificate for the server: -> `-days` expiration can be no longer than 398 days (13 months) (thanks [Apple](https://support.apple.com/en-us/HT211025)) -> https://www.globalsign.com/en/blog/maximum-ssltls-certificate-validity-now-one-year -> `-set_serial` is like an ID number for each cert. It must be a positive integer and unique to each cert signed by the CA. -> `date +%s` prints the current number of seconds since the Epoch (00:00:00 UTC, January 1, 1970). See [RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.2 "https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.2") for details - -```sh -$ openssl x509 -req -days 398 -set_serial $(date +%s) -sha256 \ - -in server-req.pem \ - -out server-cert.pem \ - -CA ca-cert.pem \ - -CAkey ca-key.pem - -# if you want to add SANs -$ openssl x509 -req -days 398 -set_serial $(date +%s) -sha256 \ - -extfile <(printf "subjectAltName=DNS:my.domain.com") \ +When setting `-days`, the validity time can be no longer than *398 days (13 months)* or you might see errors. This is for security reasons, +read up on the history behind it [here at global sign](https://www.globalsign.com/en/blog/maximum-ssltls-certificate-validity-now-one-year). + +The flag `-set_serial` is like an ID number for each cert issued by your CA. It must be a positive integer and unique to each cert issued. +Below I'm just using `date +%s` to get a unix timestamp for a simple serial number. + +For further reading see [RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.2). + +```sh {linenos=false} +openssl x509 -req -days 398 -set_serial $(date +%s) -sha256 \ -in server-req.pem \ -out server-cert.pem \ -CA ca-cert.pem \ -CAkey ca-key.pem -``` - -## Verifying the Certificates -1. Verify the server certificate: -```sh - $ openssl verify -CAfile ca-cert.pem \ - ca-cert.pem \ - server-cert.pem +# Or once again, if you need to specify SANs +openssl x509 -req -days 398 -set_serial $(date +%s) -sha256 \ + -extfile <(printf "subjectAltName=DNS:site1.myorg.internal,DNS:site2.myorg.internal") \ + -in server-req.pem \ + -out server-cert.pem \ + -CA ca-cert.pem \ + -CAkey ca-key.pem ``` -2. Verify the client certificate: -```sh - $ openssl verify -CAfile ca-cert.pem \ - ca-cert.pem \ - client-cert.pem -``` +## Verifying the Certificate -## Verify the certificate's content +1. To verify the server certificate: -```sh -openssl x509 -in mydomain.com.crt -text -noout +```sh {linenos=false} +$ openssl verify -CAfile ca-cert.pem server-cert.pem ```