SSL Private Key, Signing Request, Certificate Generation and Apache Configuration

Preparation

Versions prior to Apache v2.2.12 and OpenSSL v0.9.8j required a dedicated IP address for each certificate. With Server Name Indication (SNI) there is no need to request a new IP every time a certificate needs to be installed for a domain.

SNI can secure:

  • Multiple Apache sites with a single certificate
  • Multiple subdomains of a domains with multiple certificates
  • Multiple domains from a single IP address

With that said, you don't have to request a dedicated IP address for sites that use SSL certificates.

In order to create certificates or certificate signing requests (CSR) and use them, openssl, apache, and mod_ssl must be installed on the system.

If you are purchasing an SSL certificate from a company such as DigiCert or GoDaddy you need to generate a Certificate Signing Request (CSR):

$ openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key
$ openssl req -out CSR.csr -key privateKey.key -new
$ openssl x509 -x509toreq -in certificate.crt -out CSR.csr -signkey privateKey.key

The first command creates a new CSR and private key. If you don't need a new private key, then you can create a new CSR based on your existing key by using the second command. A third way to create a CSR is to use an existing certificate, but you need the private key in order to do so. The req sub-command creates and processes certificate requests by taking various commandline options. When the --out option is used in conjunction with the req sub-command, it takes a parameter that specifies where the CSR will be placed.

The --new option specifies that we want to create a new private key causing OpenSSL to ask the user for values for relevant fields.--newkey takes the form of <algorithm:bits>. In the above example, we are creating a private key using the RSA algorithm with a length of 2048 bits. Other algorithms support the format of <algorithm:file> where file contains the parameters for the algorithm specified. This file is generated by using the genpkey sub-command. 
--nodes specify that the key is not to be password protected.
--keyout specifies the name of the file to write the private key to.

The x509 sub-command is used to view information about, convert, and sign certificates specified by the -in option. The -x509toreq specifies that a CSR is to be generated from the certificate. The -signkey is used to pass the private key that's required when generating the CSR.

If you can get away with a self-signed certificate:

$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout privateKey.key -out certificate.crt

Most of the command-line options used in creating a self-signed certificate are used in creating a CSR from a new or existing private key. The -x509 outputs the self-signed certificate rather a CSR, which is valid for the number of days specified by -days option.

Verifying

$ openssl req -text -noout -verify -in request.csr

The above retrieves the containing in the signing request by displaying the text (-text, -noout). The -verify command-line option indicates that the user wants to verify the file specified by -in.

To ensure that private key is valid, run the following command.

$ openssl rsa -in private.key -check

To print the certificate:

$ openssl x509 -in certificate.crt -noout -text
Certificate:
  Data:
  Version: 3 (0x2)
  Serial Number:
  a2:42:e1:14:66:96:5c:8f
  Signature Algorithm: sha256WithRSAEncryption
  Issuer: C=US, ST=Texas, L=Dallas, O=Paulus World, OU=IT, CN=paulusworld.com/emailAddress=webmaster@paulusworld.com
  Validity
  Not Before: Oct 12 07:46:50 2016 GMT
  Not After : Oct 12 07:46:50 2017 GMT
  Subject: C=US, ST=Texas, L=Dallas, O=Paulus World, OU=IT, CN=paulusworld.com/emailAddress=webmaster@paulusworld.com
  Subject Public Key Info:
  Public Key Algorithm: rsaEncryption
  Public-Key: (2048 bit)
  Modulus:
  00:f4:5f:d8:67:ea:dd:bd:c4:ad:75:4a:40:42:2e:
  a6:0a:6f:af:7d:e4:1d:c9:c8:04:ec:ae:8e:07:58:
  4a:1d:49:3b:a7:0a:4f:02:79:cc:4d:5e:11:c8:24:
  47:77:be:ff:b6:f2:55:1f:8a:f3:61:18:5f:96:08:
  27:7e:2b:50:fb:97:45:69:82:c2:ff:71:bb:89:6e:
  63:35:d6:5e:4b:df:87:9a:81:b0:73:c4:fb:69:d4:
  e7:40:3e:7d:65:7a:a0:86:69:ea:09:a0:ee:c1:e1:
  4f:54:b4:e7:f2:3c:25:b8:ad:c4:5b:25:af:25:37:
  b8:bb:e5:31:09:b7:47:4d:94:48:ee:b8:bd:1c:1f:
  95:88:04:eb:e6:73:22:3b:0a:39:a6:c1:d3:65:0e:
  28:0d:6b:5d:17:9d:20:71:21:2b:d9:5e:65:0f:cf:
  87:d0:cd:90:4e:a9:65:4f:81:15:f9:1a:8a:3c:23:
  aa:0e:e7:c8:32:51:ce:f9:f3:63:da:12:6a:6d:65:
  6a:dd:0f:02:6e:1b:26:d3:59:de:aa:c7:8b:37:d7:
  ed:31:ad:a8:5d:f8:2d:b7:e6:fa:70:29:96:cd:e3:
  94:e3:18:fa:ed:29:16:11:c4:e3:34:fc:73:a7:ce:
  9d:83:f6:ff:c5:fa:a1:85:7d:27:40:3e:71:71:c3:
  94:fd
  Exponent: 65537 (0x10001)
  X509v3 extensions:
  X509v3 Subject Key Identifier:
  9D:99:53:68:2E:77:28:48:34:4B:44:53:85:6C:CB:24:9F:B7:F0:7A
  X509v3 Authority Key Identifier:
  keyid:9D:99:53:68:2E:77:28:48:34:4B:44:53:85:6C:CB:24:9F:B7:F0:7A

  X509v3 Basic Constraints:
  CA:TRUE
  Signature Algorithm: sha256WithRSAEncryption
  86:e6:80:9f:d8:9e:e1:2a:7a:1b:bd:fa:a5:1a:60:30:dd:ee:
  cb:d7:8a:17:4e:90:35:2c:d3:24:ba:29:b5:c9:64:a2:1d:f2:
  9c:77:46:fd:d8:d5:5e:91:af:b6:37:42:b2:4f:72:e4:99:7d:
  57:be:a5:25:41:9a:9e:19:b7:be:09:7e:84:2f:87:b0:54:a7:
  b2:82:1c:4c:9d:54:09:e7:86:97:b6:f2:c9:94:4b:59:e2:ed:
  55:e7:46:f8:17:75:19:12:bc:70:f9:81:c8:f3:d7:c3:b4:9b:
  c9:66:e5:f3:80:46:08:ab:44:84:27:ca:c5:8c:b6:c1:79:93:
  9f:75:e4:d5:9a:77:70:95:5c:85:d7:38:87:ad:96:f1:21:f0:
  8a:42:b6:6c:46:cd:6e:95:35:f2:57:4e:ef:48:47:29:22:20:
  cc:56:86:08:fb:96:4b:c0:0d:1b:93:c6:6c:02:98:9d:25:21:
  ed:3d:8a:ff:e0:09:c7:bb:de:78:2b:87:14:72:ba:22:2b:8d:
  ed:5d:f9:1f:36:5e:d0:8e:db:c1:82:72:75:bd:45:72:a9:61:
  50:99:25:b8:58:7f:4f:70:a4:76:36:1a:15:c8:c6:95:4f:e1:
  4d:b0:5b:a0:04:2a:5f:e8:4f:97:ec:b4:7b:cc:06:fb:37:90:
  d4:aa:84:3a

