Difference between revisions of "Create a OpenVPN Certificate Authority"

From Exterior Memory
Jump to: navigation, search
(CA Configuration Files)
(typos; sha1 -> sha2)
 
(28 intermediate revisions by the same user not shown)
Line 1: Line 1:
Part of configuring OpenVPN involves the creation of a certificate authority (CA), also known as a public key infrastructure (PKI) (the ''public'' refers to public-key cryptography). You '''can not use an existing public key infrastructure'''; you would allow anyone with a certificate of that PKI to connect to your server (the <code>tls-remote</code> and <code>tls-verify</code> options can limits the allowed clients). You either need to to set up your own certificate infrastructure, or limit OpenVPN to use password-based authentication (see the options <code>auth-user-pass-verify</code>, <code>client-cert-not-required</code> and <code>username-as-common-name</code>).
+
Part of configuring OpenVPN involves the creation of a certificate authority (CA), also known as a public key infrastructure (PKI) (the ''public'' refers to public-key cryptography). You '''can not use an existing public key infrastructure'''; you would allow anyone with a certificate of that PKI to connect to your server (the <code>tls-remote</code> and <code>tls-verify</code> options can limit the allowed clients). You either need to set up your own certificate infrastructure, or limit OpenVPN to use password-based authentication (see the options <code>auth-user-pass-verify</code>, <code>client-cert-not-required</code> and <code>username-as-common-name</code>).
  
 
The easiest method it to use easy-rsa, as described in the [http://openvpn.net/index.php/open-source/documentation/howto.html OpenVPN How-to].
 
The easiest method it to use easy-rsa, as described in the [http://openvpn.net/index.php/open-source/documentation/howto.html OpenVPN How-to].
Line 7: Line 7:
 
Certificates, when deployed correctly, are ''much'' more secure than passwords, since the secret (key) does not need to be exchanged or shared between the different hosts. However, doing so requires a security hygiene which may not be required for a small-scale deployment.
 
Certificates, when deployed correctly, are ''much'' more secure than passwords, since the secret (key) does not need to be exchanged or shared between the different hosts. However, doing so requires a security hygiene which may not be required for a small-scale deployment.
  
=== Files ===
+
== Files ==
  
 
The following files are used by OpenSSL:
 
The following files are used by OpenSSL:
Line 75: Line 75:
 
This is a compromise between the completely flat file structure of easy-rsa, and the recommendations set forth by most CA tutorials, which creates directories for certificate requests (<code>.req</code>), signed certificates (<code>.crt</code>), certificate revokations (<code>crl</code>), and private keys (<code>ca.key</code>).
 
This is a compromise between the completely flat file structure of easy-rsa, and the recommendations set forth by most CA tutorials, which creates directories for certificate requests (<code>.req</code>), signed certificates (<code>.crt</code>), certificate revokations (<code>crl</code>), and private keys (<code>ca.key</code>).
  
If you are serious about security, you should not run these commands on the same machine, but run commands in the server, client1, and client2 directory of respectively the server and client machines, and run commands in the CA directory on a machine that is not connected to the Internet.
+
If you are <del>some paranoid whacko</del> serious about security, you should not run these commands on the same machine, but run commands in the server, client1, and client2 directory of respectively the server and client machines, and run commands in the CA directory on a machine that is not connected to the Internet.
  
=== Initialize ===
+
== Initialize ==
  
 
(roughly equivalent to <code>easy-rsa/clean-all</code>)
 
(roughly equivalent to <code>easy-rsa/clean-all</code>)
Line 85: Line 85:
 
  touch index.txt
 
  touch index.txt
  
=== CA Configuration Files ===
+
== CA Configuration Files ==
  
Create configuration files. In our setup, <code>ca-sign.cnf</code> contains the configuration for signing certificates. We only use it in conjunction with the <code>openssl ca</code> command. It described the folder structure within the ca directory, the location of support files for the CA, as well as properties of the signed certificates (duration, restricted usage) as well as the policy for the name ("distinguished name") of signed certificates. Finally, it lists the policy for certification revocation lists.
+
Create configuration files. In our setup, <code>ca-sign.cnf</code> contains the configuration for signing certificates. We only use it in conjunction with the <code>openssl ca</code> command. It described the folder structure within the ca directory, the location of support files for the CA, as well as properties of the signed certificates (duration, restricted usage) as well as the policy for the name ("distinguished name") of signed certificates. Finally, it lists the policy for certification revocation lists. For this small-scale CA, there is no public URL to download the CRL; I plan to distribute it manually.
  
 
  # ca-sign.cnf
 
  # ca-sign.cnf
 
  # This configuration file is used by the 'ca' command, to create signed certificates.
 
  # This configuration file is used by the 'ca' command, to create signed certificates.
 
  [ ca ]
 
  [ ca ]
  default_ca              = CA_default                   # The default ca section
+
  default_ca              = CA_default           # The default ca section
 
   
 
   
 
  [ CA_default ]
 
  [ CA_default ]
  dir                    = /path/to/ca                   # Where everything is kept
+
  dir                    = /path/to/ca           # Where everything is kept
  certs                  = $dir/                         # Where the issued certs are kept
+
  certs                  = $dir/                 # Where the issued certs are kept
  crl_dir                = $dir/                         # Where the issued crl are kept
+
  crl_dir                = $dir/                 # Where the issued crl are kept
  new_certs_dir          = $dir/                         # default place for new certs
+
  new_certs_dir          = $dir/                 # default place for new certs
 
   
 
   
  private_key            = $dir/ca.key                   # The private key
+
  private_key            = $dir/ca.key           # The private key
  certificate            = $dir/ca.crt                   # The CA root certificate
+
  certificate            = $dir/ca.crt           # The CA root certificate
  database                = $dir/index.txt               # List of signed certificates
+
  database                = $dir/index.txt       # List of signed certificates
  serial                  = $dir/serial                   # The current serial number
+
  serial                  = $dir/serial           # The current serial number
  crlnumber              = $dir/crlnumber               # the current crl number
+
  crlnumber              = $dir/crlnumber       # the current crl number
  crl                    = $dir/crl.pem                 # The current CRL
+
  crl                    = $dir/crl.pem         # The current CRL
  RANDFILE                = $dir/.rand                   # private random number file
+
  RANDFILE                = $dir/.rand           # private random number file
 
   
 
   
  unique_subject          = no                           # allow multiple certificates with same subject.
+
  unique_subject          = no                   # allow multiple certificates with same subject.
  default_md              = default                      # Use hash algorithm specified in the request
+
  default_md              = sha2                  # Use hash algorithm specified in the request
  default_days            = 730                           # client certificates last 2 years
+
  default_days            = 730                   # client certificates last 2 years
  #default_crl_days        = 30                           # How often clients should download the CRL
+
  default_crl_days        = 30                   # How often clients should download the CRL
 
   
 
   
  #x509_extensions        = X509_ca                       # The x509 extensions for the root certificate
+
  #x509_extensions        = X509_ca               # The x509 extensions for the root certificate
  #x509_extensions        = X509_server                   # The x509 extensions for a server certificate
+
  #x509_extensions        = X509_server           # The x509 extensions for a server certificate
  x509_extensions        = X509_client                   # The x509 extensions for a client certificate
+
  x509_extensions        = X509_client           # The x509 extensions for a client certificate
 
   
 
   
 
  # These options control what fields from the distinguished name to show before signing.
 
  # These options control what fields from the distinguished name to show before signing.
 
  # They are required to make sure all fields are shown.
 
  # They are required to make sure all fields are shown.
  name_opt                = ca_default                   # Subject Name options
+
  name_opt                = ca_default           # Subject Name options
  cert_opt                = ca_default                   # Certificate field options
+
  cert_opt                = ca_default           # Certificate field options
 
   
 
   
  copy_extensions        = copy                         # Copy extensions, such as subjectAltName, from the request
+
  copy_extensions        = copy                 # Accept requested extensions
 
   
 
   
 
  policy                  = policy_dn
 
  policy                  = policy_dn
Line 129: Line 129:
 
  # X509v3 extensions for the root certificate
 
  # X509v3 extensions for the root certificate
 
  basicConstraints        = CA:TRUE
 
  basicConstraints        = CA:TRUE
 +
nsCertType              = sslCA                # restrict the usage
 +
keyUsage                = keyCertSign, cRLSign  # restrict the usage
 
  subjectKeyIdentifier    = hash
 
  subjectKeyIdentifier    = hash
 
  authorityKeyIdentifier  = keyid:always,issuer:always
 
  authorityKeyIdentifier  = keyid:always,issuer:always
  #subjectAltName          = email:move                   # Move the email address from the DN in the request to here
+
  #subjectAltName          = email:move           # Move email address from DN to extensions
 
  #crlDistributionPoints  = URI:http://www.example.com/example_ca.crl
 
  #crlDistributionPoints  = URI:http://www.example.com/example_ca.crl
 
   
 
   
Line 137: Line 139:
 
  # X509v3 extensions for server certificates
 
  # X509v3 extensions for server certificates
 
  basicConstraints        = CA:FALSE
 
  basicConstraints        = CA:FALSE
  nsCertType              = server
+
  nsCertType              = server               # restrict the usage
 +
keyUsage                = digitalSignature, keyEncipherment
 +
extendedKeyUsage        = serverAuth            # restrict the usage
 
  subjectKeyIdentifier    = hash
 
  subjectKeyIdentifier    = hash
 
  authorityKeyIdentifier  = keyid,issuer
 
  authorityKeyIdentifier  = keyid,issuer
  #subjectAltName          = email:move                   # Move the email address from the DN in the request to here
+
  #subjectAltName          = email:move           # Move email address from DN to extensions
 
  #crlDistributionPoints  = URI:http://www.example.com/example_ca.crl
 
  #crlDistributionPoints  = URI:http://www.example.com/example_ca.crl
 
   
 
   
Line 146: Line 150:
 
  # X509v3 extensions for client certificates
 
  # X509v3 extensions for client certificates
 
  basicConstraints        = CA:FALSE
 
  basicConstraints        = CA:FALSE
  nsCertType              = client
+
  nsCertType              = client               # restrict the usage
 +
keyUsage                = digitalSignature      # restrict the usage
 +
extendedKeyUsage        = clientAuth            # restrict the usage
 
  subjectKeyIdentifier    = hash
 
  subjectKeyIdentifier    = hash
 
  authorityKeyIdentifier  = keyid,issuer
 
  authorityKeyIdentifier  = keyid,issuer
  #subjectAltName          = email:move                   # Move the email address from the DN in the request to here
+
  #subjectAltName          = email:move           # Move email address from DN to extensions
 
  #crlDistributionPoints  = URI:http://www.example.com/example_ca.crl
 
  #crlDistributionPoints  = URI:http://www.example.com/example_ca.crl
 
   
 
   
 
  [ policy_dn ]
 
  [ policy_dn ]
  countryName            = supplied                     # required parameter, any value allowed
+
  countryName            = supplied             # required parameter, any value allowed
 
  stateOrProvinceName    = optional
 
  stateOrProvinceName    = optional
 
  localityName            = optional
 
  localityName            = optional
  organizationName        = match                         # required, and must match root certificate
+
  organizationName        = match                 # required, and must match root certificate
 
  organizationalUnitName  = optional
 
  organizationalUnitName  = optional
  commonName              = supplied                     # required parameter, any value allowed
+
  commonName              = supplied             # required parameter, any value allowed
  emailAddress            = optional                     # email address in DN is deprecated, use subjectAltName
+
  emailAddress            = optional             # email in DN is deprecated, use subjectAltName
 +
 
 +
The x509_extensions sections are not really required by openssl or openvpn, but allows extra security by telling OpenVPN that clients only may connect to servers only. <tt>nsCertType</tt> is required for the OpenVPN option <tt>ns-cert-type server|client</tt>; <tt>keyUsage</tt> and <tt>extendedKeyUsage</tt> are required for <tt>remote-cert-tls server|client</tt>.
  
 
<code>ca.cnf</code> defines the distinguished name for the certificate authority. It also contains the key length (2048 is recommended nowadays, over the default of 1024), and if the key should be encrypted.
 
<code>ca.cnf</code> defines the distinguished name for the certificate authority. It also contains the key length (2048 is recommended nowadays, over the default of 1024), and if the key should be encrypted.
Line 166: Line 174:
 
  # This configuration file is used by the 'req' command when the root certificates is created.
 
  # This configuration file is used by the 'req' command when the root certificates is created.
 
  [ req ]
 
  [ req ]
  default_bits            = 2048                         # default strength of client certificates
+
  default_bits            = 2048                 # default strength of client certificates
  default_md              = sha1
+
  default_md              = sha2
  encrypt_key            = yes                           # "no" is equivalent to -nodes
+
  encrypt_key            = yes                   # "no" is equivalent to -nodes
 
  prompt                  = no
 
  prompt                  = no
 
  string_mask            = utf8only
 
  string_mask            = utf8only
  distinguished_name      = ca_distinguished_name         # root certificate name
+
  distinguished_name      = ca_distinguished_name     # root certificate name
 
  req_extensions          = req_cert_extensions
 
  req_extensions          = req_cert_extensions
 
  # attributes              = req_attributes
 
  # attributes              = req_attributes
Line 183: Line 191:
 
  #organizationalUnitName  = My Department Name
 
  #organizationalUnitName  = My Department Name
 
  commonName              = OpenVPN-CA
 
  commonName              = OpenVPN-CA
  #emailAddress            = hostmaster@example.org       # email in DN is deprecated, use subjectAltName
+
  #emailAddress            = hostmaster@example.org   # email in DN is deprecated, use subjectAltName
 
   
 
   
 
  [ req_cert_extensions ]
 
  [ req_cert_extensions ]
Line 189: Line 197:
 
  subjectAltName          = email:hostmaster@example.org
 
  subjectAltName          = email:hostmaster@example.org
  
Traditionally, the email address was part of the distinguished name, like so:
+
Note that in the above examples, the [[Email in certificates|email address is specified in the subjectAltName]], instead of in the distinguished name. This is in accordance with PKIX standards.
Subject: C=NL, O=MyOrganisation, CN="www.example.org", emailAddress=hostmaster@example.org
+
  
However, RFC 3850 (section 3) specifies that nowadays:
+
== Build CA certificate ==
:The email address SHOULD be in the subjectAltName extension, and SHOULD NOT be in the subject distinguished name.
+
 
+
Like so:
+
Subject: C=NL, O=MyOrganisation, CN="www.example.org"
+
X509v3 extensions:
+
    X509v3 Subject Alternative Name:
+
        email:hostmaster@example.org
+
 
+
In the above request, the email is already specified in the request. The SubjectAltName (and all other extensions) are copied by this setting:
+
copy_extensions = copy
+
 
+
An alternative is to specify the email address in the distinguished name (DN) in the request, but copy or move it to the subjectAltName by one of these two settings:
+
subjectAltName=email:copy
+
subjectAltName=email:move
+
 
+
=== Build CA certificate ===
+
  
 
(roughly equivalent to <code>easy-rsa/build-ca</code> or <code>pkitool --interact --initca</code>)
 
(roughly equivalent to <code>easy-rsa/build-ca</code> or <code>pkitool --interact --initca</code>)
Line 229: Line 220:
 
  cp ca/ca.crt client2/
 
  cp ca/ca.crt client2/
  
=== Generate Prime Numbers ===
+
== Generate Prime Numbers ==
  
 
(roughly equivalent to <code>build-dh</code>)
 
(roughly equivalent to <code>build-dh</code>)
Line 236: Line 227:
 
  openssl dhparam -out dh2048.pem 2048
 
  openssl dhparam -out dh2048.pem 2048
  
=== Build server certificate ===
+
== Build server certificate ==
  
 
(roughly equivalent to <code>build-key-server myserver</code> or <code>pkitool --interact --server myserver</code>)
 
(roughly equivalent to <code>build-key-server myserver</code> or <code>pkitool --interact --server myserver</code>)
  
First create a configuration for the server:
+
First create a configuration for the server, similar to <code>ca.cnf</code>:
  
 
  # server.cnf
 
  # server.cnf
Line 246: Line 237:
 
  [ req ]
 
  [ req ]
 
  default_bits            = 2048
 
  default_bits            = 2048
default_keyfile        = server.key
+
  default_md              = sha2
  default_md              = sha1
+
 
  encrypt_key            = no
 
  encrypt_key            = no
 
  prompt                  = no
 
  prompt                  = no
 +
string_mask            = utf8only
 
  distinguished_name      = server_distinguished_name
 
  distinguished_name      = server_distinguished_name
 
  req_extensions          = req_cert_extensions
 
  req_extensions          = req_cert_extensions
 
  # attributes              = req_attributes
 
  # attributes              = req_attributes
x509_extensions        = usr_cert
 
 
   
 
   
 
  [ server_distinguished_name ]
 
  [ server_distinguished_name ]
 
  countryName            = NL
 
  countryName            = NL
 
  #stateOrProvinceName    = Utrecht
 
  #stateOrProvinceName    = Utrecht
  localityName            = Breukelen
+
  localityName            = HomeTown
  organizationName        = MacFreek
+
  organizationName        = My Organisation
 
  #organizationalUnitName  = My Department Name
 
  #organizationalUnitName  = My Department Name
  commonName              = gateway.macfreek.nl
+
  commonName              = vpnserver.example.org
  emailAddress            = hostmaster@macfreek.nl
+
  emailAddress            = hostmaster@example.org
 
   
 
   
 
  [ req_cert_extensions ]
 
  [ req_cert_extensions ]
 
  nsCertType              = server
 
  nsCertType              = server
+
  subjectAltName          = email:hostmaster@example.org
[ v3_ca ]
+
  subjectAltName          = email:hostmaster@macfreek.nl
+
  
 
Create the server request and private key:
 
Create the server request and private key:
Line 278: Line 266:
 
  cp server/server.req ca/
 
  cp server/server.req ca/
 
  cd ca
 
  cd ca
  openssl ca -config -extensions X509_server ca.cnf -in server.req -out server.crt
+
  openssl ca -config ca-sign.cnf -extensions X509_server -in server.req -out server.crt
  
 
Copy server.crt to the client machine.
 
Copy server.crt to the client machine.
Line 287: Line 275:
 
If you have multiple servers, repeat this step for all servers.
 
If you have multiple servers, repeat this step for all servers.
  
=== Build client certificate ===
+
== Build client certificate ==
  
 
(roughly equivalent to <code>pkitool --interact --csr myclient</code>)
 
(roughly equivalent to <code>pkitool --interact --csr myclient</code>)
 +
 +
Create a <code>client1.cnf</code> similar to <code>server.cnf</code>:
 +
 +
# client1.cnf
 +
# This configuration file is used by the 'req' command when a certificate is created for client 1.
 +
[ req ]
 +
default_bits            = 2048
 +
default_md              = sha2
 +
encrypt_key            = no
 +
prompt                  = no
 +
string_mask            = utf8only
 +
distinguished_name      = client1_distinguished_name
 +
req_extensions          = req_cert_extensions
 +
# attributes              = req_attributes
 +
 +
[ client1_distinguished_name ]
 +
countryName            = NL
 +
#stateOrProvinceName    = Utrecht
 +
localityName            = HomeTown
 +
organizationName        = My Organisation
 +
#organizationalUnitName  = My Department Name
 +
commonName              = client1.example.com
 +
 +
[ req_cert_extensions ]
 +
nsCertType              = client
 +
subjectAltName          = email:hostmaster@example.com
  
 
On the client machine
 
On the client machine
 +
cd client1/
 
  openssl req -new -config client1.cnf -keyout client1.key -out client1.req
 
  openssl req -new -config client1.cnf -keyout client1.key -out client1.req
  chmod go-rw client1.key
+
  chmod 400 client1.key
  
 
Copy client1.req to the CA machine, and run on the CA machine:
 
Copy client1.req to the CA machine, and run on the CA machine:
  openssl ca -config ca.cnf -out client1.crt -in client1.req
+
cp client1/client1.req ca/
 +
cd ca/
 +
  openssl ca -config ca-sign.cnf -out client1.crt -in client1.req
  
Copy client1.crt to the client machine.
+
Copy client1.crt to the client machine:
 +
cp ca/client1.crt client1/
  
 
You can delete client1.req. Only client1.crt and client1.key are required on the client.
 
You can delete client1.req. Only client1.crt and client1.key are required on the client.
Line 304: Line 322:
 
Repeat this step for all client hosts.
 
Repeat this step for all client hosts.
  
=== Revoke a client certificate ===
+
== Revoke a client certificate ==
 
+
If the file does not exist, create the crlnumber with a serial number:
if the file crlnumber does not exist:
+
 
  echo '0000000000000001' > crlnumber
 
  echo '0000000000000001' > crlnumber
  
  openssl ca -config ca.cnf -crl_reason superseded -revoke 5FE840894254A22.crt
+
  openssl ca -config ca-sign.cnf -crl_reason superseded -revoke 5FE840894254A22.crt
  openssl ca -config ca.cnf -gencrl -out crl.pem
+
  openssl ca -config ca-sign.cnf -gencrl -out crl.pem
  
 
where the reason is one of the following
 
where the reason is one of the following
Line 321: Line 338:
 
* certificateHold
 
* certificateHold
  
Test if you receive an error (code 23):
+
Test the revocation:
 
+
 
  cat ca.crt crl.pem > revoke-test.pem
 
  cat ca.crt crl.pem > revoke-test.pem
 
  openssl verify -CAfile revoke-test.pem -crl_check 5FE840894254A22.crt
 
  openssl verify -CAfile revoke-test.pem -crl_check 5FE840894254A22.crt
 +
 +
If the certificate is revoked, you should get the error
 +
error 23 at 0 depth lookup:certificate revoked
 +
 +
Be sure to distribute the certificate revocation list to your server and clients.
 +
 +
cp ca/crl.pem server/
 +
cp ca/crl.pem client1/
 +
cp ca/crl.pem client2/
 +
 +
== Change password ==
 +
 +
To change the password of your private key:
 +
openssl rsa -des3 -in ca.key -out ca_new.key
 +
mv ca_new.key ca.key
 +
 +
[[Category:Network Tunnel]]
 +
[[Category:Certificates]]

Latest revision as of 00:14, 3 November 2015

Part of configuring OpenVPN involves the creation of a certificate authority (CA), also known as a public key infrastructure (PKI) (the public refers to public-key cryptography). You can not use an existing public key infrastructure; you would allow anyone with a certificate of that PKI to connect to your server (the tls-remote and tls-verify options can limit the allowed clients). You either need to set up your own certificate infrastructure, or limit OpenVPN to use password-based authentication (see the options auth-user-pass-verify, client-cert-not-required and username-as-common-name).

The easiest method it to use easy-rsa, as described in the OpenVPN How-to.

This article describes the steps taken by easy-rsa in more detail, but basically gives the same result. This article is partly based on the excellent tutorial by Phil Dibowitz on creating an CA.

Certificates, when deployed correctly, are much more secure than passwords, since the secret (key) does not need to be exchanged or shared between the different hosts. However, doing so requires a security hygiene which may not be required for a small-scale deployment.

Files

The following files are used by OpenSSL:

Filename Needed by Purpose Secret
ca.cnf CA CA configuration of its common name (CN) No
ca-sign.cnf CA CA configuration for Signing No
ca.key CA Root CA key Yes
ca.crt CA + server + all clients Root CA certificate No
index.txt CA List of all signed certificates No
serial CA First free serial number of certificates No
crl.pem CA + server (+ all clients) Certificate revokation list No
crlnumber CA First free serial number of CRLs No
.rand CA Root CA certificate Yes?
dh2048.pem server only Diffie Hellman parameters No
server.cnf server only during certificate generation Server configuration No
client1.req CA only during certificate generation Client1 certificate signing request No
server.key server only Server key Yes
server.crt server only Server certificate No
client1.cnf client 1 only during certificate generation Client 1 configuration No
client1.req CA only during certificate generation Client1 certificate signing request No
client1.key client 1 only Client1 key Yes
client1.crt client 1 only Client1 certificate No
client2.cnf client 2 only during certificate generation Client 2 configuration No
client2.req CA only during certificate generation Client2 certificate signing request No
client2.key client 2 only Client2 key Yes
client2.crt client 2 only Client2 certificate No

I'll use these directories to denote the files that are required on different host:

Directory Needed by
ca CA
server server
client1 client 1
client2 client 2

This is a compromise between the completely flat file structure of easy-rsa, and the recommendations set forth by most CA tutorials, which creates directories for certificate requests (.req), signed certificates (.crt), certificate revokations (crl), and private keys (ca.key).

If you are some paranoid whacko serious about security, you should not run these commands on the same machine, but run commands in the server, client1, and client2 directory of respectively the server and client machines, and run commands in the CA directory on a machine that is not connected to the Internet.

Initialize

(roughly equivalent to easy-rsa/clean-all)

mkdir ca server client1 client2
cd ca
touch index.txt

CA Configuration Files

Create configuration files. In our setup, ca-sign.cnf contains the configuration for signing certificates. We only use it in conjunction with the openssl ca command. It described the folder structure within the ca directory, the location of support files for the CA, as well as properties of the signed certificates (duration, restricted usage) as well as the policy for the name ("distinguished name") of signed certificates. Finally, it lists the policy for certification revocation lists. For this small-scale CA, there is no public URL to download the CRL; I plan to distribute it manually.

# ca-sign.cnf
# This configuration file is used by the 'ca' command, to create signed certificates.
[ ca ]
default_ca              = CA_default            # The default ca section

[ CA_default ]
dir                     = /path/to/ca           # Where everything is kept
certs                   = $dir/                 # Where the issued certs are kept
crl_dir                 = $dir/                 # Where the issued crl are kept
new_certs_dir           = $dir/                 # default place for new certs

private_key             = $dir/ca.key           # The private key
certificate             = $dir/ca.crt           # The CA root certificate
database                = $dir/index.txt        # List of signed certificates
serial                  = $dir/serial           # The current serial number
crlnumber               = $dir/crlnumber        # the current crl number
crl                     = $dir/crl.pem          # The current CRL
RANDFILE                = $dir/.rand            # private random number file

unique_subject          = no                    # allow multiple certificates with same subject.
default_md              = sha2                  # Use hash algorithm specified in the request
default_days            = 730                   # client certificates last 2 years
default_crl_days        = 30                    # How often clients should download the CRL

#x509_extensions         = X509_ca               # The x509 extensions for the root certificate
#x509_extensions         = X509_server           # The x509 extensions for a server certificate
x509_extensions         = X509_client           # The x509 extensions for a client certificate

# These options control what fields from the distinguished name to show before signing.
# They are required to make sure all fields are shown.
name_opt                = ca_default            # Subject Name options
cert_opt                = ca_default            # Certificate field options

copy_extensions         = copy                  # Accept requested extensions

policy                  = policy_dn

[ X509_ca ]
# X509v3 extensions for the root certificate
basicConstraints        = CA:TRUE
nsCertType              = sslCA                 # restrict the usage
keyUsage                = keyCertSign, cRLSign  # restrict the usage
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always,issuer:always
#subjectAltName          = email:move            # Move email address from DN to extensions
#crlDistributionPoints   = URI:http://www.example.com/example_ca.crl

[ X509_server ]
# X509v3 extensions for server certificates
basicConstraints        = CA:FALSE
nsCertType              = server                # restrict the usage
keyUsage                = digitalSignature, keyEncipherment
extendedKeyUsage        = serverAuth            # restrict the usage
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid,issuer
#subjectAltName          = email:move            # Move email address from DN to extensions
#crlDistributionPoints   = URI:http://www.example.com/example_ca.crl

[ X509_client ]
# X509v3 extensions for client certificates
basicConstraints        = CA:FALSE
nsCertType              = client                # restrict the usage
keyUsage                = digitalSignature      # restrict the usage
extendedKeyUsage        = clientAuth            # restrict the usage
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid,issuer
#subjectAltName          = email:move            # Move email address from DN to extensions
#crlDistributionPoints   = URI:http://www.example.com/example_ca.crl

[ policy_dn ]
countryName             = supplied              # required parameter, any value allowed
stateOrProvinceName     = optional
localityName            = optional
organizationName        = match                 # required, and must match root certificate
organizationalUnitName  = optional
commonName              = supplied              # required parameter, any value allowed
emailAddress            = optional              # email in DN is deprecated, use subjectAltName

The x509_extensions sections are not really required by openssl or openvpn, but allows extra security by telling OpenVPN that clients only may connect to servers only. nsCertType is required for the OpenVPN option ns-cert-type server|client; keyUsage and extendedKeyUsage are required for remote-cert-tls server|client.

ca.cnf defines the distinguished name for the certificate authority. It also contains the key length (2048 is recommended nowadays, over the default of 1024), and if the key should be encrypted.

# ca.cnf
# This configuration file is used by the 'req' command when the root certificates is created.
[ req ]
default_bits            = 2048                  # default strength of client certificates
default_md              = sha2
encrypt_key             = yes                   # "no" is equivalent to -nodes
prompt                  = no
string_mask             = utf8only
distinguished_name      = ca_distinguished_name     # root certificate name
req_extensions          = req_cert_extensions
# attributes              = req_attributes

[ ca_distinguished_name ]
# root certificate name
countryName             = NL
#stateOrProvinceName    = Utrecht
localityName            = Hometown
organizationName        = My Organisation
#organizationalUnitName  = My Department Name
commonName              = OpenVPN-CA
#emailAddress            = hostmaster@example.org   # email in DN is deprecated, use subjectAltName

[ req_cert_extensions ]
# nsCertType              = server
subjectAltName          = email:hostmaster@example.org

Note that in the above examples, the email address is specified in the subjectAltName, instead of in the distinguished name. This is in accordance with PKIX standards.

Build CA certificate

(roughly equivalent to easy-rsa/build-ca or pkitool --interact --initca)

If your CA should be valid after the year 2038, be sure to use openssl 0.9.9 or higher.

First create a request with the correct name, and then self-sign a certificate and create a serial number file.

cd ca
openssl req -new -config ca.cnf -keyout ca.key -out ca.req
openssl ca -config ca-sign.cnf -extensions X509_ca -days 3650 -create_serial -selfsign \
    -keyfile ca.key -in ca.req -out ca.crt
chmod 400 ca.key
chmod 444 ca.crt

These actions create ca.key and ca.crt. ca.key should be kept secret. ca.crt should be distributed to all servers and clients.

cp ca/ca.crt server/
cp ca/ca.crt client1/
cp ca/ca.crt client2/

Generate Prime Numbers

(roughly equivalent to build-dh)

cd server
openssl dhparam -out dh2048.pem 2048

Build server certificate

(roughly equivalent to build-key-server myserver or pkitool --interact --server myserver)

First create a configuration for the server, similar to ca.cnf:

# server.cnf
# This configuration file is used by the 'req' command when the server certificate is created.
[ req ]
default_bits            = 2048
default_md              = sha2
encrypt_key             = no
prompt                  = no
string_mask             = utf8only
distinguished_name      = server_distinguished_name
req_extensions          = req_cert_extensions
# attributes              = req_attributes

[ server_distinguished_name ]
countryName             = NL
#stateOrProvinceName    = Utrecht
localityName            = HomeTown
organizationName        = My Organisation
#organizationalUnitName  = My Department Name
commonName              = vpnserver.example.org
emailAddress            = hostmaster@example.org

[ req_cert_extensions ]
nsCertType              = server
subjectAltName          = email:hostmaster@example.org

Create the server request and private key:

cd server
openssl req -new -config server.cnf -keyout server.key -out server.req
chmod 400 server.key

Copy server.req to the CA machine, and run on the CA machine:

cp server/server.req ca/
cd ca
openssl ca -config ca-sign.cnf -extensions X509_server -in server.req -out server.crt

Copy server.crt to the client machine.

cp ca/server.crt server/

You can delete server.req. Only server.crt and server.key are required on the server.

If you have multiple servers, repeat this step for all servers.

Build client certificate

(roughly equivalent to pkitool --interact --csr myclient)

Create a client1.cnf similar to server.cnf:

# client1.cnf
# This configuration file is used by the 'req' command when a certificate is created for client 1.
[ req ]
default_bits            = 2048
default_md              = sha2
encrypt_key             = no
prompt                  = no
string_mask             = utf8only
distinguished_name      = client1_distinguished_name
req_extensions          = req_cert_extensions
# attributes              = req_attributes

[ client1_distinguished_name ]
countryName             = NL
#stateOrProvinceName    = Utrecht
localityName            = HomeTown
organizationName        = My Organisation
#organizationalUnitName  = My Department Name
commonName              = client1.example.com

[ req_cert_extensions ]
nsCertType              = client
subjectAltName          = email:hostmaster@example.com

On the client machine

cd client1/
openssl req -new -config client1.cnf -keyout client1.key -out client1.req
chmod 400 client1.key

Copy client1.req to the CA machine, and run on the CA machine:

cp client1/client1.req ca/
cd ca/
openssl ca -config ca-sign.cnf -out client1.crt -in client1.req

Copy client1.crt to the client machine:

cp ca/client1.crt client1/

You can delete client1.req. Only client1.crt and client1.key are required on the client.

Repeat this step for all client hosts.

Revoke a client certificate

If the file does not exist, create the crlnumber with a serial number:

echo '0000000000000001' > crlnumber
openssl ca -config ca-sign.cnf -crl_reason superseded -revoke 5FE840894254A22.crt
openssl ca -config ca-sign.cnf -gencrl -out crl.pem

where the reason is one of the following

  • unspecified
  • keyCompromise
  • CACompromise
  • affiliationChanged
  • superseded
  • cessationOfOperation
  • certificateHold

Test the revocation:

cat ca.crt crl.pem > revoke-test.pem
openssl verify -CAfile revoke-test.pem -crl_check 5FE840894254A22.crt

If the certificate is revoked, you should get the error

error 23 at 0 depth lookup:certificate revoked

Be sure to distribute the certificate revocation list to your server and clients.

cp ca/crl.pem server/
cp ca/crl.pem client1/
cp ca/crl.pem client2/

Change password

To change the password of your private key:

openssl rsa -des3 -in ca.key -out ca_new.key
mv ca_new.key ca.key