certificate_authority 0.1.6 → 1.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rspec +3 -0
- data/.travis.yml +11 -0
- data/Gemfile +2 -8
- data/Gemfile.lock +71 -31
- data/README.rdoc +91 -2
- data/Rakefile +6 -41
- data/certificate_authority.gemspec +22 -66
- data/lib/certificate_authority.rb +6 -5
- data/lib/certificate_authority/certificate.rb +91 -36
- data/lib/certificate_authority/certificate_revocation_list.rb +34 -14
- data/lib/certificate_authority/core_extensions.rb +46 -0
- data/lib/certificate_authority/distinguished_name.rb +64 -16
- data/lib/certificate_authority/extensions.rb +417 -45
- data/lib/certificate_authority/key_material.rb +30 -9
- data/lib/certificate_authority/ocsp_handler.rb +75 -5
- data/lib/certificate_authority/pkcs11_key_material.rb +0 -2
- data/lib/certificate_authority/revocable.rb +14 -0
- data/lib/certificate_authority/serial_number.rb +15 -2
- data/lib/certificate_authority/signing_request.rb +91 -0
- data/lib/certificate_authority/validations.rb +31 -0
- data/lib/certificate_authority/version.rb +3 -0
- metadata +76 -48
- data/VERSION.yml +0 -5
- data/spec/spec_helper.rb +0 -4
- data/spec/units/certificate_authority_spec.rb +0 -4
- data/spec/units/certificate_revocation_list_spec.rb +0 -68
- data/spec/units/certificate_spec.rb +0 -428
- data/spec/units/distinguished_name_spec.rb +0 -59
- data/spec/units/extensions_spec.rb +0 -115
- data/spec/units/key_material_spec.rb +0 -100
- data/spec/units/ocsp_handler_spec.rb +0 -104
- data/spec/units/pkcs11_key_material_spec.rb +0 -41
- data/spec/units/serial_number_spec.rb +0 -20
- data/spec/units/signing_entity_spec.rb +0 -4
- data/spec/units/units_helper.rb +0 -1
@@ -5,6 +5,10 @@ module CertificateAuthority
|
|
5
5
|
raise "Implementation required"
|
6
6
|
end
|
7
7
|
|
8
|
+
def self.parse(value, critical)
|
9
|
+
raise "Implementation required"
|
10
|
+
end
|
11
|
+
|
8
12
|
def config_extensions
|
9
13
|
{}
|
10
14
|
end
|
@@ -12,51 +16,102 @@ module CertificateAuthority
|
|
12
16
|
def openssl_identifier
|
13
17
|
raise "Implementation required"
|
14
18
|
end
|
19
|
+
|
20
|
+
def ==(value)
|
21
|
+
raise "Implementation required"
|
22
|
+
end
|
15
23
|
end
|
16
24
|
|
17
|
-
|
25
|
+
# Specifies whether an X.509v3 certificate can act as a CA, signing other
|
26
|
+
# certificates to be verified. If set, a path length constraint can also be
|
27
|
+
# specified.
|
28
|
+
# Reference: Section 4.2.1.10 of RFC3280
|
29
|
+
# http://tools.ietf.org/html/rfc3280#section-4.2.1.10
|
30
|
+
class BasicConstraints
|
31
|
+
OPENSSL_IDENTIFIER = "basicConstraints"
|
32
|
+
|
18
33
|
include ExtensionAPI
|
19
|
-
include
|
34
|
+
include Validations
|
35
|
+
|
36
|
+
attr_accessor :critical
|
20
37
|
attr_accessor :ca
|
21
38
|
attr_accessor :path_len
|
22
|
-
|
39
|
+
|
40
|
+
def validate
|
41
|
+
unless [true, false].include? self.critical
|
42
|
+
errors.add :critical, 'must be true or false'
|
43
|
+
end
|
44
|
+
unless [true, false].include? self.ca
|
45
|
+
errors.add :ca, 'must be true or false'
|
46
|
+
end
|
47
|
+
end
|
23
48
|
|
24
49
|
def initialize
|
25
|
-
|
50
|
+
@critical = false
|
51
|
+
@ca = false
|
52
|
+
end
|
53
|
+
|
54
|
+
def openssl_identifier
|
55
|
+
OPENSSL_IDENTIFIER
|
26
56
|
end
|
27
57
|
|
28
58
|
def is_ca?
|
29
|
-
|
59
|
+
@ca
|
30
60
|
end
|
31
61
|
|
32
62
|
def path_len=(value)
|
33
|
-
|
63
|
+
fail(ArgumentError, "path_len must be a non-negative integer") if !value.is_a?(Integer) || value < 0
|
34
64
|
@path_len = value
|
35
65
|
end
|
36
66
|
|
37
|
-
def
|
38
|
-
|
67
|
+
def to_s
|
68
|
+
res = []
|
69
|
+
res << "CA:#{@ca}"
|
70
|
+
res << "pathlen:#{@path_len}" unless @path_len.nil?
|
71
|
+
res.join(',')
|
39
72
|
end
|
40
73
|
|
41
|
-
def
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
74
|
+
def ==(o)
|
75
|
+
o.class == self.class && o.state == state
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.parse(value, critical)
|
79
|
+
obj = self.new
|
80
|
+
return obj if value.nil?
|
81
|
+
obj.critical = critical
|
82
|
+
value.split(/,\s*/).each do |v|
|
83
|
+
c = v.split(':', 2)
|
84
|
+
obj.ca = (c.last.upcase == "TRUE") if c.first == "CA"
|
85
|
+
obj.path_len = c.last.to_i if c.first == "pathlen"
|
86
|
+
end
|
87
|
+
obj
|
88
|
+
end
|
89
|
+
|
90
|
+
protected
|
91
|
+
def state
|
92
|
+
[@critical,@ca,@path_len]
|
46
93
|
end
|
47
94
|
end
|
48
95
|
|
96
|
+
# Specifies where CRL information be be retrieved. This extension isn't
|
97
|
+
# critical, but is recommended for proper CAs.
|
98
|
+
# Reference: Section 4.2.1.14 of RFC3280
|
99
|
+
# http://tools.ietf.org/html/rfc3280#section-4.2.1.14
|
49
100
|
class CrlDistributionPoints
|
101
|
+
OPENSSL_IDENTIFIER = "crlDistributionPoints"
|
102
|
+
|
50
103
|
include ExtensionAPI
|
51
104
|
|
52
|
-
attr_accessor :
|
105
|
+
attr_accessor :critical
|
106
|
+
attr_accessor :uris
|
53
107
|
|
54
108
|
def initialize
|
55
|
-
|
109
|
+
@critical = false
|
110
|
+
@uris = []
|
56
111
|
end
|
57
112
|
|
58
113
|
def openssl_identifier
|
59
|
-
|
114
|
+
OPENSSL_IDENTIFIER
|
60
115
|
end
|
61
116
|
|
62
117
|
## NB: At this time it seems OpenSSL's extension handlers don't support
|
@@ -69,99 +124,302 @@ module CertificateAuthority
|
|
69
124
|
}
|
70
125
|
end
|
71
126
|
|
127
|
+
# This is for legacy support. Technically it can (and probably should)
|
128
|
+
# be an array. But if someone is calling the old accessor we shouldn't
|
129
|
+
# necessarily break it.
|
130
|
+
def uri=(value)
|
131
|
+
@uris << value
|
132
|
+
end
|
133
|
+
|
72
134
|
def to_s
|
73
|
-
|
74
|
-
|
135
|
+
res = []
|
136
|
+
@uris.each do |uri|
|
137
|
+
res << "URI:#{uri}"
|
138
|
+
end
|
139
|
+
res.join(',')
|
140
|
+
end
|
141
|
+
|
142
|
+
def ==(o)
|
143
|
+
o.class == self.class && o.state == state
|
144
|
+
end
|
145
|
+
|
146
|
+
def self.parse(value, critical)
|
147
|
+
obj = self.new
|
148
|
+
return obj if value.nil?
|
149
|
+
obj.critical = critical
|
150
|
+
value.split(/,\s*/).each do |v|
|
151
|
+
c = v.split(':', 2)
|
152
|
+
obj.uris << c.last if c.first == "URI"
|
153
|
+
end
|
154
|
+
obj
|
155
|
+
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
def state
|
159
|
+
[@critical,@uri]
|
75
160
|
end
|
76
161
|
end
|
77
162
|
|
163
|
+
# Identifies the public key associated with a given certificate.
|
164
|
+
# Should be required for "CA" certificates.
|
165
|
+
# Reference: Section 4.2.1.2 of RFC3280
|
166
|
+
# http://tools.ietf.org/html/rfc3280#section-4.2.1.2
|
78
167
|
class SubjectKeyIdentifier
|
168
|
+
OPENSSL_IDENTIFIER = "subjectKeyIdentifier"
|
169
|
+
|
79
170
|
include ExtensionAPI
|
171
|
+
|
172
|
+
attr_accessor :critical
|
173
|
+
attr_accessor :identifier
|
174
|
+
|
175
|
+
def initialize
|
176
|
+
@critical = false
|
177
|
+
@identifier = "hash"
|
178
|
+
end
|
179
|
+
|
80
180
|
def openssl_identifier
|
81
|
-
|
181
|
+
OPENSSL_IDENTIFIER
|
82
182
|
end
|
83
183
|
|
84
184
|
def to_s
|
85
|
-
|
185
|
+
res = []
|
186
|
+
res << @identifier
|
187
|
+
res.join(',')
|
188
|
+
end
|
189
|
+
|
190
|
+
def ==(o)
|
191
|
+
o.class == self.class && o.state == state
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.parse(value, critical)
|
195
|
+
obj = self.new
|
196
|
+
return obj if value.nil?
|
197
|
+
obj.critical = critical
|
198
|
+
obj.identifier = value
|
199
|
+
obj
|
200
|
+
end
|
201
|
+
|
202
|
+
protected
|
203
|
+
def state
|
204
|
+
[@critical,@identifier]
|
86
205
|
end
|
87
206
|
end
|
88
207
|
|
208
|
+
# Identifies the public key associated with a given private key.
|
209
|
+
# Reference: Section 4.2.1.1 of RFC3280
|
210
|
+
# http://tools.ietf.org/html/rfc3280#section-4.2.1.1
|
89
211
|
class AuthorityKeyIdentifier
|
212
|
+
OPENSSL_IDENTIFIER = "authorityKeyIdentifier"
|
213
|
+
|
90
214
|
include ExtensionAPI
|
91
215
|
|
216
|
+
attr_accessor :critical
|
217
|
+
attr_accessor :identifier
|
218
|
+
|
219
|
+
def initialize
|
220
|
+
@critical = false
|
221
|
+
@identifier = ["keyid", "issuer"]
|
222
|
+
end
|
223
|
+
|
92
224
|
def openssl_identifier
|
93
|
-
|
225
|
+
OPENSSL_IDENTIFIER
|
94
226
|
end
|
95
227
|
|
96
228
|
def to_s
|
97
|
-
|
229
|
+
res = []
|
230
|
+
res += @identifier
|
231
|
+
res.join(',')
|
232
|
+
end
|
233
|
+
|
234
|
+
def ==(o)
|
235
|
+
o.class == self.class && o.state == state
|
236
|
+
end
|
237
|
+
|
238
|
+
def self.parse(value, critical)
|
239
|
+
obj = self.new
|
240
|
+
return obj if value.nil?
|
241
|
+
obj.critical = critical
|
242
|
+
obj.identifier = value.split(/,\s*/).last.chomp
|
243
|
+
obj
|
244
|
+
end
|
245
|
+
|
246
|
+
protected
|
247
|
+
def state
|
248
|
+
[@critical,@identifier]
|
98
249
|
end
|
99
250
|
end
|
100
251
|
|
252
|
+
# Specifies how to access CA information and services for the CA that
|
253
|
+
# issued this certificate.
|
254
|
+
# Generally used to specify OCSP servers.
|
255
|
+
# Reference: Section 4.2.2.1 of RFC3280
|
256
|
+
# http://tools.ietf.org/html/rfc3280#section-4.2.2.1
|
101
257
|
class AuthorityInfoAccess
|
258
|
+
OPENSSL_IDENTIFIER = "authorityInfoAccess"
|
259
|
+
|
102
260
|
include ExtensionAPI
|
103
261
|
|
262
|
+
attr_accessor :critical
|
104
263
|
attr_accessor :ocsp
|
264
|
+
attr_accessor :ca_issuers
|
105
265
|
|
106
266
|
def initialize
|
107
|
-
|
267
|
+
@critical = false
|
268
|
+
@ocsp = []
|
269
|
+
@ca_issuers = []
|
108
270
|
end
|
109
271
|
|
110
272
|
def openssl_identifier
|
111
|
-
|
273
|
+
OPENSSL_IDENTIFIER
|
112
274
|
end
|
113
275
|
|
114
276
|
def to_s
|
115
|
-
|
116
|
-
"OCSP;URI:#{
|
277
|
+
res = []
|
278
|
+
res += @ocsp.map {|o| "OCSP;URI:#{o}" }
|
279
|
+
res += @ca_issuers.map {|c| "caIssuers;URI:#{c}" }
|
280
|
+
res.join(',')
|
281
|
+
end
|
282
|
+
|
283
|
+
def ==(o)
|
284
|
+
o.class == self.class && o.state == state
|
285
|
+
end
|
286
|
+
|
287
|
+
def self.parse(value, critical)
|
288
|
+
obj = self.new
|
289
|
+
return obj if value.nil?
|
290
|
+
obj.critical = critical
|
291
|
+
value.split("\n").each do |v|
|
292
|
+
if v =~ /^OCSP/
|
293
|
+
obj.ocsp << v.split.last
|
294
|
+
end
|
295
|
+
|
296
|
+
if v =~ /^CA Issuers/
|
297
|
+
obj.ca_issuers << v.split.last
|
298
|
+
end
|
299
|
+
end
|
300
|
+
obj
|
301
|
+
end
|
302
|
+
|
303
|
+
protected
|
304
|
+
def state
|
305
|
+
[@critical,@ocsp,@ca_issuers]
|
117
306
|
end
|
118
307
|
end
|
119
308
|
|
309
|
+
# Specifies the allowed usage purposes of the keypair specified in this certificate.
|
310
|
+
# Reference: Section 4.2.1.3 of RFC3280
|
311
|
+
# http://tools.ietf.org/html/rfc3280#section-4.2.1.3
|
312
|
+
#
|
313
|
+
# Note: OpenSSL when parsing an extension will return results in the form
|
314
|
+
# 'Digital Signature', but on signing you have to set it to 'digitalSignature'.
|
315
|
+
# So copying an extension from an imported cert isn't going to work yet.
|
120
316
|
class KeyUsage
|
317
|
+
OPENSSL_IDENTIFIER = "keyUsage"
|
318
|
+
|
121
319
|
include ExtensionAPI
|
122
320
|
|
321
|
+
attr_accessor :critical
|
123
322
|
attr_accessor :usage
|
124
323
|
|
125
324
|
def initialize
|
126
|
-
|
325
|
+
@critical = false
|
326
|
+
@usage = ["digitalSignature", "nonRepudiation"]
|
127
327
|
end
|
128
328
|
|
129
329
|
def openssl_identifier
|
130
|
-
|
330
|
+
OPENSSL_IDENTIFIER
|
131
331
|
end
|
132
332
|
|
133
333
|
def to_s
|
134
|
-
|
334
|
+
res = []
|
335
|
+
res += @usage
|
336
|
+
res.join(',')
|
337
|
+
end
|
338
|
+
|
339
|
+
def ==(o)
|
340
|
+
o.class == self.class && o.state == state
|
341
|
+
end
|
342
|
+
|
343
|
+
def self.parse(value, critical)
|
344
|
+
obj = self.new
|
345
|
+
return obj if value.nil?
|
346
|
+
obj.critical = critical
|
347
|
+
obj.usage = value.split(/,\s*/)
|
348
|
+
obj
|
349
|
+
end
|
350
|
+
|
351
|
+
protected
|
352
|
+
def state
|
353
|
+
[@critical,@usage]
|
135
354
|
end
|
136
355
|
end
|
137
356
|
|
357
|
+
# Specifies even more allowed usages in addition to what is specified in
|
358
|
+
# the Key Usage extension.
|
359
|
+
# Reference: Section 4.2.1.13 of RFC3280
|
360
|
+
# http://tools.ietf.org/html/rfc3280#section-4.2.1.13
|
138
361
|
class ExtendedKeyUsage
|
362
|
+
OPENSSL_IDENTIFIER = "extendedKeyUsage"
|
363
|
+
|
139
364
|
include ExtensionAPI
|
140
365
|
|
366
|
+
attr_accessor :critical
|
141
367
|
attr_accessor :usage
|
142
368
|
|
143
369
|
def initialize
|
144
|
-
|
370
|
+
@critical = false
|
371
|
+
@usage = ["serverAuth"]
|
145
372
|
end
|
146
373
|
|
147
374
|
def openssl_identifier
|
148
|
-
|
375
|
+
OPENSSL_IDENTIFIER
|
149
376
|
end
|
150
377
|
|
151
378
|
def to_s
|
152
|
-
|
379
|
+
res = []
|
380
|
+
res += @usage
|
381
|
+
res.join(',')
|
382
|
+
end
|
383
|
+
|
384
|
+
def ==(o)
|
385
|
+
o.class == self.class && o.state == state
|
386
|
+
end
|
387
|
+
|
388
|
+
def self.parse(value, critical)
|
389
|
+
obj = self.new
|
390
|
+
return obj if value.nil?
|
391
|
+
obj.critical = critical
|
392
|
+
obj.usage = value.split(/,\s*/)
|
393
|
+
obj
|
394
|
+
end
|
395
|
+
|
396
|
+
protected
|
397
|
+
def state
|
398
|
+
[@critical,@usage]
|
153
399
|
end
|
154
400
|
end
|
155
401
|
|
402
|
+
# Specifies additional "names" for which this certificate is valid.
|
403
|
+
# Reference: Section 4.2.1.7 of RFC3280
|
404
|
+
# http://tools.ietf.org/html/rfc3280#section-4.2.1.7
|
156
405
|
class SubjectAlternativeName
|
406
|
+
OPENSSL_IDENTIFIER = "subjectAltName"
|
407
|
+
|
157
408
|
include ExtensionAPI
|
158
409
|
|
159
|
-
attr_accessor :
|
410
|
+
attr_accessor :critical
|
411
|
+
attr_accessor :uris, :dns_names, :ips, :emails
|
160
412
|
|
161
413
|
def initialize
|
162
|
-
|
163
|
-
|
164
|
-
|
414
|
+
@critical = false
|
415
|
+
@uris = []
|
416
|
+
@dns_names = []
|
417
|
+
@ips = []
|
418
|
+
@emails = []
|
419
|
+
end
|
420
|
+
|
421
|
+
def openssl_identifier
|
422
|
+
OPENSSL_IDENTIFIER
|
165
423
|
end
|
166
424
|
|
167
425
|
def uris=(value)
|
@@ -179,22 +437,50 @@ module CertificateAuthority
|
|
179
437
|
@ips = value
|
180
438
|
end
|
181
439
|
|
182
|
-
def
|
183
|
-
"
|
440
|
+
def emails=(value)
|
441
|
+
raise "Emails must be an array" unless value.is_a?(Array)
|
442
|
+
@emails = value
|
184
443
|
end
|
185
444
|
|
186
445
|
def to_s
|
187
|
-
res =
|
188
|
-
res +=
|
189
|
-
res +=
|
446
|
+
res = []
|
447
|
+
res += @uris.map {|u| "URI:#{u}" }
|
448
|
+
res += @dns_names.map {|d| "DNS:#{d}" }
|
449
|
+
res += @ips.map {|i| "IP:#{i}" }
|
450
|
+
res += @emails.map {|i| "email:#{i}" }
|
451
|
+
res.join(',')
|
452
|
+
end
|
453
|
+
|
454
|
+
def ==(o)
|
455
|
+
o.class == self.class && o.state == state
|
456
|
+
end
|
457
|
+
|
458
|
+
def self.parse(value, critical)
|
459
|
+
obj = self.new
|
460
|
+
return obj if value.nil?
|
461
|
+
obj.critical = critical
|
462
|
+
value.split(/,\s*/).each do |v|
|
463
|
+
c = v.split(':', 2)
|
464
|
+
obj.uris << c.last if c.first == "URI"
|
465
|
+
obj.dns_names << c.last if c.first == "DNS"
|
466
|
+
obj.ips << c.last if c.first == "IP"
|
467
|
+
obj.emails << c.last if c.first == "EMAIL"
|
468
|
+
end
|
469
|
+
obj
|
470
|
+
end
|
190
471
|
|
191
|
-
|
472
|
+
protected
|
473
|
+
def state
|
474
|
+
[@critical,@uris,@dns_names,@ips,@emails]
|
192
475
|
end
|
193
476
|
end
|
194
477
|
|
195
478
|
class CertificatePolicies
|
479
|
+
OPENSSL_IDENTIFIER = "certificatePolicies"
|
480
|
+
|
196
481
|
include ExtensionAPI
|
197
482
|
|
483
|
+
attr_accessor :critical
|
198
484
|
attr_accessor :policy_identifier
|
199
485
|
attr_accessor :cps_uris
|
200
486
|
##User notice
|
@@ -203,12 +489,12 @@ module CertificateAuthority
|
|
203
489
|
attr_accessor :notice_numbers
|
204
490
|
|
205
491
|
def initialize
|
492
|
+
self.critical = false
|
206
493
|
@contains_data = false
|
207
494
|
end
|
208
495
|
|
209
|
-
|
210
496
|
def openssl_identifier
|
211
|
-
|
497
|
+
OPENSSL_IDENTIFIER
|
212
498
|
end
|
213
499
|
|
214
500
|
def user_notice=(value={})
|
@@ -258,7 +544,93 @@ module CertificateAuthority
|
|
258
544
|
|
259
545
|
def to_s
|
260
546
|
return "" unless @contains_data
|
261
|
-
|
547
|
+
res = []
|
548
|
+
res << "ia5org"
|
549
|
+
res += @config_extensions["custom_policies"] unless @config_extensions.nil?
|
550
|
+
res.join(',')
|
551
|
+
end
|
552
|
+
|
553
|
+
def self.parse(value, critical)
|
554
|
+
obj = self.new
|
555
|
+
return obj if value.nil?
|
556
|
+
obj.critical = critical
|
557
|
+
value.split(/,\s*/).each do |v|
|
558
|
+
c = v.split(':', 2)
|
559
|
+
obj.policy_identifier = c.last if c.first == "policyIdentifier"
|
560
|
+
obj.cps_uris << c.last if c.first =~ %r{CPS.\d+}
|
561
|
+
# TODO: explicit_text, organization, notice_numbers
|
562
|
+
end
|
563
|
+
obj
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
# DEPRECATED
|
568
|
+
# Specifics the purposes for which a certificate can be used.
|
569
|
+
# The basicConstraints, keyUsage, and extendedKeyUsage extensions are now used instead.
|
570
|
+
# https://www.openssl.org/docs/apps/x509v3_config.html#Netscape_Certificate_Type
|
571
|
+
class NetscapeCertificateType
|
572
|
+
OPENSSL_IDENTIFIER = "nsCertType"
|
573
|
+
|
574
|
+
include ExtensionAPI
|
575
|
+
|
576
|
+
attr_accessor :critical
|
577
|
+
attr_accessor :flags
|
578
|
+
|
579
|
+
def initialize
|
580
|
+
self.critical = false
|
581
|
+
self.flags = []
|
582
|
+
end
|
583
|
+
|
584
|
+
def openssl_identifier
|
585
|
+
OPENSSL_IDENTIFIER
|
586
|
+
end
|
587
|
+
|
588
|
+
def to_s
|
589
|
+
res = []
|
590
|
+
res += self.flags
|
591
|
+
res.join(',')
|
592
|
+
end
|
593
|
+
|
594
|
+
def self.parse(value, critical)
|
595
|
+
obj = self.new
|
596
|
+
return obj if value.nil?
|
597
|
+
obj.critical = critical
|
598
|
+
obj.flags = value.split(/,\s*/)
|
599
|
+
obj
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
# DEPRECATED
|
604
|
+
# Contains a comment which will be displayed when the certificate is viewed in some browsers.
|
605
|
+
# https://www.openssl.org/docs/apps/x509v3_config.html#Netscape_String_extensions_
|
606
|
+
class NetscapeComment
|
607
|
+
OPENSSL_IDENTIFIER = "nsComment"
|
608
|
+
|
609
|
+
include ExtensionAPI
|
610
|
+
|
611
|
+
attr_accessor :critical
|
612
|
+
attr_accessor :comment
|
613
|
+
|
614
|
+
def initialize
|
615
|
+
self.critical = false
|
616
|
+
end
|
617
|
+
|
618
|
+
def openssl_identifier
|
619
|
+
OPENSSL_IDENTIFIER
|
620
|
+
end
|
621
|
+
|
622
|
+
def to_s
|
623
|
+
res = []
|
624
|
+
res << self.comment if self.comment
|
625
|
+
res.join(',')
|
626
|
+
end
|
627
|
+
|
628
|
+
def self.parse(value, critical)
|
629
|
+
obj = self.new
|
630
|
+
return obj if value.nil?
|
631
|
+
obj.critical = critical
|
632
|
+
obj.comment = value
|
633
|
+
obj
|
262
634
|
end
|
263
635
|
end
|
264
636
|
|