Blog di Bernardino (Dino) Ciuffetti

13 Mag 21 How to create a Certification Authority with CRL, OCSP and SAN on OpenSSL

Anyone knows that OpenSSL is a very cool full featured, free and open source SSL/TLS framework and toolkit but few people use it to create a custom Private Certification Authority.

The reasons to create a Private CA are many, but they are out of scope here, so I’ll just say how to achieve the goal.

First you must create a personalized version of my openssl.conf configuration file. You can safely do it modifing this labels below and running this one, on a single line:

# C="IT"; ST="Italy"; L="Rome"; O="My org"; OU="My Unit"; CN="My CA"; eml=""; CABASEDIR="/tmp/B"; DD=730; mkdir -p "$CABASEDIR"; cd "$CABASEDIR"; echo 'H4sIAGM8nWACA7VVbYvjNhD+rl8hCIYuhOx2r3fQFMOlyRbChc2SXD4cIQRFmsTq
JUB7lClBc8zXb0L5HW5PtdefPC+Hx+NxkGjrfIgA1AL5CyDty6++CQAA' | openssl base64 -d | gunzip |sed "s/%C%/$C/g"|sed "s/%ST%/$ST/g"|sed "s/%L%/$L/g"|sed "s/%O%/$O/g"|sed "s/%OU%/$OU/g"|sed "s/%eml%/$eml/g"|sed "s|%CABASEDIR%|$CABASEDIR|g"|sed "s/%DD%/$DD/g" > openssl.conf

So, those labels must be modified to your needs:

C="IT"; ST="Italy"; L="Rome"; O="My org"; OU="My Unit"; eml="" CABASEDIR="/tmp/B"; DD=730

where C is your Country, ST is your State or Province name, L is locality, O is organization, OU is organization unit, eml is your CA email (if any), CABASEDIR is the directory that will hold all your CA stuff (private keys, certificates, config files, certificate serials and ca db) and DD is your default certificate validity in days.

At this time you should have a file called openssl.conf into your CABASEDIR directory.

As an alternative, you could directly copy and modify the openssl.conf file here.

Next, you obviously need to create the private key and self sign the certificate of your brand new CA, in this example we’ll create a clear RSA private key with 4096 bit encryption length, and a CA certificate that is valid for about 10 years. You mileage may vary, feel free to customize things:

# openssl genrsa -out ca.key 4096
# openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -extensions 'v3_ca' -config openssl.conf

This way you’ll get a clear (not encrypted) private key, so a password is not needed when you’ll going to use it to sign things, generate new certificates, etc. btw, for security reasons, you may need to encrypt your PK with a passphrase. In that case, add -des attribute to your openssl genrsa command. Also you’ll have your precious CA certificate.
Choose a cool CN for your CA Name.

Now it’s time to create a large random number that will be used by OpenSSL as a starting point for your certificates’ Serial Numbers. You can create a large random number with this one (you could also create one by hand…):

# hexdump -n 20 -e '20/1 "%02X" 1 "\n"' /dev/random > certs.seq

Perfect. Now proceed creating an empty file called certs.db:

# touch certs.db

Also create a starting serial number for revoked certificates and an empty CRL:

# echo 00 > crlserial
# openssl ca -config openssl.conf -keyfile ca.key -cert ca.crt -gencrl -out crl.pem 
Using configuration from openssl.conf

At this point, you should have something like this:

# ls -lrth
totale 16K
-rw-r--r-- 1 dino dino 1,5K mag 5 20:06 openssl.conf
-rw------- 1 dino dino 3,2K mag 5 20:06 ca.key
-rw-r--r-- 1 dino dino 2,0K mag 5 20:07 ca.crt
-rw-r--r-- 1 dino dino 41 mag 5 20:07 certs.seq
-rw-r--r-- 1 dino dino 3 mag 5 20:08 crlserial
-rw-r--r-- 1 dino dino 999 mag 5 20:08 crl.pem
-rw-r--r-- 1 dino dino 0 mag 5 20:08 certs.db

Well. Now we can start creating our server (or client) certificates.
We start from its private key (here at 2048 bit but you can choose your own key length):

# openssl genrsa -out server.key 2048

And now the certificate:

# openssl req -new -key server.key -out server.csr -extensions 'v3_req' -config openssl.conf
# openssl ca -cert ca.crt -keyfile ca.key -in server.csr -out server.crt -config openssl.conf

If you don’t want to use the default certificates expiry days setted into openssl.conf (param default_days), you can pass the -days attribute to the last command, for example -days 365.
When asked, pay attention to correctly set all the requested attributes, principally the Common Name. Press Y when asked to sign and commit.

