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