Skip to content

Instantly share code, notes, and snippets.

@pzb
Created November 24, 2015 04: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 pzb/eef7702530e0b08a804d to your computer and use it in GitHub Desktop.
Save pzb/eef7702530e0b08a804d to your computer and use it in GitHub Desktop.
#!/usr/bin/ruby
require 'openssl'
require 'base64'
require 'optparse'
options = {
:outform => "PEM"
}
OptionParser.new do |opts|
opts.on("-n", "--name NAME", "Trust Anchor Name") do |v|
options[:name] = v
end
opts.on("--outform FORM", ["DER", "PEM"], "Select output encoding", " (DER, PEM)") do |v|
options[:outform] = v
end
end.parse!
# This takes a certificate as input and outputs trust anchor info
# RFC 5914 defines the TrustAnchorInfo structure
c = OpenSSL::X509::Certificate.new(File.read(ARGV[0]))
key_id = nil
eku = nil
policy_set = nil
policy_flags = nil
name_constr = nil
pathlen = nil
c.extensions.each do |ext|
e = OpenSSL::ASN1.decode(ext.to_der).value
oid = e.first.oid
content = OpenSSL::ASN1.decode(e.last.value)
case oid
when "2.5.29.14" # id-ce-subjectKeyIdentifier
key_id = e.last
when "2.5.29.19" # id-ce-basicConstraints
bc = content.value
if bc.length == 0 || !bc.first.value
raise "Only able to create Trust Anchor Info from CA-certificate"
end
if bc.length == 2
$stderr.puts "Copying path length constraint of #{bc.last.value.to_s}"
pathlen = bc.last
end
when "2.5.29.30" # id-ce-nameConstraints
$stderr.puts "Copying name constraints:"
$stderr.puts ext.value
name_constr = content
when "2.5.29.32" # id-ce-certificatePolicies
policies = content.value.map{|pi|pi.value.first.oid}.uniq
if policies.length > 1 || policies[0] != "2.5.29.32.0"
# mulitple policies or a single non-anyPolicy policy
$stderr.puts "Adding policies #{policies.join(",")}"
policy_infos = policies.map do |p|
OpenSSL::ASN1::Sequence.new([OpenSSL::ASN1::ObjectId.new(p)])
end
policy_set = OpenSSL::ASN1::Sequence.new(policy_infos)
end
when "2.5.29.36" # id-ce-policyConstraints
raise "PolicyConstraints not yet implemented"
when "2.5.29.37" # id-ce-extKeyUsage
$stderr.puts "Copying extended key usages"
$stderr.puts ext.value
eku = ext
when "2.5.29.54" # id-ce-inhibitAnyPolicy
raise "InhibitAnyPolicy not yet implemented"
end
end
if key_id.nil?
raise "Certificate must have subject key identifier"
end
cert_path_data = [
c.subject.to_der, # taName
# Never including certificate (our purpose is to convert cerificate to tai)
]
if !policy_set.nil?
policy_set.tag_class = :CONTEXT_SPECIFIC
policy_set.tag = 1
cert_path_data << policy_set
end
if !name_constr.nil?
name_constr.tag_class = :CONTEXT_SPECIFIC
name_constr.tag = 3
cert_path_data << name_constr
end
if !pathlen.nil?
pathlen.tag_class = :CONTEXT_SPECIFIC
pathlen.tag = 4
cert_path_data << pathlen
end
cert_path = OpenSSL::ASN1::Sequence.new(cert_path_data)
tai_data = [
# version DEFAULT v1 (not encoded),
c.public_key.to_der,
key_id
]
if !options[:name].nil?
tai_data << OpenSSL::ASN1::UTF8String.new(options[:name])
end
tai_data << cert_path
if !eku.nil?
tai_data << OpenSSL::ASN1::Sequence.new([eku], 1, :EXPLICIT)
#tai_data << OpenSSL::ASN1::ASN1Data.new(ext_data, 1, :CONTEXT_SPECIFIC)
end
tai = OpenSSL::ASN1::Sequence.new(tai_data).to_der
if options[:outform] == "PEM"
puts "-----BEGIN TRUST ANCHOR-----"
puts Base64.encode64(tai)
puts "-----END TRUST ANCHOR-----"
else
print tai
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment