Skip to content

Instantly share code, notes, and snippets.

@MohamedKari
Last active May 28, 2020
Embed
What would you like to do?
CA-signed Certificate Generation with self-generated CA
# make SAN entries for *.amazonaws.com certificate
echo "DNS = ec2-x-x-x-x.eu-central-1.compute.amazonaws.com" >> amazonaws.com.san

# make SAN entries for localhost certificate
echo "DNS.1 = localhost" >> localhost.san
echo "IP.1 = 127.0.0.1" >> localhost.san
echo "IP.2 = 0.0.0.0" >> localhost.san

# make CA Certificate and add it to OS cert store
make ca-crt
make add-to-macos-store

# make client certs to be used by the local Dev Web Server and the Cloud Dev Web Server
make client-crt SAN_FILE="amazonaws.com.san"
make client-crt SAN_FILE="localhost.san"

OpenSSL Keys

Creating a public/private key pair

Using openssl (PEM format)

The following creates a key pair that is contained within a single file:

openssl genrsa -out private.key 4096

Even though the file looks like

-----BEGIN RSA PRIVATE KEY-----
MIIJKgIBAAKCAgEAy4rZLJaLe...
-----END RSA PRIVATE KEY-----

it actually contains the key pair.

In fact, we can see the components of the private key incl. the public by using:

openssl rsa -noout -text -in private.key

which yields

RSA Private-Key: (4096 bit, 2 primes)
modulus:
    00:cb:8a:d9:2c:96:8b:79
    ...
publicExponent: 65537 (0x10001)
privateExponent:
    00:cb:8a:d9:2c:96:8b:79:65:dc:f2:d7:08:6e:d4:
    e5:b0:03:e0:62:47:9a:ad:93:f2:61:90:b5:e7:34:
    ...
prime1:
    00:e4:6f:ea:3e:71:14:52:e0:d1:7b:71:6e:59:78:
    d1:84:0c:8c:81:00:66:90:e1:de:ae:cc:3b:77:cb:
    ...
prime2:
    00:e4:19:f8:5c:a8:c3:3c:1d:c9:23:22:3e:d0:98:
    41:2c:f1:3e:cb:43:98:7e:fc:b8:66:bd:21:d0:73:
    ... 
exponent1:
    00:b8:87:5f:25:89:9a:ed:48:06:70:3d:34:f2:b9:
    92:25:a5:2d:6a:97:b4:42:9c:f2:91:29:11:70:b8:
    ...
exponent2:
    69:41:da:ab:d7:6c:90:37:26:73:c1:ff:be:7e:23:
    c5:3b:65:c0:a2:66:a2:62:b8:2d:20:a5:93:ed:8a:
    ...
coefficient:
    00:96:d5:da:3a:77:b4:91:4d:ce:c1:ca:a6:2e:fc:
    97:8e:da:da:47:b9:fb:45:b7:82:94:ec:50:c1:14:
    ...

The components of the public key can be examined using:

openssl rsa -noout -text -inform PEM -in public.key -pubin

which comprises only the modulus and the exponent.

The public key can be extracted from the Base64-encoded string using

openssl rsa -in private.key -pubout -out public.key

The discussed inputs and outputs are PEM-encoded, which esp. means that they private.key file and the public.key file are PEM-Header and PEM-Footer-sandwiched.

The public key can also be extracted from the private key using ssh-key with

ssh-keygen -y -f private.key > public.key

however this will result in the public.key file be in OpenSSH encoding. See below to convert a public.key in OpenSSH format to a public.key in PEM format.

The following however are equivalent:

openssl rsa -in private_pem.key -pubout -out public_pem.key
ssh-keygen -f public_pem.key -i -mPKCS8 > public_openssh.key
- and -
ssh-keygen -y -f private_pem.key > public_openssh.key

Using ssh-keygen (OpenSSH format = PKCS8 format)

ssh-keygen -P "" -t rsa -b 4096 -f some_key

will create a private key named some_key and a public key named some_key.pub, both in OpenSSH (= PKCS8) format.

Conversion

From OpenSSH public key to PEM public key

ssh-keygen -f public_openssh.key -m 'PEM' -e > public_pem.key

From PEM public key to OpenSSH public key

ssh-keygen -f public_pem.key -i -mPKCS8 > public_openssh.key

Private key

The private key is normally PEM format.

# args
SAN_FILE = localhost.san
# vars
NAME = $(basename $(SAN_FILE))
ca_key_passphrase = $(shell openssl rand -base64 32)
define ca_conf_template
[ req ]
default_bits = 4096
default_md = sha256
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[ req_distinguished_name ]
C = DE
ST = NW
L = Essen
O = mkari
OU = mo
CN = SelfSigningCA
[v3_ca]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
basicConstraints = CA:TRUE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign
subjectAltName = email:mo@mkari.de
issuerAltName = issuer:copy
endef
define req_conf_template
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no
[ req_distinguished_name ]
C = DE
ST = NW
L = Essen
O = Kari
OU = Mo
CN = $(NAME)
[ v3_req ]
basicConstraints = CA:FALSE
subjectAltName = @SAN
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign
[ SAN ]
endef
export ca_conf_template
export req_conf_template
ca-cert-conf:
printf "$$ca_conf_template" > ca-cert.cnf
req-cert-conf:
rm -f req-cert.conf
printf "$$req_conf_template" > req-cert.cnf
cat $(SAN_FILE) >> req-cert.cnf
private-client-key:
# private key actually contains the private and the public key
# see readme for more info, e. g. on how to examine the components of the private key
echo "creating new private key for client..."
openssl genrsa -out $(NAME).pem 2048
# create the certficate for Certificate Authority
ca-crt: ca-cert-conf
printf $(ca_key_passphrase) > ca-cert.pass
openssl req \
-new \
-passout file:ca-cert.pass \
-keyout ca-cert.key \
-config ca-cert.cnf \
-x509 \
-extensions v3_ca \
-out ca-cert.crt \
-days 365
openssl rsa -in ca-cert.key -out ca-cert-unecrpyted.key -passin file:ca-cert.pass
# create the Certificate Signing Request
client-csr: req-cert-conf private-client-key
openssl req \
-new \
-nodes \
-key $(NAME).pem \
-out $(NAME).csr \
-config req-cert.cnf
# sign the certificate with the Certificate Authority
client-crt: req-cert-conf client-csr
openssl x509 \
-req \
-days 365 \
-in $(NAME).csr \
-CA ca-cert.crt \
-CAkey ca-cert.key \
-CAcreateserial \
-out $(NAME).crt \
-extfile req-cert.cnf \
-extensions v3_req \
-passin file:ca-cert.pass
verify:
openssl verify -CAfile ca-cert.crt localhost.crt
openssl x509 -in ca-cert.crt -text -noout
openssl x509 -in localhost.crt -text -noout
add-to-macos-store:
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca-cert.crt
check-with-curl:
curl -vvv --cacert ./ca-cert.crt https://localhost:5000
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment