SYNOPSYS

I need a PKI to setup a VPN.
It’s based on my analysis of what easy-rsa does.

DOCUMENTATION

Simple PKI subjectAltName = DNS:example.com, DNS:www.example.com, DNS: app.example.com
How to create your own PKI with openssl -extensions server_cert
Creating a PKI infrastructure with OpenSSL

PROCEDURE

Create the basic infrastructure

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
base=$(pwd)/pki
conf=$base/openssl.conf
key_pass=$base/key_pass
serial=$base/serial
ca_key=$base/private/ca.key
ca_crt=$base/ca.crt
server_key=$base/server.key
server_req=$base/reqs/server.req
server_crt=$base/issued/server.crt
client_key=$base/client.key
client_req=$base/reqs/client.req
client_crt=$base/issued/client.crt

rm -fr pki && mkdir -p pki/{issued,private,reqs,issued,certs_by_serial}
touch pki/index.txt
echo "my_private_key_passwd" > $key_pass

Create the openssl configuration file ( see /etc/ssl/openssl.cnf )

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
cat <<EOF > $conf
[ ca ]
default_ca      = CA_default

[ CA_default ]
dir             = MY_DIR
certificate     = \$dir/ca.crt           # the CA certificate
private_key     = \$dir/private/ca.key   # The private key
serial          = \$dir/serial           # the current serial number
database        = \$dir/index.txt        # database index file
certs           = \$dir/certs            # where the issued certs are kept
new_certs_dir   = \$dir/certs_by_serial  # default place for new certs

x509_extensions = sub_ca_cert
policy          = policy_anything

# Extensions to add when Root CA creates an Subordinate Certificate CA (Public Key)
[ sub_ca_cert ]
basicConstraints          = CA:true
keyUsage                  = critical, cRLSign, keyCertSign
subjectKeyIdentifier      = hash
authorityKeyIdentifier    = keyid, issuer

[ policy_anything ]
countryName             = optional
stateOrProvinceName     = optional
localityName            = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional
serialNumber            = optional

[req]
default_bits        = 2048
prompt              = yes
distinguished_name  = cn_only
x509_extensions     = req_exts

[ cn_only ]
commonName          = Common Name (eg: your user, host, or server name)
commonName_max      = 64
commonName_default  = AsYnK

[ req_exts ]
basicConstraints        = CA:TRUE
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always,issuer:always
keyUsage = cRLSign, keyCertSign

[ server_exts ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = serverAuth
keyUsage = digitalSignature,keyEncipherment
subjectAltName = DNS:openvpn

[ client_exts ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
extendedKeyUsage = clientAuth
keyUsage = digitalSignature
EOF

sed -i "s#MY_DIR#$base#" $conf
export OPENSSL_CONF=$conf

Generate the CA private key

1
2
openssl genpkey -algorithm ed25519 -out $ca_key -aes256 -pass file:$key_pass
openssl pkey -in $ca_key -passin file:$key_pass -text

Generate the CA certificate

1
2
openssl req -utf8 -new -x509 -days 3650 -sha256 -key $ca_key -passin file:$key_pass -out $ca_crt
openssl x509 -in $ca_crt -text -noout

Generate the server private key and certificate signing request

1
2
3
openssl req -utf8 -new -newkey ed25519 -keyout $server_key -out $server_req -noenc
openssl pkey -in $server_key -text -noout
openssl req -in $server_req -text -noout

Generate the client private key and certificate signing request

1
2
3
openssl req -utf8 -new -newkey ed25519 -keyout $client_key -out $client_req -noenc
openssl pkey -in $client_key -text -noout
openssl req -in $client_req -text -noout

Show the CN of each request

1
2
openssl req -in $server_req -noout -subject -nameopt utf8,sep_multiline,space_eq,lname,align
openssl req -in $client_req -noout -subject -nameopt utf8,sep_multiline,space_eq,lname,align

Generate a random serial and sign the server certificate with the CA

1
2
3
openssl rand -hex 16 > $serial
openssl ca -utf8 -batch -days 825 -in $server_req -out $server_crt -extensions server_exts -passin file:$key_pass
openssl x509 -in $server_crt -text -noout

Generate a random serial and sign the client certificate with the CA

1
2
3
openssl rand -hex 16 > $serial
openssl ca -utf8 -batch -days 825 -in $client_req -out $client_crt -extensions client_exts -passin file:$key_pass
openssl x509 -in $client_crt -text -noout