Skip to content

Instantly share code, notes, and snippets.

@mic-kul
Created March 24, 2016 13:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mic-kul/4da0aac1906a22a10b8c to your computer and use it in GitHub Desktop.
Save mic-kul/4da0aac1906a22a10b8c to your computer and use it in GitHub Desktop.
generate #ready-to-use-with-nginx bundle.crt from single certificate
#!/usr/bin/env ruby
# cert2bundle.rb
# author: @mic-kul
# USAGE: ./cert2bundle.rb some.domain.crt
# generates #ready-to-use-with-nginx bundle.crt in current working directory
require "openssl"
require "net/http"
require "uri"
require "base64"
%w(begin end).each do |location|
define_method("cert_#{location}") do
"-----#{location.upcase} CERTIFICATE-----"
end
end
def base64_candidate?(str)
str != nil && str.class == String && str.length % 4 == 0 && str =~ /^[A-Za-z0-9+\/=]+\Z/
end
def encoded_cert(str)
return str if str.start_with?(cert_begin)
[cert_begin, Base64.encode64(str).strip, cert_end].join("\n")
end
def from_file(path)
File.read(path)
end
def from_uri(uri)
Net::HTTP.get_response(URI.parse(uri)).body
end
def issuer_uri(cert)
begin
OpenSSL::X509::Certificate.new(cert)
.to_text.match(/CA\ Issuers\ \-\ URI\:(.*)$/)[1]
rescue
nil
end
end
file_name = ARGV.shift
raise "Certificate bundler requires exactly one argument: path to the certificate" if file_name == nil
chain = []
cert_data = from_file(file_name)
chain << cert_data.strip
parent_uri = issuer_uri(cert_data)
while parent_uri do
puts "Downloaded CA from: #{parent_uri}"
cert_data = from_uri(parent_uri)
chain << encoded_cert(cert_data)
parent_uri = issuer_uri(cert_data)
end
puts "Chain size: #{chain.size}"
File.open('bundle.crt', 'w') { |file| file.write(chain.join("\n")) }
puts "Saved to bundle.crt"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment