Configuring two-way authentication SSL with Apache

A common way to protect a server from the access of malicious is to identify the client; in my opinion, the best way to do that is the mutual SSL authentication. To understand what is the mutual SSL Authentication and other good practices for the protection of an endpoint you can read this article.
You can implement two-way authentication SSL using a WEB Server, for this example I used apache web server.
In the web there are more abstract examples of configuring two-way authentication SSL with Apache for development environment, but no one has a complete example. I hope this is quite complete!
Yes, I’m talking about development environment, because usually in this step certificates are self signed and there is much more work to do (you have to simulate a CA and create certificates).

Here there are the three marco steps:

  1. Create the server certificate
  2. Create the client certificate and the PKCS12 container
  3. Configure the apache web server

1. Create the server certificate

Before creating a certificate, you have to create a CA:
Create the structure directory and protect from other users:
mkdir ssl
chmod 0700 ssl
cd ssl
mkdir certs private
Create a database to keep track of each certificate signed:
echo '100001' > serial
touch certindex.txt
Make a custom config file for openssl to use:
#
# OpenSSL configuration file.
#

# Establish working directory.

dir = .

[ ca ]
default_ca = CA_default

[ CA_default ]
serial = $dir/serial
database = $dir/certindex.txt
new_certs_dir = $dir/certs
certificate = $dir/cacert.pem
private_key = $dir/private/cakey.key
default_days = 365
default_md = md5
preserve = no
email_in_dn = no
nameopt = default_ca
certopt = default_ca
policy = policy_match

[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional

[ req ]
default_bits = 2048 # Size of keys
default_keyfile = key.pem # name of generated keys
default_md = md5 # message digest algorithm
string_mask = nombstr # permitted characters
distinguished_name = req_distinguished_name
req_extensions = v3_req

[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = IT
countryName_min = 2
countryName_max = 2

stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Italy

localityName = Locality Name (eg, city)
localityName_default = Milan

0.organizationName = Organization Name (eg, company)
0.organizationName_default = Organization default

# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd

organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Organization unit name default

commonName = Common Name (eg, YOUR name)
commonName_max = 64
commonName_default = www.stefanocapitanio.com

emailAddress = Email Address
emailAddress_max = 64

# SET-ex3 = SET extension number 3

[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20

unstructuredName = An optional company name

[ req_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = IT
countryName_min = 2
countryName_max = 2

stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Italy

localityName = Locality Name (eg, city)

0.organizationName = Organization Name (eg, company)
0.organizationName_default = Organization default

# we can do this but it is not needed normally :-)
#1.organizationName = Second Organization Name (eg, company)
#1.organizationName_default = World Wide Web Pty Ltd

organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = Organization unit default

commonName = Common Name (eg, YOUR name)
commonName_max = 64
commonName_default = www.stefanocapitanio.com

emailAddress = Email Address
emailAddress_max = 64

# SET-ex3 = SET extension number 3

[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20

unstructuredName = An optional company name
[ v3_ca ]
basicConstraints = CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always

[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
Create root certificate:
openssl req -new -x509 -extensions v3_ca -keyout private/cakey.key -out cacert.pem -days 365 -config ./openssl.cnf
This script will create private/cakey.key  that is the private key of the CA and the cacert.pem that is the  which is the one you can give to others for import in their browsers.
Create a key and signing request for the server
openssl req -new -nodes -out server-req.pem -keyout private/server-key.key -days 365 -config ./openssl.cnf
The output of this script is server-req.pem that is the CSR and the private/server-key.key that is the private key
Sign the request
openssl ca -out server-cert.pem -days 365 -config ./openssl.cnf -infiles server-req.pem
This will produce server-cert.pem that is the public certificate

2. Create the client certificate and the PKCS12 container

Create a key and signing request for each client
openssl req -new -nodes -out client-req.pem -keyout private/client-key.key -days 365 -config ./openssl.cnf
*on the common name you have to specify a different name
Sign each request
openssl ca -out name-cert.pem -days 365 -config ./openssl.cnf -infiles client-req.pem
Create the PKCS12 file
openssl pkcs12 -export -in name-cert.pem -inkey private/client-key.key -certfile cacert.pem -name "[friendly name]" -out name-cert.p12
The produced file is the file that the server will require to comunicate, and you have to install on the client

3. Configure APACHE

After installing and configuring apache and enabling SSL, you can get a VirtualHost and configure them:
<VirtualHost *:7001>
  ServerAdmin name@yourdomain.com
  SSLEngine on
  SSLCertificateFile /home/sempla1/ssl/server-cert.pem
  SSLCertificateKeyFile /home/sempla1/ssl/private/server-key.pem

  SSLVerifyClient require
  SSLVerifyDepth 10
  SSLCACertificateFile /home/sempla1/ssl/cacert.pem
  <location />
    Order allow,deny
    allow from all
    SSLRequire (%{SSL_CLIENT_S_DN_CN} eq "clientcn")
 </location>
  ProxyPass / http://127.0.0.1:8080/
  ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>

One-way  (standard) SSL auth configuration:

SSLEngine on -> to enable the single way SSL authentication
SSLCertificateFile -> to specify the public certificate that the WebServer will show to the users
SSLCertificateKeyFIle -> to specify the private key that will be used to encrypt the data sent
Note: You need to import cacert to client browser to make it trust seft sign certificate.

Two-way SSL auth configuration:

SSLVerifyClient -> to enable the two-way SSL authentication
SSLVerifyDepth -> to specify the depth of the check if the certificate has an approved CA
SSLCACertificateFile -> the public key that will be used to decrypt the data recieved
SSLRequire -> Allows only requests that satisfy the expression
 Ok, now you are ready to test the two-way SSL authentication in your browser: install the client certificate (.p12 file) and add the CA in the trusted CA (to avoid the alert on the not secure https connection).
 A big thank you to www.flatmtn.com, I used its guides to start creating CA, keys and certificates.

https://jamielinux.com/docs/openssl-certificate-authority/index.html

Nhận xét

Bài đăng phổ biến