codesnip

How do I convert a .pfx certificate bag to use with Apache SSL on Bitnami?

I have a client who has a large web presence that’s uniformly IIS and windows hosts. They have a wildcard SSL cert that covers all servers and subdomains under their main domain.

In an effort to configure a standalone LAMP server under that wildcard, had it’s own small challenge.

To enable a wildcard SSL cert on a server (at least in this example) you’ll need:

  • The private key from the server that generated the Certificate Request (.csr)
  • The CA-Bundle or chain from the certificate authority
  • The Wildcard SSL certificate.

In this case, the client was running windows servers so the whole lot was wrapped in a PKCS12 archive.

From Wikipedia:

In cryptography, PKCS #12 defines an archive file format for storing many cryptography objects as a single file. It is commonly used to bundle a private key with its X.509certificate or to bundle all the members of a chain of trust.

A PKCS #12 file may be encrypted and signed. The internal storage containers, called “SafeBags”, may also be encrypted and signed. A few SafeBags are predefined to store certificates, private keys and CRLs. Another SafeBag is provided to store any other data at individual implementer’s choice.

PKCS #12 is one of the family of standards called Public-Key Cryptography Standards (PKCS) published by RSA Laboratories.

The filename extension for PKCS #12 files is “.p12” or “.pfx”.

These files can be created, parsed and read out with the OpenSSL pkcs12 command.

OK, so I have the PFX file provided by the client with the keys inside. Here’s the process for extracting and configuring apache to accept them.

In this instance I’m running a bitnami wordpress stack on Amazon EC2 so the paths in config files reflect that and may need altered for your particular installation.


Step 1: You copy the pfx file to the machine to be secured.

In this case I just used SFTP to put the file in place in my apache config folder. (/opt/bitnami/apache2/conf)

Step 2: You extract the certificate (.crt)

SSH to your server:

ssh -i ~/path/to/sshkey.pem bitnami@SUB.DOMAIN.com

Navigate to Apache configuration folder:

cd /opt/bitnami/apache2/conf

Next we’ll use the openssl pkcs12 command to extract the cert file.

openssl pkcs12 -in STAR_DOMAIN_com.pfx -clcerts -nokeys -out STAR_DOMAIN_encrypted.crt

Obviously you’ll update your file names according to your application here.
It will ask for the container passphrase.

Step 3: You export the keyfile.

openssl pkcs12 -in STAR_DOMAIN_com.pfx -nocerts -out STAR_DOMAIN_encrypted.key

Enter the container passphrase, and create one for your new key.

Step 4: You translate the keyfile to PEM encoding

openssl rsa -in STAR_DOMAIN_encrypted.key -outform PEM -out STAR_DOMAIN_encrypted_pem.key

Supply the passphrase you created for the key.

Step 5: You export the Certificate Authority chain bundle.

openssl pkcs12 -in STAR_DOMAIN_com.pfx -cacerts -nokeys -out STAR_DOMAIN_cabundle.pem

You should now have the required keys and certificates: STAR_DOMAIN_encrypted.crt, STAR_DOMAIN_encrypted_pem.key, STAR_DOMAIN_cabundle.pem

STEP 6: You configure apache SSL.

Back up your original httpd.conf file:

sudo cp httpd.conf httpd.conf.bak

or in this case, bitnami.conf is the file we’re editing:

sudo cp ./bitnami/bitnami.conf ./bitnami/bitnami.conf.bak

Edit your httpd.conf (in this case bitnami.conf)

sudo nano /opt/bitnami/apache2/conf/bitnami/bitnami.conf

NOTE: If you want to force this site to be SSL all the time, which I’m doing in this case. Look for the <VirtualHost _default_:80> section to force the redirect.

Paste the following block under the DocumentRoot line:

  RewriteEngine On
  RewriteCond %{HTTPS} !=on
  RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R,L]

Here’s what the full <VirtualHost _default_:80> section looks like on my server:

DocumentRoot "/opt/bitnami/apache2/htdocs"
  RewriteEngine On
  RewriteCond %{HTTPS} !=on
  RewriteRule ^/(.*) https://%{SERVER_NAME}/$1 [R,L]
  <directory "="" opt="" bitnami="" apache2="" htdocs"="">
    Options FollowSymLinks MultiViews
    AddLanguage en en
    AddLanguage es es
    AddLanguage pt-BR pt-br
    AddLanguage zh zh
    AddLanguage ko ko
    AddLanguage he he
    AddLanguage de de
    AddLanguage ro ro
    AddLanguage ru ru
    LanguagePriority en
    ForceLanguagePriority Prefer Fallback

    AllowOverride All
    
      Order allow,deny
      Allow from all
    
    = 2.3 >
      Require all granted
  
  # Error Documents
  ErrorDocument 503 /503.html

  # Bitnami applications installed with a prefix URL (default)
  Include "/opt/bitnami/apache2/conf/bitnami/bitnami-apps-prefix.conf"


