bin/r509 in r509-0.10.0 vs bin/r509 in r509-1.0
- old
+ new
@@ -1,32 +1,41 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'r509'
require 'r509/trollop'
+require 'io/console'
-opts = R509::Trollop::options do
+opts = R509::Trollop.options do
opt :interactive, "Interactive CSR/self-signed certificate generation. Overrides all flags other than keyout and out."
opt :subject, "X509 subject / delimited. Example: /CN=test.com/O=Org/C=US/ST=Illinois/L=Chicago", :type => :string
- opt :message_digest, "Message digest to use. sha1, sha224, sha256, sha384, sha512, md5", :type => :string, :default => 'sha1'
+ opt :san, "Subject Alternative Name Example: test.com,*.test.com", :type => :string
+ opt :message_digest, "Message digest to use. sha1, sha224, sha256, sha384, sha512, md5", :type => :string, :default => 'sha256'
opt :duration, "Self-sign the certificate with the duration (in days) specified.", :type => :integer
opt :bits, "Bit length of generated key. Ignored for EC.", :type => :integer, :default => 2048
opt :curve_name, "Name of elliptic curve to use. Only used for EC.", :type => :string, :default => 'secp384r1'
opt :keyout, "File name to save generated key.", :type => :string
opt :out, "File name to save generated CSR or self-signed certificate", :type => :string
opt :type, "Type of key to generate. RSA/DSA/EC", :type => :string, :default => "RSA"
+ opt :password, "Password to encrypt generated key", :type => :string
+ if RUBY_PLATFORM.match('darwin')
+ opt :clipboard, "Copy CSR or certificate to the clipboard", :default => false, :short => :p
+ end
version "r509 #{R509::VERSION}"
end
-if opts[:interactive] == true or opts[:subject].nil? then
- if opts[:type].upcase == "RSA" or opts[:type].upcase == "DSA"
+opts[:duration] = opts[:duration].to_i
+subject = []
+
+if opts[:interactive] == true || opts[:subject].nil?
+ if opts[:type].upcase == "RSA" || opts[:type].upcase == "DSA"
print "CSR Bit Length (2048):"
bit_length = gets.chomp
- bit_length = (bit_length.to_i > 0)? bit_length.to_i : 2048
+ opts[:bits] = (bit_length.to_i > 0) ? bit_length.to_i : 2048
elsif opts[:type].upcase == "EC"
print "Curve Name (secp384r1):"
curve_name = gets.chomp
- curve_name = (not curve_name.empty?)? curve_name : 'secp384r1'
+ opts[:curve_name] = (!curve_name.empty?) ? curve_name : 'secp384r1'
else
puts "Invalid key type specified. RSA/DSA/EC"
exit
end
@@ -40,117 +49,105 @@
when 'sha512' then 'sha512'
when 'md5' then 'md5'
else R509::MessageDigest::DEFAULT_MD
end
- subject = []
print "C (US): "
c = gets.chomp
- c = c.empty? ? 'US':c;
- subject.push ['C',c]
+ c = c.empty? ? 'US' : c
+ subject.push ['C', c]
print "ST (Illinois): "
st = gets.chomp
- st = st.empty? ? 'Illinois':st;
- subject.push ['ST',st]
+ st = st.empty? ? 'Illinois' : st
+ subject.push ['ST', st]
print "L (Chicago): "
l = gets.chomp
- l = l.empty? ? 'Chicago':l;
- subject.push ['L',l]
+ l = l.empty? ? 'Chicago' : l
+ subject.push ['L', l]
print "O (r509 LLC): "
o = gets.chomp
- o = o.empty? ? 'r509 LLC':o;
- subject.push ['O',o]
+ o = o.empty? ? 'r509 LLC' : o
+ subject.push ['O', o]
print "OU (null by default): "
ou = gets.chomp
- if(!ou.empty?) then
- subject.push ['OU',ou]
+ unless ou.empty?
+ subject.push ['OU', ou]
end
print "CN: "
- subject.push ['CN',gets.chomp]
+ subject.push ['CN', gets.chomp]
print "SAN Domains (comma separated):"
- san_domains = []
- san_domains = gets.chomp.split(',').collect { |domain| domain.strip }
- csr = R509::CSR.new(
- :subject => subject,
- :bit_length => bit_length,
- :type => opts[:type].upcase,
- :curve_name => curve_name,
- :san_names => san_domains,
- :message_digest => opts[:message_digest]
- )
+ opts[:san] = gets.chomp
- selfsign = 0
print "Self-signed cert duration in days (null disables self-sign):"
- selfsign_input = gets.chomp
- if selfsign_input.to_i > 0
- selfsign = selfsign_input.to_i
+ opts[:duration] = gets.chomp.to_i
+
+ print "Password to encrypt generated key (empty disables encryption):"
+ password = STDIN.noecho(&:gets).chomp
+ puts ""
+ unless password.empty?
+ print "Retype password:"
+ password_confirm = STDIN.noecho(&:gets).chomp
+ puts ""
+ unless password == password_confirm
+ puts "Passwords do not match."
+ exit
+ end
+ opts[:password] = password
end
-elsif not opts[:subject].nil?
- subject = OpenSSL::X509::Name.new
- opts[:subject].chomp.split('/').each { |item|
- if item != '' then
- value = item.split('=')
- subject.add_entry(value[0],value[1])
+else
+ opts[:subject].chomp.split('/').each do |item|
+ if item != ''
+ subject.push item.split('=')[0..1]
end
- }
- csr = R509::CSR.new(
- :subject => subject,
- :bit_length => opts[:bits],
- :type => opts[:type].upcase,
- :curve_name => opts[:curve_name],
- :message_digest => opts[:message_digest]
- )
- selfsign = opts[:duration] || 0
+ end
end
+csr_or_cert = csr = R509::CSR.new(
+ :subject => subject,
+ :bit_length => opts[:bits],
+ :type => opts[:type].upcase,
+ :curve_name => opts[:curve_name],
+ :san_names => (opts[:san] || "").split(',').map { |domain| domain.strip },
+ :message_digest => opts[:message_digest]
+)
+
+# for self signed, outputting the cert (not the csr)
+selfsign = opts[:duration]
if selfsign > 0
- cert = R509::CertificateAuthority::Signer.selfsign(
+ csr_or_cert = R509::CertificateAuthority::Signer.selfsign(
:csr => csr,
- :not_after => Time.now.to_i+86400*selfsign,
+ :not_after => Time.now.to_i + 86400 * selfsign,
:message_digest => opts[:message_digest]
)
- if opts[:keyout].nil?
- puts csr.key.to_pem
+end
+
+if opts[:keyout]
+ if opts[:password]
+ csr.key.write_encrypted_pem(opts[:keyout], "aes256", opts[:password])
else
csr.key.write_pem(opts[:keyout])
end
- if opts[:out].nil?
- puts cert.to_pem
- else
- cert.write_pem(opts[:out])
- end
-
- puts cert.subject
- if not cert.san.nil?
- puts "SAN(s): "+cert.san.names.map { |n| n.value }.join(", ")
- end
else
- if opts[:keyout].nil?
- puts csr.key.to_pem
+ if opts[:password]
+ puts csr.key.to_encrypted_pem("aes256", opts[:password])
else
- csr.key.write_pem(opts[:keyout])
+ puts csr.key.to_pem
end
+end
- if opts[:out].nil?
- puts csr.to_pem
- else
- csr.write_pem(opts[:out])
- end
-
- puts csr.subject
- if not csr.san.nil?
- puts "SAN(s): "+csr.san.names.map{|n| n.value}.join(", ")
- end
+if opts[:out]
+ csr_or_cert.write_pem(opts[:out])
+else
+ puts csr_or_cert.to_pem
end
-if RUBY_PLATFORM.match('darwin') != nil then
- if selfsign > 0
- IO.popen('pbcopy','w').puts cert
- else
- IO.popen('pbcopy','w').puts csr
- end
+puts csr_or_cert.subject
+puts "SAN(s): #{csr_or_cert.san.names.map { |n| n.value }.join(", ")}" if csr_or_cert.san
+
+if opts[:clipboard]
+ IO.popen('pbcopy', 'w').puts csr_or_cert
end