certificate_authority 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,31 +1,31 @@
1
1
  module CertificateAuthority
2
2
  class CertificateRevocationList
3
3
  include ActiveModel::Validations
4
-
4
+
5
5
  attr_accessor :certificates
6
6
  attr_accessor :parent
7
7
  attr_accessor :crl_body
8
8
  attr_accessor :next_update
9
-
9
+
10
10
  validate do |crl|
11
11
  errors.add :next_update, "Next update must be a positive value" if crl.next_update < 0
12
12
  errors.add :parent, "A parent entity must be set" if crl.parent.nil?
13
13
  end
14
-
14
+
15
15
  def initialize
16
16
  self.certificates = []
17
17
  self.next_update = 60 * 60 * 4 # 4 hour default
18
18
  end
19
-
19
+
20
20
  def <<(cert)
21
21
  raise "Only revoked certificates can be added to a CRL" unless cert.revoked?
22
22
  self.certificates << cert
23
23
  end
24
-
24
+
25
25
  def sign!
26
26
  raise "No parent entity has been set!" if self.parent.nil?
27
27
  raise "Invalid CRL" unless self.valid?
28
-
28
+
29
29
  revocations = self.certificates.collect do |certificate|
30
30
  revocation = OpenSSL::X509::Revoked.new
31
31
  x509_cert = OpenSSL::X509::Certificate.new(certificate.to_pem)
@@ -33,27 +33,27 @@ module CertificateAuthority
33
33
  revocation.time = certificate.revoked_at
34
34
  revocation
35
35
  end
36
-
36
+
37
37
  crl = OpenSSL::X509::CRL.new
38
38
  revocations.each do |revocation|
39
39
  crl.add_revoked(revocation)
40
40
  end
41
-
41
+
42
42
  crl.version = 1
43
43
  crl.last_update = Time.now
44
44
  crl.next_update = Time.now + self.next_update
45
-
45
+
46
46
  signing_cert = OpenSSL::X509::Certificate.new(self.parent.to_pem)
47
47
  digest = OpenSSL::Digest::Digest.new("SHA512")
48
48
  crl.issuer = signing_cert.subject
49
49
  self.crl_body = crl.sign(self.parent.key_material.private_key, digest)
50
-
50
+
51
51
  self.crl_body
52
52
  end
53
-
53
+
54
54
  def to_pem
55
55
  raise "No signed CRL body" if self.crl_body.nil?
56
56
  self.crl_body.to_pem
57
57
  end
58
58
  end#CertificateRevocationList
59
- end
59
+ end
@@ -1,39 +1,58 @@
1
1
  module CertificateAuthority
2
2
  class DistinguishedName
3
3
  include ActiveModel::Validations
4
-
4
+
5
5
  validates_presence_of :common_name
6
-
6
+
7
7
  attr_accessor :common_name
8
8
  alias :cn :common_name
9
-
9
+
10
10
  attr_accessor :locality
11
11
  alias :l :locality
12
-
12
+
13
13
  attr_accessor :state
14
14
  alias :s :state
15
-
15
+
16
16
  attr_accessor :country
17
17
  alias :c :country
18
-
18
+
19
19
  attr_accessor :organization
20
20
  alias :o :organization
21
-
21
+
22
22
  attr_accessor :organizational_unit
23
23
  alias :ou :organizational_unit
24
-
24
+
25
25
  def to_x509_name
26
26
  raise "Invalid Distinguished Name" unless valid?
27
-
27
+
28
28
  # NB: the capitalization in the strings counts
29
29
  name = OpenSSL::X509::Name.new
30
30
  name.add_entry("CN", common_name)
31
31
  name.add_entry("O", organization) unless organization.blank?
32
- name.add_entry("OU", common_name) unless organizational_unit.blank?
33
- name.add_entry("S", common_name) unless state.blank?
34
- name.add_entry("L", common_name) unless locality.blank?
35
-
32
+ name.add_entry("OU", organizational_unit) unless organizational_unit.blank?
33
+ name.add_entry("ST", state) unless state.blank?
34
+ name.add_entry("L", locality) unless locality.blank?
35
+ name.add_entry("C", country) unless country.blank?
36
+ name
37
+ end
38
+
39
+ def self.from_openssl openssl_name
40
+ unless openssl_name.is_a? OpenSSL::X509::Name
41
+ raise "Argument must be a OpenSSL::X509::Name"
42
+ end
43
+
44
+ name = DistinguishedName.new
45
+ openssl_name.to_a.each do |k,v|
46
+ case k
47
+ when "CN" then name.common_name = v
48
+ when "L" then name.locality = v
49
+ when "ST" then name.state = v
50
+ when "C" then name.country = v
51
+ when "O" then name.organization = v
52
+ when "OU" then name.organizational_unit = v
53
+ end
54
+ end
36
55
  name
