Skip to content

Instantly share code, notes, and snippets.

@gamba
Last active January 15, 2021 20:18
Show Gist options
  • Save gamba/b93039e952f0e346b3e0e59430d0ba8d to your computer and use it in GitHub Desktop.
Save gamba/b93039e952f0e346b3e0e59430d0ba8d to your computer and use it in GitHub Desktop.
Example of a Ruby script to clone existing x.509 certificates with new keys. Used in forensic lab to test certificate pinning / verification implementation.
#!/usr/bin/ruby
require 'openssl'
out_path = "~/"
# Self Signed CA
input_ca = "~/ca_certificate.pem"
p = parse_input_path input_ca
ca = parse_input_certificate input_ca
banner ca
# Generate a new key of the same type
ca_key = ca[:c_algo_class].generate ca[:size], ca[:exponent]
# Replace existing key with the new one
ca[:cert].public_key = ca_key.public_key
# Self Sign the certificate
ca[:cert].sign ca_key, ca[:s_algo_class].new
#File.write("#{out_path}/#{name}.public_key.pem", new_key.public_key.to_pem)
File.write("#{out_path}/#{p[:name]}.private_key.pem", ca_key.to_pem)
File.write("#{out_path}/#{p[:name]}.certificate.pem", ca[:cert].to_s)
# CA Signed Leaf Certificate
input_cert = "~/leaf_certificate.pem"
p = parse_input_path input_cert
cert = parse_input_certificate input_cert
banner cert
# Generate a new key of the same type
cert_key = cert[:c_algo_class].generate cert[:size], cert[:exponent]
# Replace existing key with the new one
cert[:cert].public_key = cert_key.public_key
# Sign the certificate with CA private key
cert[:cert].sign ca_key, cert[:s_algo_class].new
File.write("#{out_path}/#{p[:name]}.private_key.pem", cert_key.to_pem)
File.write("#{out_path}/#{p[:name]}.certificate.pem", cert[:cert].to_s)
# ------------------------------------------------------------------------------------------------
BEGIN {
def parse_input_path(arg)
ext = arg.split(".").last
name = arg.split("/").last.gsub(".#{ext}","")
path = arg.gsub( arg.split("/").last, "")
{
name: name,
path: path,
ext: ext
}
end
def parse_input_certificate(arg)
cert = OpenSSL::X509::Certificate.new File.read(arg)
algo = cert.signature_algorithm
exponent = cert.public_key.e.to_i
size = cert.public_key.n.num_bytes * 8
s_algo = algo.split("With").first.upcase
c_algo = algo.split("With").last.split("Encryption").first.upcase
# https://ruby-doc.org/stdlib-2.4.0/libdoc/openssl/rdoc/OpenSSL/PKey.html
# EC, RSA, DSA, DH
c_algo_class = Object.const_get "OpenSSL::PKey::#{c_algo}"
# https://ruby-doc.org/stdlib-2.4.0/libdoc/openssl/rdoc/OpenSSL/Digest.html
# MD2, MD4, MD5, SHA, SHA1, SHA224, SHA256, SHA384, SHA512
s_algo_class = Object.const_get "OpenSSL::Digest::#{s_algo}"
{
c_algo: c_algo,
c_algo_class: c_algo_class,
s_algo: s_algo,
s_algo_class: s_algo_class,
exponent: exponent,
size: size,
subject: cert.subject.to_s,
cert: cert
}
end
def banner(c)
puts "Cert: #{c[:subject]}"
puts "Algo: #{c[:c_algo]} #{c[:s_algo]} #{c[:size]} #{c[:exponent]}"
puts ""
end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment