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
@@ -15,11 +15,30 @@ module CertificateAuthority
|
|
15
15
|
def is_in_memory?
|
16
16
|
raise "Required implementation"
|
17
17
|
end
|
18
|
+
|
19
|
+
def self.from_x509_key_pair(pair,password=nil)
|
20
|
+
if password.nil?
|
21
|
+
key = OpenSSL::PKey::RSA.new(pair)
|
22
|
+
else
|
23
|
+
key = OpenSSL::PKey::RSA.new(pair,password)
|
24
|
+
end
|
25
|
+
mem_key = MemoryKeyMaterial.new
|
26
|
+
mem_key.public_key = key.public_key
|
27
|
+
mem_key.private_key = key
|
28
|
+
mem_key
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.from_x509_public_key(public_key_pem)
|
32
|
+
key = OpenSSL::PKey::RSA.new(public_key_pem)
|
33
|
+
signing_request_key = SigningRequestKeyMaterial.new
|
34
|
+
signing_request_key.public_key = key.public_key
|
35
|
+
signing_request_key
|
36
|
+
end
|
18
37
|
end
|
19
38
|
|
20
39
|
class MemoryKeyMaterial
|
21
40
|
include KeyMaterial
|
22
|
-
include
|
41
|
+
include Validations
|
23
42
|
|
24
43
|
attr_accessor :keypair
|
25
44
|
attr_accessor :private_key
|
@@ -28,11 +47,13 @@ module CertificateAuthority
|
|
28
47
|
def initialize
|
29
48
|
end
|
30
49
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
50
|
+
def validate
|
51
|
+
if private_key.nil?
|
52
|
+
errors.add :private_key, "cannot be blank"
|
53
|
+
end
|
54
|
+
if public_key.nil?
|
55
|
+
errors.add :public_key, "cannot be blank"
|
56
|
+
end
|
36
57
|
end
|
37
58
|
|
38
59
|
def is_in_hardware?
|
@@ -61,10 +82,10 @@ module CertificateAuthority
|
|
61
82
|
|
62
83
|
class SigningRequestKeyMaterial
|
63
84
|
include KeyMaterial
|
64
|
-
include
|
85
|
+
include Validations
|
65
86
|
|
66
|
-
|
67
|
-
|
87
|
+
def validate
|
88
|
+
errors.add :public_key, "cannot be blank" if public_key.nil?
|
68
89
|
end
|
69
90
|
|
70
91
|
attr_accessor :public_key
|
@@ -1,6 +1,74 @@
|
|
1
1
|
module CertificateAuthority
|
2
|
+
class OCSPResponseBuilder
|
3
|
+
attr_accessor :ocsp_response
|
4
|
+
attr_accessor :verification_mechanism
|
5
|
+
attr_accessor :ocsp_request_reader
|
6
|
+
attr_accessor :parent
|
7
|
+
attr_accessor :next_update
|
8
|
+
|
9
|
+
GOOD = OpenSSL::OCSP::V_CERTSTATUS_GOOD
|
10
|
+
REVOKED = OpenSSL::OCSP::V_CERTSTATUS_REVOKED
|
11
|
+
|
12
|
+
NO_REASON=0
|
13
|
+
KEY_COMPROMISED=OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE
|
14
|
+
UNSPECIFIED=OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED
|
15
|
+
|
16
|
+
def build_response()
|
17
|
+
raise "Requires a parent for signing" if @parent.nil?
|
18
|
+
if @verification_mechanism.nil?
|
19
|
+
## If no verification callback is provided we're marking it GOOD
|
20
|
+
@verification_mechanism = lambda {|cert_id| [GOOD,NO_REASON] }
|
21
|
+
end
|
22
|
+
|
23
|
+
@ocsp_request_reader.ocsp_request.certid.each do |cert_id|
|
24
|
+
result,reason = verification_mechanism.call(cert_id.serial)
|
25
|
+
|
26
|
+
## cert_id, status, reason, rev_time, this update, next update, ext
|
27
|
+
## - unit of time is seconds
|
28
|
+
## - rev_time is currently set to "now"
|
29
|
+
@ocsp_response.add_status(cert_id,
|
30
|
+
result, reason,
|
31
|
+
0, 0, @next_update, nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
@ocsp_response.sign(OpenSSL::X509::Certificate.new(@parent.to_pem), @parent.key_material.private_key, nil, nil)
|
35
|
+
OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, @ocsp_response)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.from_request_reader(request_reader,verification_mechanism=nil)
|
39
|
+
response_builder = OCSPResponseBuilder.new
|
40
|
+
response_builder.ocsp_request_reader = request_reader
|
41
|
+
|
42
|
+
ocsp_response = OpenSSL::OCSP::BasicResponse.new
|
43
|
+
ocsp_response.copy_nonce(request_reader.ocsp_request)
|
44
|
+
response_builder.ocsp_response = ocsp_response
|
45
|
+
response_builder.next_update = 60*15 #Default of 15 minutes
|
46
|
+
response_builder
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class OCSPRequestReader
|
51
|
+
attr_accessor :raw_ocsp_request
|
52
|
+
attr_accessor :ocsp_request
|
53
|
+
|
54
|
+
def serial_numbers
|
55
|
+
@ocsp_request.certid.collect do |cert_id|
|
56
|
+
cert_id.serial
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.from_der(request_body)
|
61
|
+
reader = OCSPRequestReader.new
|
62
|
+
reader.raw_ocsp_request = request_body
|
63
|
+
reader.ocsp_request = OpenSSL::OCSP::Request.new(request_body)
|
64
|
+
|
65
|
+
reader
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
## DEPRECATED
|
2
70
|
class OCSPHandler
|
3
|
-
include
|
71
|
+
include Validations
|
4
72
|
|
5
73
|
attr_accessor :ocsp_request
|
6
74
|
attr_accessor :certificate_ids
|
@@ -10,10 +78,10 @@ module CertificateAuthority
|
|
10
78
|
|
11
79
|
attr_accessor :ocsp_response_body
|
12
80
|
|
13
|
-
validate
|
81
|
+
def validate
|
14
82
|
errors.add :parent, "A parent entity must be set" if parent.nil?
|
83
|
+
all_certificates_available
|
15
84
|
end
|
16
|
-
validate :all_certificates_available
|
17
85
|
|
18
86
|
def initialize
|
19
87
|
self.certificates = {}
|
@@ -24,9 +92,11 @@ module CertificateAuthority
|
|
24
92
|
end
|
25
93
|
|
26
94
|
def extract_certificate_serials
|
27
|
-
|
28
|
-
openssl_request = OpenSSL::OCSP::Request.new(self.ocsp_request)
|
95
|
+
openssl_request = OpenSSL::OCSP::Request.new(@ocsp_request)
|
29
96
|
|
97
|
+
if openssl_request.certid.nil?
|
98
|
+
raise "Invalid openssl request"
|
99
|
+
end
|
30
100
|
self.certificate_ids = openssl_request.certid.collect do |cert_id|
|
31
101
|
cert_id.serial
|
32
102
|
end
|
@@ -1,9 +1,22 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
1
3
|
module CertificateAuthority
|
2
4
|
class SerialNumber
|
3
|
-
include
|
5
|
+
include Validations
|
6
|
+
include Revocable
|
4
7
|
|
5
8
|
attr_accessor :number
|
6
9
|
|
7
|
-
|
10
|
+
def validate
|
11
|
+
if self.number.nil?
|
12
|
+
errors.add :number, "must not be empty"
|
13
|
+
elsif self.number.to_i <= 0
|
14
|
+
errors.add :number, "must be greater than zero"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
self.number = SecureRandom.random_number(2**128-1)
|
20
|
+
end
|
8
21
|
end
|
9
22
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module CertificateAuthority
|
2
|
+
class SigningRequest
|
3
|
+
attr_accessor :distinguished_name
|
4
|
+
attr_accessor :key_material
|
5
|
+
attr_accessor :raw_body
|
6
|
+
attr_accessor :openssl_csr
|
7
|
+
attr_accessor :digest
|
8
|
+
attr_accessor :attributes
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
@attributes = []
|
12
|
+
end
|
13
|
+
|
14
|
+
# Fake attribute for convenience because adding
|
15
|
+
# alternative names on a CSR is remarkably non-trivial.
|
16
|
+
def subject_alternative_names=(alt_names)
|
17
|
+
raise "alt_names must be an Array" unless alt_names.is_a?(Array)
|
18
|
+
|
19
|
+
factory = OpenSSL::X509::ExtensionFactory.new
|
20
|
+
name_list = alt_names.map{|m| "DNS:#{m}"}.join(",")
|
21
|
+
ext = factory.create_ext("subjectAltName",name_list,false)
|
22
|
+
ext_set = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence([ext])])
|
23
|
+
attr = OpenSSL::X509::Attribute.new("extReq", ext_set)
|
24
|
+
@attributes << attr
|
25
|
+
end
|
26
|
+
|
27
|
+
def read_attributes_by_oid(*oids)
|
28
|
+
attributes.detect { |a| oids.include?(a.oid) }
|
29
|
+
end
|
30
|
+
protected :read_attributes_by_oid
|
31
|
+
|
32
|
+
def to_cert
|
33
|
+
cert = Certificate.new
|
34
|
+
if !@distinguished_name.nil?
|
35
|
+
cert.distinguished_name = @distinguished_name
|
36
|
+
end
|
37
|
+
cert.key_material = @key_material
|
38
|
+
if attribute = read_attributes_by_oid('extReq', 'msExtReq')
|
39
|
+
set = OpenSSL::ASN1.decode(attribute.value)
|
40
|
+
seq = set.value.first
|
41
|
+
seq.value.collect { |asn1ext| OpenSSL::X509::Extension.new(asn1ext).to_a }.each do |o, v, c|
|
42
|
+
Certificate::EXTENSIONS.each do |klass|
|
43
|
+
cert.extensions[klass::OPENSSL_IDENTIFIER] = klass.parse(v, c) if v && klass::OPENSSL_IDENTIFIER == o
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
cert
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_pem
|
51
|
+
to_x509_csr.to_pem
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_x509_csr
|
55
|
+
raise "Must specify a DN/subject on csr" if @distinguished_name.nil?
|
56
|
+
raise "Invalid DN in request" unless @distinguished_name.valid?
|
57
|
+
raise "CSR must have key material" if @key_material.nil?
|
58
|
+
raise "CSR must include a public key on key material" if @key_material.public_key.nil?
|
59
|
+
raise "Need a private key on key material for CSR generation" if @key_material.private_key.nil?
|
60
|
+
|
61
|
+
opensslcsr = OpenSSL::X509::Request.new
|
62
|
+
opensslcsr.subject = @distinguished_name.to_x509_name
|
63
|
+
opensslcsr.public_key = @key_material.public_key
|
64
|
+
opensslcsr.attributes = @attributes unless @attributes.nil?
|
65
|
+
opensslcsr.sign @key_material.private_key, OpenSSL::Digest.new(@digest || "SHA512")
|
66
|
+
opensslcsr
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.from_x509_csr(raw_csr)
|
70
|
+
csr = SigningRequest.new
|
71
|
+
openssl_csr = OpenSSL::X509::Request.new(raw_csr)
|
72
|
+
csr.distinguished_name = DistinguishedName.from_openssl openssl_csr.subject
|
73
|
+
csr.raw_body = raw_csr
|
74
|
+
csr.openssl_csr = openssl_csr
|
75
|
+
csr.attributes = openssl_csr.attributes
|
76
|
+
key_material = SigningRequestKeyMaterial.new
|
77
|
+
key_material.public_key = openssl_csr.public_key
|
78
|
+
csr.key_material = key_material
|
79
|
+
csr
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.from_netscape_spkac(raw_spkac)
|
83
|
+
openssl_spkac = OpenSSL::Netscape::SPKI.new raw_spkac
|
84
|
+
csr = SigningRequest.new
|
85
|
+
csr.raw_body = raw_spkac
|
86
|
+
key_material = SigningRequestKeyMaterial.new
|
87
|
+
key_material.public_key = openssl_spkac.public_key
|
88
|
+
csr
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# This is a super simple replacement for ActiveSupport::Validations
|
3
|
+
#
|
4
|
+
|
5
|
+
module CertificateAuthority
|
6
|
+
class Errors < Array
|
7
|
+
def add(symbol, msg)
|
8
|
+
self.push([symbol, msg])
|
9
|
+
end
|
10
|
+
def full_messages
|
11
|
+
self.map {|i| i[0].to_s + ": " + i[1]}.join("\n")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Validations
|
16
|
+
def valid?
|
17
|
+
@errors = Errors.new
|
18
|
+
validate
|
19
|
+
errors.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
# must be overridden
|
23
|
+
def validate
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
def errors
|
28
|
+
@errors ||= Errors.new
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
metadata
CHANGED
@@ -1,111 +1,139 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: certificate_authority
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Chris Chandler
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2020-05-28 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement:
|
17
|
-
none: false
|
14
|
+
name: coveralls
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
22
|
-
type: :
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
23
49
|
prerelease: false
|
24
|
-
version_requirements:
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
25
55
|
- !ruby/object:Gem::Dependency
|
26
56
|
name: rspec
|
27
|
-
requirement:
|
28
|
-
none: false
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
29
58
|
requirements:
|
30
|
-
- -
|
59
|
+
- - ">="
|
31
60
|
- !ruby/object:Gem::Version
|
32
61
|
version: '0'
|
33
62
|
type: :development
|
34
63
|
prerelease: false
|
35
|
-
version_requirements:
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
36
69
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
38
|
-
requirement:
|
39
|
-
none: false
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
40
72
|
requirements:
|
41
|
-
- -
|
73
|
+
- - ">="
|
42
74
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
75
|
+
version: '0'
|
44
76
|
type: :development
|
45
77
|
prerelease: false
|
46
|
-
version_requirements:
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
47
83
|
description:
|
48
|
-
email:
|
84
|
+
email:
|
85
|
+
- squanderingtime@gmail.com
|
49
86
|
executables: []
|
50
87
|
extensions: []
|
51
|
-
extra_rdoc_files:
|
52
|
-
- README.rdoc
|
88
|
+
extra_rdoc_files: []
|
53
89
|
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".travis.yml"
|
54
93
|
- Gemfile
|
55
94
|
- Gemfile.lock
|
56
95
|
- README.rdoc
|
57
96
|
- Rakefile
|
58
|
-
- VERSION.yml
|
59
97
|
- certificate_authority.gemspec
|
60
98
|
- lib/certificate_authority.rb
|
61
99
|
- lib/certificate_authority/certificate.rb
|
62
100
|
- lib/certificate_authority/certificate_revocation_list.rb
|
101
|
+
- lib/certificate_authority/core_extensions.rb
|
63
102
|
- lib/certificate_authority/distinguished_name.rb
|
64
103
|
- lib/certificate_authority/extensions.rb
|
65
104
|
- lib/certificate_authority/key_material.rb
|
66
105
|
- lib/certificate_authority/ocsp_handler.rb
|
67
106
|
- lib/certificate_authority/pkcs11_key_material.rb
|
107
|
+
- lib/certificate_authority/revocable.rb
|
68
108
|
- lib/certificate_authority/serial_number.rb
|
69
109
|
- lib/certificate_authority/signing_entity.rb
|
110
|
+
- lib/certificate_authority/signing_request.rb
|
111
|
+
- lib/certificate_authority/validations.rb
|
112
|
+
- lib/certificate_authority/version.rb
|
70
113
|
- lib/tasks/certificate_authority.rake
|
71
|
-
|
72
|
-
- spec/units/certificate_authority_spec.rb
|
73
|
-
- spec/units/certificate_revocation_list_spec.rb
|
74
|
-
- spec/units/certificate_spec.rb
|
75
|
-
- spec/units/distinguished_name_spec.rb
|
76
|
-
- spec/units/extensions_spec.rb
|
77
|
-
- spec/units/key_material_spec.rb
|
78
|
-
- spec/units/ocsp_handler_spec.rb
|
79
|
-
- spec/units/pkcs11_key_material_spec.rb
|
80
|
-
- spec/units/serial_number_spec.rb
|
81
|
-
- spec/units/signing_entity_spec.rb
|
82
|
-
- spec/units/units_helper.rb
|
83
|
-
homepage: http://github.com/cchandler/certificate_authority
|
114
|
+
homepage: https://github.com/cchandler/certificate_authority
|
84
115
|
licenses:
|
85
116
|
- MIT
|
117
|
+
metadata:
|
118
|
+
homepage_uri: https://github.com/cchandler/certificate_authority
|
119
|
+
source_code_uri: https://github.com/cchandler/certificate_authority
|
86
120
|
post_install_message:
|
87
121
|
rdoc_options: []
|
88
122
|
require_paths:
|
89
123
|
- lib
|
90
124
|
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
-
none: false
|
92
125
|
requirements:
|
93
|
-
- -
|
126
|
+
- - ">="
|
94
127
|
- !ruby/object:Gem::Version
|
95
|
-
version: '
|
96
|
-
segments:
|
97
|
-
- 0
|
98
|
-
hash: -2366790866817530073
|
128
|
+
version: '2.4'
|
99
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
-
none: false
|
101
130
|
requirements:
|
102
|
-
- -
|
131
|
+
- - ">="
|
103
132
|
- !ruby/object:Gem::Version
|
104
133
|
version: '0'
|
105
134
|
requirements: []
|
106
|
-
|
107
|
-
rubygems_version: 1.8.15
|
135
|
+
rubygems_version: 3.1.2
|
108
136
|
signing_key:
|
109
|
-
specification_version:
|
137
|
+
specification_version: 4
|
110
138
|
summary: Ruby gem for managing the core functions outlined in RFC-3280 for PKI
|
111
139
|
test_files: []
|