37
56
  end
38
57
  end
39
- end
58
+ end
@@ -4,40 +4,40 @@ module CertificateAuthority
4
4
  def to_s
5
5
  raise "Implementation required"
6
6
  end
7
-
7
+
8
8
  def config_extensions
9
9
  {}
10
10
  end
11
-
11
+
12
12
  def openssl_identifier
13
13
  raise "Implementation required"
14
14
  end
15
15
  end
16
-
16
+
17
17
  class BasicContraints
18
18
  include ExtensionAPI
19
19
  include ActiveModel::Validations
20
20
  attr_accessor :ca
21
21
  attr_accessor :path_len
22
22
  validates :ca, :inclusion => [true,false]
23
-
23
+
24
24
  def initialize
25
25
  self.ca = false
26
26
  end
27
-
27
+
28
28
  def is_ca?
29
29
  self.ca
30
30
  end
31
-
31
+
32
32
  def path_len=(value)
33
33
  raise "path_len must be a non-negative integer" if value < 0 or !value.is_a?(Fixnum)
34
34
  @path_len = value
35
35
  end
36
-
36
+
37
37
  def openssl_identifier
38
38
  "basicConstraints"
39
39
  end
40
-
40
+
41
41
  def to_s
42
42
  result = ""
43
43
  result += "CA:#{self.ca}"
@@ -45,20 +45,20 @@ module CertificateAuthority
45
45
  result
46
46
  end
47
47
  end
48
-
48
+
49
49
  class CrlDistributionPoints
50
50
  include ExtensionAPI
51
-
51
+
52
52
  attr_accessor :uri
53
-
53
+
54
54
  def initialize
55
- self.uri = "http://moo.crlendPoint.example.com/something.crl"
55
+ # self.uri = "http://moo.crlendPoint.example.com/something.crl"
56
56
  end
57
-
57
+
58
58
  def openssl_identifier
59
59
  "crlDistributionPoints"
60
60
  end
61
-
61
+
62
62
  ## NB: At this time it seems OpenSSL's extension handlers don't support
63
63
  ## any of the config options the docs claim to support... everything comes back
64
64
  ## "missing value" on GENERAL NAME. Even if copied verbatim
@@ -68,141 +68,155 @@ module CertificateAuthority
68
68
  # "issuer_sect" => {"CN" => "crlissuer.com", "C" => "US", "O" => "shudder"}
69
69
  }
70
70
  end
71
-
71
+
72
72
  def to_s
73
+ return "" if self.uri.nil?
73
74
  "URI:#{self.uri}"
74
75
  end
75
76
  end
76
-
77
+
77
78
  class SubjectKeyIdentifier
78
79
  include ExtensionAPI
79
80
  def openssl_identifier
80
81
  "subjectKeyIdentifier"
81
82
  end
82
-
83
+
83
84
  def to_s
84
85
  "hash"
85
86
  end
86
87
  end
87
-
88
+
88
89
  class AuthorityKeyIdentifier
89
90
  include ExtensionAPI
90
-
91
+
91
92
  def openssl_identifier
92
93
  "authorityKeyIdentifier"
93
94
  end
94
-
95
+
95
96
  def to_s
96
97
  "keyid,issuer"
97
98
  end
98
99
  end
99
-
100
+
100
101
  class AuthorityInfoAccess
101
102
  include ExtensionAPI
102
-
103
+
103
104
  attr_accessor :ocsp
104
-
105
+
105
106
  def initialize
106
107
  self.ocsp = []
107
108
  end
108
-
109
+
109
110
  def openssl_identifier
110
111
  "authorityInfoAccess"
111
112
  end
112
-
113
+
113
114
  def to_s
114
115
  return "" if self.ocsp.empty?
115
116
  "OCSP;URI:#{self.ocsp}"
116
117
  end
117
118
  end
118
-
119
+
119
120
  class KeyUsage
120
121
  include ExtensionAPI
121
-
122
+
122
123
  attr_accessor :usage
123
-
124
+
124
125
  def initialize
125
126
  self.usage = ["digitalSignature", "nonRepudiation"]
126
127
  end
127
-
128
+
128
129
  def openssl_identifier
129
130
  "keyUsage"
130
131
  end
131
-
132
+
132
133
  def to_s