Next we’ll locate the <VirtualHost _default_:443> configuration section.

You should see something of this sort by default:

 
  DocumentRoot "/opt/bitnami/apache2/htdocs"
  SSLEngine on
  SSLCertificateFile "/opt/bitnami/apache2/conf/server.crt"
  SSLCertificateKeyFile "/opt/bitnami/apache2/conf/server.key"

We need to specify the proper certificate, key and bundle locations here. I’ve commented out the defaults and added the required sections above.

The section you need to add looks like this:

SSLCertificateFile "/opt/bitnami/apache2/conf/STAR_DOMAIN_com_encrypted.crt"
SSLCertificateKeyFile "/opt/bitnami/apache2/conf/STAR_DOMAIN_com_pem.key"
SSLCACertificateFile "/opt/bitnami/apache2/conf/STAR_DOMAIN_com_cabundle.pem"

After it’s added you’ll have this:

DocumentRoot "/opt/bitnami/apache2/htdocs" 
SSLEngine on 
SSLCertificateFile "/opt/bitnami/apache2/conf/STAR_DOMAIN_com_encrypted.crt" 
SSLCertificateKeyFile "/opt/bitnami/apache2/conf/STAR_DOMAIN_com_pem.key" 
SSLCACertificateFile "/opt/bitnami/apache2/conf/STAR_DOMAIN_com_cabundle.pem" 
#SSLCertificateFile "/opt/bitnami/apache2/conf/server.crt" 
#SSLCertificateKeyFile "/opt/bitnami/apache2/conf/server.key"

Next, save your configuration and exit.

Then, you restart apache to reflect your changes.

sudo /opt/bitnami/ctlscript.sh restart apache

Visit your site to verify it’s forcing SSL and your certs are in place.

circuit

.htaccess SSL redirect for single wordpress page.

I recently had a client site that necessitated a single page that would automatically redirect to a secure page for donations.

That meant, they’d be collecting credit card information as well as personal info and then passing it off to PayPal.

After setting up the secure certificates in the server and getting SSL working, the tricky part was getting the redirect to work.

Ideally, it would do this:

  • When a user accesses www.site.com/folder/SSLpage the server forces that page to go to HTTPS.
  • If any other page is accessed, it forces that page back to HTTP.

This was much trickier than it should have been, as none of the documentation I found on the web would do what I needed it to.

Here’s the resulting  code, with comments, that worked.

Please note: Make sure your apache configuration (httpd.conf) allows for overrides using .htaccess before proceeding.

In httpd.conf look for the line inside your <directory> statement that matches where your wordpress install lives:

[hr]

 

Options Indexes FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all


[hr]

Take note of the AllowOverride None statement, and change it to AllowOverride All.

Save the file and restart apache:

  • On RHEL/CentOS that’s #service httpd restart

Now, navigate to your WordPress root directory (sometimes /var/www/htdocs/wordpress or similar)

Use a text editor like nano or vi to create your .htaccess file, or edit the one that’s there.

Here’s what my working .htaccess looks like, with comments for ease of re-use:

[hr]


#Force secure Page/post

RewriteEngine on
#If current port is 80 (http)
RewriteCond %{SERVER_PORT} ^80$
#Then rewrite to HTTPS
#replace URI after the ^ with your wordpress permalink
RewriteCond %{REQUEST_URI} ^/page/name/here/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? https://%{HTTP_HOST}%{REQUEST_URI} [L,S=1,R=301]


#Escape secure form page/post

#if current port is 443 (https)
RewriteCond %{SERVER_PORT} ^443$
#and you’re NOT on the page you specified above rewrite to http
#Replace URI after the ^ with the same permalink as above
RewriteCond %{REQUEST_URI} !^/page/name/here/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .? http://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]


#start wordpress

RewriteEngine On
#RewriteBase /wordpress/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]


[hr]

If all goes well, the single page you specified in the permalink section above, will go to HTTPS and the rest will go to HTTP.

I’m open to discussion, as I’m sure there’s an Apache wizard out there somewhere who could improve on this code. But the amount of time I spent trying to get this to work compelled me to give it back to the community.