To check a PKCS#12 file:

$ openssl pkcs12 -info -in keyStore.p12

Configuration

The minimal configuration lines that are needed are to enable SSL:

<VirtualHost *:443>
     ServerName www.example.com
     SSLEngine On
     SSLCertificateFile "/path/to/file.crt"
     SSLCertificateKeyFile "/parth/to/file.key"
</VirtualHost>

The default and global SSL configuration settings are stored in a separate file located either in the /etc/httpd, /etc/apache or a subdirectory within the aforementioned directories.

When setting up a domain on a server that isn't managed by a control panel such as Plesk or cPanel, I break up the configuration for each virtual host based on domain. Each HTTP and HTTPS virtual host configuration lives in their own file located in either vhosts or ssl_vhosts, respectively.

<VirtualHost *:80>
     ServerName example.com
     ServerAlias www.example.com
     ServerAdmin webmaster@example.com

     ErrorLog "/path/to/logs/error_log"
     CustomLog "/path/to/logs/access_log" combined

     DocumentRoot "/path/to/web/root"
     <Directory "/path/to/web/root">
          Options -Indexes -FollowSymLinks
          AllowOverride None

          # Redirects & Rewrites
          Include example.inc
          Require all granted
     </Directory>
</VirtualHost>

 

<VirtualHost *:443>
     ServerName example.com
     ServerAlias www.example.com
     ServerAdmin webmaster@example.com

     ErrorLog "/path/to/logs/ssl-error_log"
     CustomLog "/path/to/logs/ssl-access_log" combined

     SSLEngine On
     # Specify Protocol
     SSLProtocol -All +TLSv1.2
     SSLHonorCypherOrder On
     SSLCipherSuite SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5

     SSLCertificateFile "/path/to/file.crt"
     SSLCertificateKeyFile "/path/to/file.key"
     SSLCertificateChainFile "/path/to/bundle.ctr"

     DocumentRoot "/path/to/we/root"
     <Directory "/path/to/web/root">
          Include example_com.inc
     </Directory>
</VirtualHost>

Troubleshooting

In the event that an error arises that the private key doesn't match or that the site isn't trusted, use these commands to verify that the SSL certificate was installed correctly:

$ openssl x509 -noout -modulus -in certificate.crt | openssl md5
$ openssl rsa -noout -modulus -in privateKey.key | openssl md5
$ openssl req -noout -modulus -in CSR.csr | openssl md5

To verify a certificate using the commandline:

$ openssl s_client -showcerts -connect example.com:443

Converting Certificates

Convert a DER file (.crt .cer .der) to PEM

$ openssl x509 -inform der -in certificate.cer -out certificate.pem

Convert a PEM file to DER

$ openssl x509 -outform der -in certificate.pem -out certificate.der

Convert a PKCS#12 file (.pfx .p12) containing a private key and certificates to PEM

$ openssl pkcs12 -in keyStore.pfx -out keyStore.pem -nodes

You can add -nocerts to only output the private key or add -nokeys to only output the certificates.

Convert a PEM certificate file and a private key to PKCS#12 (.pfx .p12)

$ openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile CACert.crt