133
134
  "#{self.usage.join(',')}"
134
135
  end
135
136
  end
136
-
137
+
137
138
  class ExtendedKeyUsage
138
139
  include ExtensionAPI
139
-
140
+
140
141
  attr_accessor :usage
141
-
142
+
142
143
  def initialize
143
144
  self.usage = ["serverAuth","clientAuth"]
144
145
  end
145
-
146
+
146
147
  def openssl_identifier
147
148
  "extendedKeyUsage"
148
149
  end
149
-
150
+
150
151
  def to_s
151
152
  "#{self.usage.join(',')}"
152
153
  end
153
154
  end
154
-
155
+
155
156
  class SubjectAlternativeName
156
157
  include ExtensionAPI
157
-
158
- attr_accessor :uris
159
-
158
+
159
+ attr_accessor :uris, :dns_names, :ips
160
+
160
161
  def initialize
161
162
  self.uris = []
163
+ self.dns_names = []
164
+ self.ips = []
162
165
  end
163
-
166
+
164
167
  def uris=(value)
165
168
  raise "URIs must be an array" unless value.is_a?(Array)
166
169
  @uris = value
167
170
  end
168
-
171
+
172
+ def dns_names=(value)
173
+ raise "DNS names must be an array" unless value.is_a?(Array)
174
+ @dns_names = value
175
+ end
176
+
177
+ def ips=(value)
178
+ raise "IPs must be an array" unless value.is_a?(Array)
179
+ @ips = value
180
+ end
181
+
169
182
  def openssl_identifier
170
183
  "subjectAltName"
171
184
  end
172
-
185
+
173
186
  def to_s
174
- if self.uris.empty?
175
- return ""
176
- end
177
- "URI:#{self.uris.join(',URI:')}"
187
+ res = self.uris.map {|u| "URI:#{u}" }
188
+ res += self.dns_names.map {|d| "DNS:#{d}" }
189
+ res += self.ips.map {|i| "IP:#{i}" }
190
+
191
+ return res.join(',')
178
192
  end
179
193
  end
180
-
194
+
181
195
  class CertificatePolicies
182
196
  include ExtensionAPI
183
-
197
+
184
198
  attr_accessor :policy_identifier
185
199
  attr_accessor :cps_uris
186
200
  ##User notice
187
201
  attr_accessor :explicit_text
188
202
  attr_accessor :organization
189
203
  attr_accessor :notice_numbers
190
-
204
+
191
205
  def initialize
192
206
  @contains_data = false
193
207
  end
194
-
195
-
208
+
209
+
196
210
  def openssl_identifier
197
211
  "certificatePolicies"
198
212
  end
199
-
213
+
200
214
  def user_notice=(value={})
201
215
  value.keys.each do |key|
202
216
  self.send("#{key}=".to_sym, value[key])
203
217
  end
204
218
  end
205
-
219
+
206
220
  def config_extensions
207
221
  config_extension = {}
208
222
  custom_policies = {}
@@ -210,43 +224,43 @@ module CertificateAuthority
210
224
  unless self.policy_identifier.nil?
211
225
  custom_policies["policyIdentifier"] = self.policy_identifier
212
226
  end
213
-
227
+
214
228
  if !self.cps_uris.nil? and self.cps_uris.is_a?(Array)
215
229
  self.cps_uris.each_with_index do |cps_uri,i|
216
230
  custom_policies["CPS.#{i}"] = cps_uri
217
231
  end
218
232
  end
219
-
233
+
220
234
  unless self.explicit_text.nil?
221
235
  notice["explicitText"] = self.explicit_text
222
236
  end
223
-
237
+
224
238
  unless self.organization.nil?
225
239
  notice["organization"] = self.organization
226
240
  end
227
-
241
+
228
242
  unless self.notice_numbers.nil?
229
243
  notice["noticeNumbers"] = self.notice_numbers
230
244
  end
231
-
245
+
232
246
  if notice.keys.size > 0
233
247
  custom_policies["userNotice.1"] = "@notice"
234
248
  config_extension["notice"] = notice
235
249
  end
236
-
250
+
237
251
  if custom_policies.keys.size > 0
238
252
  config_extension["custom_policies"] = custom_policies
239
253
  @contains_data = true
240
254
  end
241
-
255
+
242
256
  config_extension
243
257
  end
244
-
258
+
245
259
  def to_s
246
260
  return "" unless @contains_data
247
261
  "ia5org,@custom_policies"
248
262
  end
249
263
  end
250
-
264
+
251
265
  end
252
- end
266
+ end