There is a handy script distributed alongside openssl, CA.sh
to do most of this stuff. Its location is distribution specific. In Debian and derivatives you can locate it using:
# apt-file search CA.sh
openssl: /usr/lib/ssl/misc/CA.sh
And RedHat and derivatives the (approximate) equivalent is:
# yum provides */CA
1:openssl-1.0.1e-4.fc18.x86_64 : Utilities from the general purpose cryptography library with TLS implementation
Repo : @updates
Matched from:
Filename : /etc/pki/tls/misc/CA
This is a very simple bash script that eases the creation of the directory structure needed to manage a CA (this is described in the [ CA_default ]
section of openssl.cnf). I recommend you to use it and look at the code to learn what it is actually doing.
# ./CA.sh -help
usage: ./CA.sh -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify
This script will use the defaults provided in openssl.cnf, and/or you can provide one configuration file as an argument to the openssl $command
using the -config
switch if not using CA.sh
.
The location of the openssl.cnf
file is also distribution specific, and you can use the same commands above to find it. The one you want is the one provided by the openssl
package.
You probably want to modify the following sections:
[ CA_default ]
default_days = 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
[ req ]
default_bits = 2048
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = AU
countryName_min = 2
countryName_max = 2
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Some-State
localityName = Locality Name (eg, city)
0.organizationName = Organization Name (eg, company)
0.organizationName_default = Internet Widgits Pty Ltd
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd
organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 64
Once you have edited openssl.cnf
to match your needs, you can generate a CA certificate. Depending on whether you need this CA signed by an recognized third-party CA or not, you can generate a self-signed CA or a CSR to be submitted for signing.
./CA.sh -newca
You will be interactively prompted to ask some questions, the defaults will appear between square brackets. You will recognize the options you modified in openssl.cnf
here.
- Generate a certificate for the server
You can create a certificate request for the server using the same script:
./CA.sh -newreq
Again, you will be prompted to ask several questions, the most important is the Common Name of the certificate, which must match the DNS resolvable name for the IP of the server (or you can use other means, like /etc/hosts
, not recommended, hard to maintain and scale)
What you will obtain is a Certificate Signing Request (CSR for short). This will be signed by the Certificate Authority (CA) you created before.
./CA.sh -sign
- Generate certificates for the clients
Repeat the steps of creating a CSR and getting it signed by the CA. When doing so, pay close attention to how you fill in the Common Name, Organization and Organizational Unit fields, as those will be required afterwards in order to configure the server.
A neat way to distribute the client certificates alongside their respective private keys and the CA certificate is using p12 bundles:
openssl pkcs12 -export -in Certificates/client.pem -inkey client.key -certfile CA.pem
-out clientcert.p12
Let's suppose the server you are referring to is an Apache web server. Once you have the server certificate, you configure the appropriate VHOST
to serve whatever content is going to be protected by mutual SSL authentication. An example could be this phpmyadmin
virtual hosts. This is working in an Apache 2.4 server, so please don't use it as-is and carefully review and test it to adapt it to your needs.
Listen 443 https
<VirtualHost 120.120.120.120:443>
DocumentRoot "/srv/www/html"
ServerAdmin [email protected]
SSLCACertificateFile /etc/pki/CA/cacert.pem
SSLCertificateFile /etc/pki/tls/private/phpmyadmin.company.com/newcert.pem
SSLCertificateKeyFile /etc/pki/tls/private/phpmyadmin.company.com/newkey.pem
SSLCARevocationCheck chain
SSLCARevocationFile /etc/pki/CA/crl/crl.pem
SSLEngine on
SSLStrictSNIVHostCheck on
SSLVerifyClient require
SSLVerifyDepth 5
ServerName phpmyadmin.company.com
RewriteEngine on
RewriteCond %{REMOTE_ADDR} !^127\.0\.0\.1$
RewriteCond %{HTTPS} !=on
RewriteRule . - [F]
Alias /console /usr/share/phpMyAdmin
ErrorLog "|/usr/sbin/rotatelogs -L /var/log/httpd/phpmyadmin/error.log -f /var/log/httpd/phpmyadmin/error.log.%Y%m%d 86400"
CustomLog "|/usr/sbin/rotatelogs -L /var/log/httpd/phpmyadmin/access.log -f /var/log/httpd/phpmyadmin/access.log.%Y%m%d 86400" logstash_json
<Directory /usr/share/phpMyAdmin/>
Require ssl
Require ssl-verify-client
SSLRequireSSL
SSLOptions +FakeBasicAuth +StrictRequire
SSLRequire %{SSL_CIPHER_USEKEYSIZE} >= 256
SSLRequire %{SSL_CLIENT_S_DN_O} eq "Awesome Company" \
and %{SSL_CLIENT_S_DN_OU} eq "Development" \
and %{SSL_CLIENT_S_DN_CN} in {"John Doe", "Jane Doe"}
SSLRenegBufferSize 131072
</Directory>
</VirtualHost>
You can use as many per-directory access control as you need, the important part is that the client certificates shown must comply with the restrictions imposed by the SSLRequire
directives, i.e., they must match the Organization, Organizational Unit and Common Name conditions (or other fields of the certificate as you see fit). These fields are taken from the client certificates.
- Generate a Certificate Revocation List
In order to be able to revoke access to a client certificate, you need to generate a CRL.
The command to do it (provided you in the top of the CA directory structure):
openssl ca -config /path/to/openssl.cnf -gencrl -out crl/crl.pem
Afterwards, you revoke client certs as needed using:
openssl ca -config /path/to/openssl.cnf -revoke clientcert.pem
References:
OpenSSL online documentation and Apache online documentation.