Preparing Certificate files for Nginx
The Story
When installing SSL certificates for nginx, assuming you’re using certificate hierarchy (and not a self-signed ceritificate), you’re required to concatenate all of the certificate files (*.crt
) to a single file, starting from your site’s certificate up to the root certificate.
Today I got this bundle to prepare, courtesy of Comodo:
AddTrustExternalCARoot.crt
best_site.crt
COMODORSAAddTrustCA.crt
COMODORSADomainValidationSecureServerCA.crt
Which certificate should follow my site’s? Unclear, even from their documentation.
I made this ruby script, which uses some certificate metadata to recognize the relationship between the provided certificates.
The Script
Provide the CRT file names as arguments, save the script’s output as the new CRT. The proper order is printed to STDERR
.
require 'openssl'
# Load and parse files
crt_files=ARGV # Read all arguments as files
crts = crt_files.map{|f|
cert = OpenSSL::X509::Certificate.new File.read f
{
name: f,
parent: cert.extensions.find{|m|m.oid=='authorityKeyIdentifier'}.value.split("\n").find{|sf|sf[/^keyid/]}.gsub(/^keyid:/,''),
son: cert.extensions.find{|m|m.oid=='subjectKeyIdentifier'}.value
}
}
# Find the root, where parent is son
root = crts.find{|c|c[:parent]==c[:son]}
certs_sorted=[]
new_certs=[root]
# process new_certs until we're out
loop do
certs_sorted|=new_certs
new_new_certs = new_certs.map{|nc|
crts.select{|c|c[:parent]==nc[:son]}
}.flatten(1).uniq
filtered_certs = new_new_certs - new_certs
new_certs = filtered_certs
break if new_certs.empty?
end
certs_sorted.reverse! # Reverse
STDERR.puts "Certificate order: #{certs_sorted.map{|c|c[:name]}.join(', ')}"
puts certs_sorted.map{|c| File.read(c[:name])}.join
Interesting bits
I’m not sure if the method I’m using to construct the certificate tree is standard SSL stuff or unique to Comodo, but I noticed the certificates reference their parents in the authorityKeyIdentifier
extension.
Oddly enough, they don’t reference the parent’s serial number, but some other serial-like value that I find under subjectKeyIdentifier
of the parent certificate.
The loop isn’t very interesting, but still full of neat ruby stuff like limited flattening, array subtraction and other stuff that “decent” languages would never allow.