If everything gone OK you’ll have your brand new key and certificate:

# ls -lrth server.*
-rw------- 1 dino dino 1,7K mag 5 22:26 server.key
-rw-r--r-- 1 dino dino 1,2K mag 5 22:26 server.csr
-rw-r--r-- 1 dino dino 5,7K mag 5 22:28 server.crt

You can check the certificate with this command:

# openssl x509 -in server.crt -noout -text

Please note that the new certificate is signed by our CA, and also has the following useful properties:

    X509v3 extensions:
        X509v3 Key Usage: 
            Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
        X509v3 Basic Constraints: 
        X509v3 Extended Key Usage: 
            TLS Web Server Authentication, TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption

Also note that the generated certificate is valid for both Server and Client purposes and has a X509v3 CRL Distribution Points extension that points to URI: please change this value inside your openssl.conf before generating the CA certificate. This is where you’ll publish your CRL.

As an added bonus, you could also add SANs (Subject Alternative Names) to your certificate, if you like. This permits you to have cool certificates like wildcard domains, multiple domains and IP address on your certificates.

To add a SAN you can modify the last line of openssl.conf configuration file, so that you can include your SANs. For example:

# To add SAN uncomment the # and personalize

and create your CSR and certificate like done above (but first remember to revoke or manually remove the certificate from certs.db or you’ll get the “ERROR:There is already a certificate for…” error):

# openssl req -new -key server.key -out server.csr -extensions 'v3_req' -config openssl.conf
# openssl ca -cert ca.crt -keyfile ca.key -in server.csr -out server.crt -config openssl.conf

To revoke a certificate (in this example is called 792FCB9AE9BBBFFAE33796CF3D1D0D7B6AF399DF.pem) you can simply do this (this will set the given certificate as revoked into the certs.db file):

# openssl ca -config openssl.conf -keyfile ca.key -cert ca.crt -revoke 792FCB9AE9BBBFFAE33796CF3D1D0D7B6AF399DF.pem -crl_reason unspecified
Using configuration from openssl.conf
Revoking Certificate 792FCB9AE9BBBFFAE33796CF3D1D0D7B6AF399DF.
Data Base Updated

After that you need to update the CRL with all the revoked certificates inside. Also, remember to refresh the CRL with the same command almost every default_crl_days (check openssl.conf) even if no certificates are revoked or your CRL will expire:

# openssl ca -config openssl.conf -keyfile ca.key -cert ca.crt -gencrl -updatedb -out crl.pem

At this poin you might want to arrange your OCSP responder with its key and certificate.

Please note that the configuration of OCSP Stapling or responder is out of scope in this article, we just realized how to create its certificates with OpenSSL. If you don’t need OCSP on your certificates, left commented out the authorityInfoAccess attribute in openssl.conf and skip this last step, btw I can tell you, as a testing purposes, how to create a OCSP test responder:

# openssl genrsa -out ocsp.key 2048
# openssl req -new -key ocsp.key -out ocsp.csr -extensions 'v3_req' -config openssl.conf
# openssl ca -cert ca.crt -keyfile ca.key -in ocsp.csr -out ocsp.crt -extensions ocsp -config openssl.conf

When you create the OCSP certificate, keep in mind that the common name must match the OCSP;URI.0 attribute defined into the [ocsp_info] section of your openssl.conf.

# openssl ocsp -index certs.db -port 9999 -rsigner ocsp.crt -rkey ocsp.key -CA ca.crt
ocsp: waiting for OCSP client connections...

And then, to test:

# openssl ocsp -issuer ca.crt -CAfile ca.crt -cert server.crt -url http://ocsp:9999
Response verify OK
server.crt: good
	This Update: May 13 15:10:17 2021 GMT

Now, we try to revoke the server certificate, just for test:

openssl ca -config openssl.conf -keyfile ca.key -cert ca.crt -revoke server.crt -crl_reason unspecified
Using configuration from openssl.conf
Adding Entry with serial number 2DE87D684C64D0BB4B23D0BC9959B8EB23AF932F to DB for /C=IT/ST=Italy/L=Rome/O=My org/OU=My Unit/CN=myserver/
Revoking Certificate 2DE87D684C64D0BB4B23D0BC9959B8EB23AF932F.
Data Base Updated

We must also update our CRL and check if the revoked certificate is inserted into our CRL:

