1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
#!/usr/bin/env ruby
# encoding: utf-8
# vim: ts=4:sw=4:et:
require "openssl"
require "optparse"
require "pp"
require_relative "lib/backend"
require_relative "lib/cert_util"
require_relative "lib/issuer"
require_relative "lib/openssl_ext"
#require_relative "lib/x509_ext" # not yet used, only needed for KRB5: names
def import_pubkey(path)
buf = File.read(path)
if buf =~ /^-----BEGIN (?:NEW )?CERTIFICATE REQUEST-----\r?$/
req = OpenSSL::X509::Request.new(buf)
return req.public_key
elsif buf =~ /^-----BEGIN CERTIFICATE-----\r?$/
cert = OpenSSL::X509::Certificate.new(buf)
return cert.public_key
elsif buf =~ /^-----BEGIN PUBLIC KEY-----\r?$/
key = OpenSSL::PKey.read(buf)
return key.public_key
elsif buf =~ /^-----BEGIN (?:RSA )?PRIVATE KEY-----\r?$/
key = OpenSSL::PKey.read(buf)
if key.is_a? OpenSSL::PKey::EC
# The .public_key is a PKey::EC::Point which won't work
return key
else
pp key
return key.public_key
end
else
raise "unrecognized request or public key file: #{path}"
end
end
def import_request_subject(path)
buf = File.read(path)
if buf =~ /^-----BEGIN (?:NEW )?CERTIFICATE REQUEST-----\r?$/
req = OpenSSL::X509::Request.new(buf)
return req.subject.to_rfc2253
elsif buf =~ /^-----BEGIN CERTIFICATE-----\r?$/
cert = OpenSSL::X509::Certificate.new(buf)
return cert.subject.to_rfc2253
else
raise "unrecognized request file: #{path}"
end
end
arg_dbdir = nil
arg_request = nil
arg_template = nil
arg_subject = nil
arg_aliases = []
arg_unit = nil
arg_days = nil
arg_output = nil
OptionParser.new do |parser|
parser.on("-d", "--ca-dir PATH", String, "Path to CA database") do |arg|
arg_dbdir = arg
end
parser.on("-r", "--request FILE", String, "Input request or public key") do |arg|
arg_request = arg
end
parser.on("-t", "--type NAME", String, "Certificate template") do |arg|
arg_template = arg
end
parser.on("-s", "--subject NAME", String, "Certificate subject") do |arg|
arg_subject = arg
end
parser.on("-a", "--alias HOSTNAME", String, "Additional subject name") do |arg|
arg_aliases << arg
end
parser.on("-u", "--ou NAME", "Organizational unit") do |arg|
arg_unit = arg
end
parser.on("-y", "--days DAYS", "Certificate lifetime") do |arg|
arg_days = parse_lifetime(arg)
end
parser.on("-o", "--output FILE", String, "Output certificate filename") do |arg|
arg_output = arg
end
parser.on("--[no-]debug", "Enable pkcs11-provider debugging") do |arg|
ENV["PKCS11_PROVIDER_DEBUG"] = "file:/dev/stderr,level:2"
end
# Prevent short options like "-d" from matching "--debug" if they aren't
# explicitly declared.
#parser.require_exact = true
end.parse!
if !arg_dbdir
arg_dbdir = File.readlink(".default") rescue "root"
end
if !arg_request
raise "request or public key not specified"
end
if !arg_template
raise "template not specified"
end
if !arg_subject
if arg_template == "subca"
arg_subject = import_request_subject(arg_request)
else
raise "Subject name not specified"
end
end
pubkey = import_pubkey(arg_request)
puts "Loaded request:"
puts " Public key: #{pubkey}"
ca = Backend.new(arg_dbdir)
puts "Loaded CA chain:"
ca.chain.each do |cert|
puts " #{cert.subject.to_rfc2253}"
end
iss = Issuer.new(ca)
params = [pubkey, arg_subject, arg_aliases, arg_unit, arg_days]
case arg_template
when "host"
cert = iss.issue_host(*params)
when "user"
cert = iss.issue_client(*params)
when "addc"
cert = iss.issue_ad_dc(*params)
when "device"
cert = iss.issue_device(*params)
when "subca"
cert = iss.issue_subca(*params)
when "code"
cert = iss.issue_code(*params)
else
raise "Unknown certificate type: #{arg_template.inspect}"
end
if cert.nil?
raise "certificate issuance was aborted"
end
#puts "got cert:"
#puts cert.to_text.gsub(/^\s+([0-9a-f:])+\n/, "")
if !arg_output
arg_output = "#{cert_to_filename(cert)}.crt"
end
File.open(arg_output, "w") do |fh|
fh.write(cert.to_pem)
fh.write(ca.chain.map(&:to_pem).join)
end
puts "Saved certificate to: #{arg_output}"
|