certificate_authority 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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