# openssl ca -config openssl.conf -keyfile ca.key -cert ca.crt -gencrl -updatedb -out crl.pem                            
Using configuration from openssl.conf
# openssl verify -crl_check -CAfile ca.crt -CRLfile crl.pem server.crt 
C = IT, ST = Italy, L = Rome, O = My org, OU = My Unit, CN = myserver, emailAddress =
error 23 at 0 depth lookup: certificate revoked
error server.crt: verification failed

If we recheck now our OCSP responder:

openssl ocsp -issuer ca.crt -CAfile ca.crt -cert server.crt -url http://ocsp:9999 
Response verify OK
server.crt: revoked
	This Update: May 13 15:23:34 2021 GMT
	Reason: unspecified
	Revocation Time: May 13 15:22:14 2021 GMT

Finaly, the mission is complete!!!!

I spent hours getting this things done!! It’s now time to collect and share back to everybody. Bye!!! Ciao, Dino 🙂

21 Feb 14 HOWTO generate a SAN (Subject Alternative Names) SSL CSR with OpenSSL

There is a cool SSLv3 protocol extension that’s called SAN (Subject Alternative Names). With this extension you can create a single SSL X509 certificate that is valid for several domain names, instead of a classic certificate that’s valid for one domain name only.

You can ofcourse create this kind of certificate with OpenSSL. We are now going to see how to do that.
Fist you have to create a file called openssl.cnf and put it for example into a temporary dir. The file should begin with:

distinguished_name = req_distinguished_name
req_extensions = v3_req

This is to enable SSLv3 req extensions.
Now, you have to add your custom informations to the openssl.cnf file: those informations will be reflected on the next steps.
Add something like this to openssl.cnf:

countryName = Country Name (2 letter code)
countryName_default = IT
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = Italy
localityName = Locality Name (eg, city)
localityName_default = Rome
organizationName = Organization name
organizationName_default = My company name Srl
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = System Techies
commonName = Common Name (eg, YOUR name)
commonName_max = 64
#commonName_default =
emailAddress = Email Address
emailAddress_max = 40

The informations above are used by the “openssl req” command to ask you data to generate your certificate request.
Then, add this block of informations into the openssl.cnf file:

keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names

Those informations will enable some extra useful things on your certificate request that will hopefully became valid on your brand new SSLv3 certificate. For example you are requesting your Certification Authority to release a X509 SSLv3 certificate with server and client authentication purposes, plus other certificate goodies.

Now the cool part: this is where you are asking your CA to release a certificate with Alternative Names (certificate valid for several domains). Append this stuff in openssl.cnf:

DNS.1   =
DNS.2   =
DNS.3   =
# you could also specify IP addresses like this:
# IP.1 =

OK. You are almost ready to create your CSR, but first you have to generate your private key.
NOTE that many CA are now requesting a private key of 2048 bits or more. Warned: a key of 1024 bits is not recommended!
To generate a 2048 bits private key, as usual, execute this command:

openssl genrsa -out server.key 2048

