This one took me a lot of time to get my head over!
Introduction
Openssl is a TLS/SSL and crypto library https://www.openssl.org: it has many commands and lot of configuration options.
openssl is a command line tool that can be used for:
- Creation of key parameters
- Creation of X.509 certificates, CSRs and CRLs
- Calculation of message digests
- Encryption and decryption
- SSL/TLS client and server tests
- Handling of S/MIME signed or encrypted mail
- And more…
Terminology
CA = Certificate Authority: entity that issues digital certificates
CSR = Certificate Signing Request
PKI = Public Key Infrastructure
PEM = Privacy Enhanced Mail
X509 File Extensions
The first thing we have to understand is what each type of file extension is. There is a lot of confusion about what DER, PEM, CRT, and CER are and many have incorrectly said that they are all interchangeable. While in certain cases some can be interchanged the best practice is to identify how your certificate is encoded and then label it correctly. Correctly labeled certificates will be much easier to manipulat
Encodings (also used as extensions)
- .DER = The DER extension is used for binary DER encoded certificates. These files may also bear the CER or the CRT extension. Proper English usage would be “I have a DER encoded certificate” not “I have a DER certificate”.
- .PEM = The PEM extension is used for different types of X.509v3 files which contain ASCII (Base64) armored data prefixed with a “—– BEGIN …” line.
Common Extensions
- .CRT = The CRT extension is used for certificates. The certificates may be encoded as binary DER or as ASCII PEM. The CER and CRT extensions are nearly synonymous. Most common among *nix systems
- CER = alternate form of .crt (Microsoft Convention) You can use MS to convert .crt to .cer (.both DER encoded .cer, or base64[PEM] encoded .cer) The .cer file extension is also recognized by IE as a command to run a MS cryptoAPI command (specifically rundll32.exe cryptext.dll,CryptExtOpenCER) which displays a dialogue for importing and/or viewing certificate contents.
- .KEY = The KEY extension is used both for public and private PKCS#8 keys. The keys may be encoded as binary DER or as ASCII PEM.
The only time CRT and CER can safely be interchanged is when the encoding type can be identical. (ie PEM encoded CRT = PEM encoded CER)
First lets set up your CA
Create a folder to hold our config and keys: sudo mkdir /etc/apache2/ssl && cd /etc/apache2/ssl
Create a basic configuration file: touch openssl-ca.cnf
Put this inside sudo nano openssl-ca.cnf
:
# openssl-ca.cnf
HOME = .
RANDFILE = $ENV::HOME/.rnd
####################################################################
[ ca ]
default_ca = CA_default # The default ca section
[ CA_default ]
default_days = 1000 # how long to certify for
default_crl_days = 30 # how long before next CRL
default_md = sha256 # use public key default MD
preserve = no # keep passed DN ordering
x509_extensions = ca_extensions # The extensions to add to the cert
email_in_dn = no # Don't concat the email in the DN
copy_extensions = copy # Required to copy SANs from CSR to cert
####################################################################
[ req ]
default_bits = 4096
default_keyfile = cakey.pem
distinguished_name = ca_distinguished_name
x509_extensions = ca_extensions
string_mask = utf8only
####################################################################
[ ca_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = MA
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default =Drâa‐Tafilalet
localityName = Locality Name (eg, city)
localityName_default = Ouarzazate
organizationName = Organization Name (eg, company)
organizationName_default = Test CA, Limited
organizationalUnitName = Organizational Unit (eg, division)
organizationalUnitName_default = Server Research Department
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Test CA
emailAddress = Email Address
emailAddress_default = [email protected]
####################################################################
[ ca_extensions ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always, issuer
basicConstraints = critical, CA:true
keyUsage = keyCertSign, cRLSign
Then, execute the following. The -nodes
omits the password or passphrase so you can examine the certificate.
$ openssl req -x509 -config openssl-ca.cnf -newkey rsa:4096 -sha256 -nodes -out cacert.pem -outform PEM
After the command executes, cacert.pem
will be your certificate for CA operations, and cakey.pem
will be the private key. Recall the private key does not have a password or passphrase.
You can dump the certificate with the following:
$ openssl x509 -in cacert.pem -text -noout
And test its purpose with the following:
$ openssl x509 -purpose -in cacert.pem -inform PEM
Second: lets sign an end entity certificate (a.k.a server or user)
For part two, I’m going to create another conf file that’s easily digestible.
First, touch the openssl-server.cnf (you can make one of these for user certificates also).
$ touch openssl-server.cnf
Then open it and add the following.
#openssl-server.cnf
HOME = .
RANDFILE = $ENV::HOME/.rnd
####################################################################
[ req ]
default_bits = 2048
default_keyfile = serverkey.pem
distinguished_name = server_distinguished_name
req_extensions = server_req_extensions
string_mask = utf8only
####################################################################
[ server_distinguished_name ]
countryName = Country Name (2 letter code)
countryName_default = US
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = MD
localityName = Locality Name (eg, city)
localityName_default = Baltimore
organizationName = Organization Name (eg, company)
organizationName_default = Test CA, Limited
commonName = Common Name (e.g. server FQDN or YOUR name)
commonName_default = Test CA
emailAddress = Email Address
emailAddress_default = [email protected]
####################################################################
[ server_req_extensions ]
subjectKeyIdentifier = hash
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alternate_names
nsComment = "OpenSSL Generated Certificate"
####################################################################
[ alternate_names ]
DNS.1 = mydomain.dev
DNS.2 = www.mydomain.dev
DNS.3 = mail.mydomain.dev
DNS.4 = ftp.mydomain.dev
# IPv4 localhost
IP.1 = 127.0.0.1
# IPv6 localhost
IP.2 = ::1
Then, create the server certificate request.
Be sure to omit -x509
*. Adding -x509
will create a certifcate, and not a request.
$ openssl req -config openssl-server.cnf -newkey rsa:2048 -sha256 -nodes -out servercert.csr -outform PEM
After this command executes, you will have a request in servercert.csr
and a private key in serverkey.pem
.
And you can inspect it again.
$ openssl req -text -noout -verify -in servercert.csr
Next, you have to sign it with your CA.
You are almost ready to sign the server’s certificate by your CA. The CA’s openssl-ca.cnf
needs two more sections before issuing the command.
First, open openssl-ca.cnf
and add the following two sections:
####################################################################
[ signing_policy ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
####################################################################
[ signing_req ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
basicConstraints = CA:FALSE
keyUsage = digitalSignature, keyEncipherment
Second, add the following to the [ CA_default ]
section of openssl-ca.cnf. I left them out earlier because they can complicate things (they were unused at the time). Now you will see how they are used, so hopefully they will make sense.
base_dir = .
certificate = $base_dir/cacert.pem # The CA certifcate
private_key = $base_dir/cakey.pem # The CA private key
new_certs_dir = $base_dir # Location for new certs after signing
database = $base_dir/index.txt # Database index file
serial = $base_dir/serial.txt # The current serial number
unique_subject = no # Set to 'no' to allow creation of
# several certificates with same subject.
Third, touch index.txt
and serial.txt
:
$ touch index.txt
$ echo '01' > serial.txt
Then, perform the following:
$ openssl ca -config openssl-ca.cnf -policy signing_policy -extensions signing_req -out servercert.pem -infiles servercert.csr
You should confirm the sign of the certificate.
After the command executes, you will have a freshly minted server certificate in servercert.pem
. The private key was created earlier and is available in serverkey.pem
.
Finally, you can inspect your freshly minted certificate with the following:
$ openssl x509 -in servercert.pem -text -noout
Add the certification to your virtual host
Edit your virtual host:
sudo nano /etc/apache2/sites-available/mydomain.dev.conf
<VirtualHost *:443>
ServerName mydomain.dev
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/servercert.pem
SSLCertificateKeyFile /etc/apache2/ssl/serverkey.pem
SSLCertificateChainFile /etc/apache2/ssl/cacert.pem
DocumentRoot /var/www/mydomain/web
<Directory /var/www/mydomain/web>
AllowOverride None
Order Allow,Deny
Allow from All
<IfModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ app_dev.php [QSA,L]
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
</IfModule>
</Directory>
<Directory /var/www/mydomain/>
Options FollowSymlinks
</Directory>
<Directory /var/www/mydomain/web/bundles>
<IfModule mod_rewrite.c>
RewriteEngine Off
</IfModule>
</Directory>
ErrorLog ${APACHE_LOG_DIR}/mydomain.dev_error.log
CustomLog ${APACHE_LOG_DIR}/mydomain.dev_access.log combined
</VirtualHost>
Add the certificate to Google Chrome
See this steps: https://css-tricks.com/trusting-ssl-locally-mac/
- Open chrome://settings-frame/
- Scroll down the page and click on: Show advanced settings…
- Scroll down and open: Manage certificates on the HTTPS/SSL section
- The Keychain Access screen will be displayed. Chrome uses the Keychain Access utility built into MAC OS manage digital certificate
- Under ‘Keychains’ on the left, select ‘Login’ and click ‘My Certificates’ in the ‘Category’ column.
Final notes
Earlier, you added the following to CA_default
: copy_extensions = copy
. This copies extension provided by the person making the request.
If you omit copy_extensions = copy
, then your server certificate will lack the Subject Alternate Names (SANs) like www.mydomain.dev
and mail.mydomain.dev
.
If you use copy_extensions = copy
but don’t look over the request, then the requester might be able to trick you into signing something like a subordinate root (rather than a server or user certificate). Which means he will be able to mint certificates that chain back to your trusted root. Be sure to verify the request with openssl req -verify
before signing.
If you omit unique_subject
or set it to yes
, then you will only be allowed to create one certificate under the subject’s distinguished name.
unique_subject = yes # Set to 'no' to allow creation of
# several ctificates with same subject.
Trying to create a second certificate while experimenting will result in the following when signing your server’s certificate with the CA’s private key:
Sign the certificate? [y/n]:Y
failed to update database
TXT_DB error number 2
So unique_subject = no
is perfect for testing.
If you want to ensure the Organizational Name is consistent between self-signed CAs, Subordinate CA and End-Entity certificates, then add the following to your CA configuration files:
[ policy_match ]
organizationName = match
If you want to allow the Organizational Name to change, then use:
[ policy_match ]
organizationName = supplied
There are other rules concerning the handling of DNS names in X.509/PKIX certificates. Refer to these documents for the rules:
RFC 6797 and RFC 7469 are listed because they are more restrictive than the other RFCs and CA/B documents. RFC’s 6797 and 7469 do not allow an IP address, either.
Thanks to Jeff at stackoverflow for his inspiring post