Perfect. It’s time to create the Certificate Request (PKCS#10) with SSLv3 extensions:

openssl req -new -out server.csr -key server.key -config openssl.cnf

Now, send your new server.csr file to your Certification Authority that will hopefully accept the request and relase a valid X509 SSLv3 certificate with SAN.

Good luck and enjoy.

13 Nov 13 Apache HTTPD as 2WAY (mutual) authentication SSL reverse proxy balancer

In this small article I’ll instruct myself (and you too?) how to create a 2 way authentication (mutual authentication) SSL reverse proxy balancer gateway. This configuration is useful in any enterprise environment where it’s requested to separate clients, the frontend and the backend, and when the traffic between clients and the gateway, and between the gateway and the backends must be encrypted.
This also ensure the clients and the backends to be authentic, and avoids Man In The Middle attacks.

Since the reverse proxy is in the middle between the clients and the backends, it’s requested for the clients to send a known client certificate to the gateway (apache), so that the gateway can recognize them. This is done with X509 certificates.
For the same reason, each backend contacted by the gateway is requested to respond with a valid and known server certificate. This is also done with X509 certificates.
Generally, the clients and the backends will also check their peer’s (apache) certificate to be known and valid, so that if someone is going to impersonate the gateway, it will be found and will not be considered authentic.

To do so, we’ll use:

  • apache httpd
  • mod_ssl
  • mod_proxy_balancer + mod_proxy + mod_proxy_http

Everything is done with a simple and single virtualhost in apache to be included in httpd.conf.
A working example is given below (assumes apache to be installed in /opt/apache, working with IP on port 443):

# General setup for the virtual host
DocumentRoot “/opt/apache/htdocs”
CustomLog “|/opt/apache/bin/rotatelogs /opt/apache/logs/ssl_request_%Y%m%d.log 43200” “%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \”%r\” %b”
ErrorLog “|/opt/apache/bin/rotatelogs /opt/apache/logs/error_%Y%m%d.log 43200”
CustomLog “|/opt/apache/bin/rotatelogs /opt/apache/logs/access_%Y%m%d.log 43200” combined

# Enable SSL Server on this virtualhost
SSLEngine on
# Disable SSLv2 in favor of the more robust and secure SSLv3
SSLProtocol all -SSLv2
# List of supported cryptografic server cipher suites

# Apache server certificate
SSLCertificateFile “/opt/apache/conf/ssl/server.pem”
# Apache server private key
SSLCertificateKeyFile “/opt/apache/conf/ssl/key.pem”
# Apache server CA certificate (certificate of who released your server certificate)
SSLCertificateChainFile “/opt/apache/conf/ssl/ca.pem”
# Client’s CA certificates (list of certificates of who released your client’s certificates)
SSLCACertificateFile “/opt/apache/conf/ssl/ca.pem”
# It’s mandatory for apache to authenticate the client’s certificate
SSLVerifyClient require

# Enable SSL Client on this virtualhost (the traffic to the backends can be encrypted)
SSLProxyEngine on
# Apache client CA certificate (certificate of who released your client certificate)
SSLProxyMachineCertificateChainFile “/opt/apache/conf/ssl/ca.pem”
# Apache client private key + client certificate (concatenated in a single file)
SSLProxyMachineCertificateFile “/opt/apache/conf/ssl/client.pem”
# Backends’ CA certificates (list of certificates of who released your backends’ certificates)
SSLProxyCACertificateFile “/opt/apache/conf/ssl/ca.pem”
# It’s mandatory for apache to authenticate the backends’ certificate
SSLProxyVerify require

<FilesMatch “\.(cgi|shtml|phtml|php)$”>
SSLOptions +StdEnvVars
<Directory “/opt/apache/cgi-bin”>
SSLOptions +StdEnvVars

BrowserMatch “MSIE [2-5]” \
nokeepalive ssl-unclean-shutdown \
downgrade-1.0 force-response-1.0

# Define a load balancer worker to be used to balance the HTTPS traffic to three backends.
# The traffic between apache and the backends is encrypted
<Proxy balancer://httpslb>
# Define the first backend (https) with 2 way auth
BalancerMember route=worker1 retry=10
# Define the second backend (https) with 2 way auth
BalancerMember route=worker2 retry=10
# Define the third backend (https) with 2 way auth
BalancerMember route=worker3 retry=10

# Don’t send the “/balancer-manager” uri to the backends
ProxyPass /balancer-manager !
# Distribute the traffic (any url, since it is “/”) to the backends with round robin + cookie based session persistence
ProxyPass / balancer://httpslb/ lbmethod=byrequests stickysession=JSESSIONID


If the clients and the backends are configured to check the gateway (apache) certificates, this is considered to be a very secure configuration.


14 Mar 11 Utilizzare openssl come Certification Authority

Come utilizzare openssl per creare una CA (Certification Authority)

NOTE: there’s a new more advanced article:

Ciao gente.
A volte capita la necessita’ di creare un ente certificatore con openssl, ad esempio per poter generare e firmare dei certificati x509 che possono essere utili ai fini di riconoscimento lato server/client, ad esempio con apache.

I passaggi che da seguire sono semplici:

# Generazione della chiave privata dell’ente certificatore
openssl genrsa -des3 -out ca.key 4096
# Generazione del certificato dell’ente certificatore
openssl req -new -x509 -days 9999 -key ca.key -out ca.crt

# Creazione della chiave privata del server
openssl genrsa -out server.key 2048
# Generazione del CSR del server
openssl req -new -key server.key -out server.csr
# Creazione del certificato server e firma con il certificato dell’ente certificatore
openssl x509 -req -in server.csr -out server.crt -sha1 -CA ca.crt -CAkey ca.key -CAcreateserial -days 1365

# Creazione della chiave privata del client da autenticare
openssl genrsa -des3 -out user.key 1024
# Generazione del CSR del client
openssl req -new -key user.key -out user.csr
# Creazione del certificato client e firma con il certificato dell’ente certificatore
openssl x509 -req -in user.csr -out user.crt -sha1 -CA ca.crt -CAkey ca.key -CAcreateserial -days 1365
# Conversione in formato PKCS#12
openssl pkcs12 -export -in user.crt -inkey user.key -name “Nome e cognome” -out user.p12

Se avete domande chiedete pure.
Ciao, Dino.