r509 0.10.0 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/README.mdown +2 -2
- data/Rakefile +2 -3
- data/bin/r509 +77 -80
- data/bin/r509-parse +4 -4
- data/doc/R509.html +60 -60
- data/doc/R509/ASN1.html +158 -48
- data/doc/R509/ASN1/GeneralName.html +157 -154
- data/doc/R509/ASN1/GeneralNames.html +246 -237
- data/doc/R509/CRL.html +41 -39
- data/doc/R509/CRL/Administrator.html +105 -100
- data/doc/R509/CRL/FileReaderWriter.html +146 -98
- data/doc/R509/CRL/ReaderWriter.html +57 -54
- data/doc/R509/CRL/SQLiteReaderWriter.html +727 -0
- data/doc/R509/CRL/SignedList.html +83 -80
- data/doc/R509/CSR.html +184 -162
- data/doc/R509/Cert.html +271 -269
- data/doc/R509/Cert/Extensions.html +62 -63
- data/doc/R509/Cert/Extensions/AuthorityInfoAccess.html +138 -108
- data/doc/R509/Cert/Extensions/AuthorityKeyIdentifier.html +100 -84
- data/doc/R509/Cert/Extensions/BasicConstraints.html +89 -88
- data/doc/R509/Cert/Extensions/CRLDistributionPoints.html +87 -83
- data/doc/R509/Cert/Extensions/CertificatePolicies.html +78 -76
- data/doc/R509/Cert/Extensions/ExtendedKeyUsage.html +128 -125
- data/doc/R509/Cert/Extensions/GeneralNamesMixin.html +83 -78
- data/doc/R509/Cert/Extensions/InhibitAnyPolicy.html +69 -67
- data/doc/R509/Cert/Extensions/KeyUsage.html +138 -135
- data/doc/R509/Cert/Extensions/NameConstraints.html +82 -81
- data/doc/R509/Cert/Extensions/NoticeReference.html +59 -56
- data/doc/R509/Cert/Extensions/OCSPNoCheck.html +70 -69
- data/doc/R509/Cert/Extensions/PolicyConstraints.html +71 -69
- data/doc/R509/Cert/Extensions/PolicyInformation.html +63 -60
- data/doc/R509/Cert/Extensions/PolicyQualifiers.html +60 -57
- data/doc/R509/Cert/Extensions/SubjectAlternativeName.html +91 -87
- data/doc/R509/Cert/Extensions/SubjectKeyIdentifier.html +72 -71
- data/doc/R509/Cert/Extensions/UserNotice.html +60 -57
- data/doc/R509/Cert/Extensions/ValidationMixin.html +43 -40
- data/doc/R509/CertificateAuthority.html +39 -37
- data/doc/R509/CertificateAuthority/OptionsBuilder.html +58 -55
- data/doc/R509/CertificateAuthority/Signer.html +277 -60
- data/doc/R509/Config.html +40 -38
- data/doc/R509/Config/CAConfig.html +255 -188
- data/doc/R509/Config/CAConfigPool.html +64 -61
- data/doc/R509/Config/CertProfile.html +119 -116
- data/doc/R509/Config/SubjectItemPolicy.html +94 -93
- data/doc/R509/Engine.html +60 -56
- data/doc/R509/Helpers.html +99 -96
- data/doc/R509/MessageDigest.html +69 -68
- data/doc/R509/NameSanitizer.html +51 -48
- data/doc/R509/OCSP.html +39 -37
- data/doc/R509/OCSP/Request.html +39 -37
- data/doc/R509/OCSP/Request/Nonce.html +67 -67
- data/doc/R509/OCSP/Response.html +93 -90
- data/doc/R509/OIDMapper.html +48 -46
- data/doc/R509/PrivateKey.html +170 -169
- data/doc/R509/R509Error.html +45 -42
- data/doc/R509/SPKI.html +99 -89
- data/doc/R509/Subject.html +86 -83
- data/doc/R509/Validity.html +57 -57
- data/doc/R509/Validity/Checker.html +63 -93
- data/doc/R509/Validity/DefaultChecker.html +58 -55
- data/doc/R509/Validity/DefaultWriter.html +62 -59
- data/doc/R509/Validity/Status.html +77 -74
- data/doc/R509/Validity/Writer.html +75 -123
- data/doc/_index.html +37 -31
- data/doc/class_list.html +25 -27
- data/doc/css/full_list.css +32 -31
- data/doc/css/style.css +221 -78
- data/doc/file.CONTRIBUTING.html +29 -30
- data/doc/file.LICENSE.html +29 -30
- data/doc/file.README.html +31 -32
- data/doc/file.YAML.html +33 -34
- data/doc/file.r509.html +39 -48
- data/doc/file_list.html +39 -30
- data/doc/frames.html +10 -21
- data/doc/index.html +31 -32
- data/doc/js/app.js +100 -71
- data/doc/js/full_list.js +168 -130
- data/doc/method_list.html +1788 -1119
- data/doc/top-level-namespace.html +45 -49
- data/lib/r509.rb +21 -7
- data/lib/r509/asn1.rb +45 -32
- data/lib/r509/cert.rb +45 -51
- data/lib/r509/cert/extensions/authority_info_access.rb +49 -23
- data/lib/r509/cert/extensions/authority_key_identifier.rb +16 -11
- data/lib/r509/cert/extensions/base.rb +22 -23
- data/lib/r509/cert/extensions/basic_constraints.rb +11 -12
- data/lib/r509/cert/extensions/certificate_policies.rb +26 -26
- data/lib/r509/cert/extensions/crl_distribution_points.rb +5 -7
- data/lib/r509/cert/extensions/extended_key_usage.rb +5 -5
- data/lib/r509/cert/extensions/inhibit_any_policy.rb +4 -3
- data/lib/r509/cert/extensions/key_usage.rb +5 -5
- data/lib/r509/cert/extensions/name_constraints.rb +16 -16
- data/lib/r509/cert/extensions/ocsp_no_check.rb +3 -3
- data/lib/r509/cert/extensions/policy_constraints.rb +8 -8
- data/lib/r509/cert/extensions/subject_alternative_name.rb +5 -4
- data/lib/r509/cert/extensions/subject_key_identifier.rb +5 -5
- data/lib/r509/cert/extensions/validation_mixin.rb +11 -10
- data/lib/r509/certificate_authority/options_builder.rb +19 -21
- data/lib/r509/certificate_authority/signer.rb +26 -27
- data/lib/r509/config.rb +1 -0
- data/lib/r509/config/ca_config.rb +70 -75
- data/lib/r509/config/cert_profile.rb +9 -8
- data/lib/r509/config/subject_item_policy.rb +25 -28
- data/lib/r509/crl/administrator.rb +19 -20
- data/lib/r509/crl/reader_writer.rb +10 -8
- data/lib/r509/crl/signed_list.rb +4 -4
- data/lib/r509/crl/sqlite_reader_writer.rb +75 -0
- data/lib/r509/csr.rb +54 -60
- data/lib/r509/ec-hack.rb +3 -2
- data/lib/r509/engine.rb +5 -6
- data/lib/r509/exceptions.rb +1 -1
- data/lib/r509/helpers.rb +11 -14
- data/lib/r509/io_helpers.rb +7 -7
- data/lib/r509/message_digest.rb +5 -6
- data/lib/r509/ocsp.rb +11 -13
- data/lib/r509/oid_mapper.rb +2 -2
- data/lib/r509/private_key.rb +28 -32
- data/lib/r509/spki.rb +17 -20
- data/lib/r509/subject.rb +26 -27
- data/lib/r509/trollop.rb +1 -0
- data/lib/r509/validity.rb +30 -21
- data/lib/r509/version.rb +4 -2
- data/r509.yaml +9 -17
- data/spec/asn1_spec.rb +145 -146
- data/spec/cert/extensions/authority_info_access_spec.rb +41 -41
- data/spec/cert/extensions/authority_key_identifier_spec.rb +29 -23
- data/spec/cert/extensions/base_spec.rb +38 -34
- data/spec/cert/extensions/basic_constraints_spec.rb +21 -21
- data/spec/cert/extensions/certificate_policies_spec.rb +99 -87
- data/spec/cert/extensions/crl_distribution_points_spec.rb +24 -25
- data/spec/cert/extensions/extended_key_usage_spec.rb +40 -36
- data/spec/cert/extensions/inhibit_any_policy_spec.rb +12 -12
- data/spec/cert/extensions/key_usage_spec.rb +44 -39
- data/spec/cert/extensions/name_constraints_spec.rb +83 -83
- data/spec/cert/extensions/ocsp_no_check_spec.rb +10 -10
- data/spec/cert/extensions/policy_constraints_spec.rb +19 -19
- data/spec/cert/extensions/subject_alternative_name_spec.rb +46 -47
- data/spec/cert/extensions/subject_key_identifier_spec.rb +10 -10
- data/spec/cert_spec.rb +105 -101
- data/spec/certificate_authority/options_builder_spec.rb +90 -90
- data/spec/certificate_authority/signer_spec.rb +41 -41
- data/spec/config/ca_config_spec.rb +169 -119
- data/spec/config/cert_profile_spec.rb +33 -33
- data/spec/config/subject_item_policy_spec.rb +22 -22
- data/spec/crl/administrator_spec.rb +65 -65
- data/spec/crl/reader_writer_spec.rb +20 -19
- data/spec/crl/signed_list_spec.rb +26 -26
- data/spec/crl/sqlite_reader_writer_spec.rb +42 -0
- data/spec/csr_spec.rb +149 -145
- data/spec/engine_spec.rb +14 -14
- data/spec/fixtures.rb +56 -39
- data/spec/fixtures/crl_list.sql +13 -0
- data/spec/fixtures/csr1.der +0 -0
- data/spec/fixtures/csr1.pem +6 -6
- data/spec/message_digest_spec.rb +43 -43
- data/spec/ocsp_spec.rb +25 -25
- data/spec/oid_mapper_spec.rb +18 -19
- data/spec/private_key_spec.rb +79 -81
- data/spec/r509_spec.rb +16 -16
- data/spec/spec_helper.rb +3 -3
- data/spec/spki_spec.rb +94 -94
- data/spec/subject_spec.rb +107 -107
- data/spec/validity_spec.rb +25 -25
- metadata +113 -111
- metadata.gz.sig +0 -0
@@ -14,8 +14,8 @@ module R509
|
|
14
14
|
# cRLDistributionPoints extension.) This extension may be included in
|
15
15
|
# end entity or CA certificates. Conforming CAs MUST mark this
|
16
16
|
# extension as non-critical.
|
17
|
-
# You can use this extension to parse an existing extension for easy
|
18
|
-
# to the contents or create a new one.
|
17
|
+
# You can use this extension to parse an existing extension for easy
|
18
|
+
# access to the contents or create a new one.
|
19
19
|
class AuthorityInfoAccess < OpenSSL::X509::Extension
|
20
20
|
include R509::Cert::Extensions::ValidationMixin
|
21
21
|
|
@@ -23,32 +23,46 @@ module R509
|
|
23
23
|
OID = "authorityInfoAccess"
|
24
24
|
Extensions.register_class(self)
|
25
25
|
|
26
|
-
# An R509::ASN1::GeneralNames object of OCSP endpoints (or nil if not
|
26
|
+
# An R509::ASN1::GeneralNames object of OCSP endpoints (or nil if not
|
27
|
+
# present)
|
27
28
|
# @return [R509::ASN1::GeneralNames,nil]
|
28
29
|
attr_reader :ocsp
|
29
|
-
# An R509::ASN1::GeneralNames object of CA Issuers (or nil if not
|
30
|
+
# An R509::ASN1::GeneralNames object of CA Issuers (or nil if not
|
31
|
+
# present)
|
30
32
|
# @return [R509::ASN1::GeneralNames,nil]
|
31
33
|
attr_reader :ca_issuers
|
32
34
|
|
33
|
-
# This method takes a hash or an existing Extension object to parse. If
|
34
|
-
# a hash you must supply :ocsp_location and/or
|
35
|
-
# must be in the form seen in the
|
35
|
+
# This method takes a hash or an existing Extension object to parse. If
|
36
|
+
# passing a hash you must supply :ocsp_location and/or
|
37
|
+
# :ca_issuers_location. These values must be in the form seen in the
|
38
|
+
# examples below.
|
36
39
|
#
|
37
|
-
# @option arg :ocsp_location [Array,R509::ASN1::GeneralNames] Array of
|
38
|
-
#
|
40
|
+
# @option arg :ocsp_location [Array,R509::ASN1::GeneralNames] Array of
|
41
|
+
# hashes (see examples) or GeneralNames object
|
42
|
+
# @option arg :ca_issuers_location [Array] Array of hashes (see
|
43
|
+
# examples) or GeneralNames object
|
39
44
|
# @option arg :critical [Boolean] (false)
|
40
45
|
# @example
|
41
46
|
# R509::Cert::Extensions::AuthorityInfoAccess.new(
|
42
|
-
# :ocsp_location => [
|
43
|
-
#
|
47
|
+
# :ocsp_location => [
|
48
|
+
# { :type => "URI", :value => "http://ocsp.domain.com" }
|
49
|
+
# ],
|
50
|
+
# :ca_issuers_location => [
|
51
|
+
# {
|
52
|
+
# :type => "dirName",
|
53
|
+
# :value => { :CN => 'myCN', :O => 'some Org' }
|
54
|
+
# }
|
55
|
+
# ]
|
44
56
|
# )
|
45
57
|
# @example
|
46
|
-
# name = R509::ASN1::GeneralName.new(
|
58
|
+
# name = R509::ASN1::GeneralName.new(
|
59
|
+
# :type => "IP", :value => "127.0.0.1"
|
60
|
+
# )
|
47
61
|
# R509::Cert::Extensions::AuthorityInfoAccess.new(
|
48
62
|
# :ca_issuers_location => [name]
|
49
63
|
# )
|
50
64
|
def initialize(arg)
|
51
|
-
|
65
|
+
unless R509::Cert::Extensions.is_extension?(arg)
|
52
66
|
arg = build_extension(arg)
|
53
67
|
end
|
54
68
|
|
@@ -59,8 +73,16 @@ module R509
|
|
59
73
|
# @return [Hash]
|
60
74
|
def to_h
|
61
75
|
hash = { :critical => self.critical? }
|
62
|
-
|
63
|
-
|
76
|
+
unless @ocsp.names.empty?
|
77
|
+
hash[:ocsp_location] = R509::Cert::Extensions.names_to_h(
|
78
|
+
@ocsp.names
|
79
|
+
)
|
80
|
+
end
|
81
|
+
unless @ca_issuers.names.empty?
|
82
|
+
hash[:ca_issuers_location] = R509::Cert::Extensions.names_to_h(
|
83
|
+
@ca_issuers.names
|
84
|
+
)
|
85
|
+
end
|
64
86
|
hash
|
65
87
|
end
|
66
88
|
|
@@ -73,8 +95,8 @@ module R509
|
|
73
95
|
|
74
96
|
def parse_extension
|
75
97
|
data = R509::ASN1.get_extension_payload(self)
|
76
|
-
@ocsp= R509::ASN1::GeneralNames.new
|
77
|
-
@ca_issuers= R509::ASN1::GeneralNames.new
|
98
|
+
@ocsp = R509::ASN1::GeneralNames.new
|
99
|
+
@ca_issuers = R509::ASN1::GeneralNames.new
|
78
100
|
data.entries.each do |access_description|
|
79
101
|
# AccessDescription ::= SEQUENCE {
|
80
102
|
# accessMethod OBJECT IDENTIFIER,
|
@@ -99,9 +121,9 @@ module R509
|
|
99
121
|
]
|
100
122
|
|
101
123
|
locations.each do |pair|
|
102
|
-
validate_location(pair[:key].to_s,arg[pair[:key]])
|
124
|
+
validate_location(pair[:key].to_s, arg[pair[:key]])
|
103
125
|
data = arg[pair[:key]]
|
104
|
-
|
126
|
+
unless data.nil?
|
105
127
|
elements = R509::ASN1::GeneralNames.new(data)
|
106
128
|
elements.names.each do |name|
|
107
129
|
serialize = name.serialize_name
|
@@ -113,13 +135,17 @@ module R509
|
|
113
135
|
|
114
136
|
ef = OpenSSL::X509::ExtensionFactory.new
|
115
137
|
ef.config = OpenSSL::Config.parse(aia_conf.join("\n"))
|
116
|
-
critical = R509::Cert::Extensions.calculate_critical(
|
117
|
-
|
138
|
+
critical = R509::Cert::Extensions.calculate_critical(
|
139
|
+
arg[:critical], false
|
140
|
+
)
|
141
|
+
ef.create_extension("authorityInfoAccess", aia.join(","), critical)
|
118
142
|
end
|
119
143
|
|
120
144
|
def validate_authority_info_access(aia)
|
121
|
-
if
|
122
|
-
|
145
|
+
if !aia.is_a?(Hash) ||
|
146
|
+
(aia[:ocsp_location].nil? && aia[:ca_issuers_location].nil?)
|
147
|
+
raise ArgumentError, "You must pass a hash with at least one of "\
|
148
|
+
"the following two keys (:ocsp_location, :ca_issuers_location)"
|
123
149
|
end
|
124
150
|
end
|
125
151
|
end
|
@@ -16,7 +16,6 @@ module R509
|
|
16
16
|
# You can use this extension to parse an existing extension for easy access
|
17
17
|
# to the contents or create a new one.
|
18
18
|
class AuthorityKeyIdentifier < OpenSSL::X509::Extension
|
19
|
-
|
20
19
|
# friendly name for Authority Key Identifier OID
|
21
20
|
OID = "authorityKeyIdentifier"
|
22
21
|
# default extension behavior when generating
|
@@ -33,13 +32,13 @@ module R509
|
|
33
32
|
# @return [String,nil]
|
34
33
|
attr_reader :authority_cert_serial_number
|
35
34
|
|
36
|
-
|
37
35
|
# @option arg :public_key [OpenSSL::PKey] Required if embedding keyid
|
38
|
-
# @option arg :issuer_subject [R509::Subject] Required if embedding issuer
|
39
|
-
# @option arg :
|
36
|
+
# @option arg :issuer_subject [R509::Subject] Required if embedding issuer. This should be the issuing certificate's issuer subject name.
|
37
|
+
# @option arg :issuer_serial [Integer] Required if embedding issuer. This should be the issuing certificate's issuer serial number.
|
38
|
+
# @option arg :value [String] (keyid) For the rules of :value see: http://www.openssl.org/docs/apps/x509v3_config.html#Authority_Key_Identifier_. If you want to embed issuer you MUST supply :issuer_subject and :issuer_serial and not :public_key
|
40
39
|
# @option arg :critical [Boolean] (false)
|
41
40
|
def initialize(arg)
|
42
|
-
|
41
|
+
unless R509::Cert::Extensions.is_extension?(arg)
|
43
42
|
arg = build_extension(arg)
|
44
43
|
end
|
45
44
|
|
@@ -74,23 +73,29 @@ module R509
|
|
74
73
|
end
|
75
74
|
|
76
75
|
def build_extension(arg)
|
77
|
-
arg[:value] = AKI_EXTENSION_DEFAULT
|
76
|
+
arg[:value] = AKI_EXTENSION_DEFAULT if arg[:value].nil?
|
78
77
|
validate_authority_key_identifier(arg)
|
79
78
|
ef = OpenSSL::X509::ExtensionFactory.new
|
80
79
|
fake_cert = OpenSSL::X509::Certificate.new
|
81
80
|
fake_cert.extensions = [R509::Cert::Extensions::SubjectKeyIdentifier.new(:public_key => arg[:public_key])] unless arg[:public_key].nil?
|
82
|
-
fake_cert.
|
81
|
+
fake_cert.issuer = arg[:issuer_subject].name unless arg[:issuer_subject].nil?
|
82
|
+
fake_cert.serial = arg[:issuer_serial] unless arg[:issuer_serial].nil?
|
83
83
|
ef.issuer_certificate = fake_cert
|
84
84
|
critical = R509::Cert::Extensions.calculate_critical(arg[:critical], false)
|
85
|
-
|
85
|
+
ef.create_extension("authorityKeyIdentifier", arg[:value], critical) # this could also be keyid:always,issuer:always
|
86
86
|
end
|
87
87
|
|
88
88
|
def validate_authority_key_identifier(aki)
|
89
|
-
if aki[:value].downcase.include?("keyid")
|
89
|
+
if aki[:value].downcase.include?("keyid") && aki[:public_key].nil?
|
90
90
|
raise ArgumentError, "You must supply an OpenSSL::PKey object to :public_key if aki value contains keyid (present by default)"
|
91
91
|
end
|
92
|
-
if aki[:value].downcase.include?("issuer")
|
93
|
-
|
92
|
+
if aki[:value].downcase.include?("issuer")
|
93
|
+
unless aki[:issuer_subject].is_a?(R509::Subject)
|
94
|
+
raise ArgumentError, "You must supply an R509::Subject object to :issuer_subject if aki value contains issuer"
|
95
|
+
end
|
96
|
+
unless aki[:issuer_serial].is_a?(Integer)
|
97
|
+
raise ArgumentError, "You must supply an integer to :issuer_serial if aki value contains issuer"
|
98
|
+
end
|
94
99
|
end
|
95
100
|
aki
|
96
101
|
end
|
@@ -14,32 +14,32 @@ module R509
|
|
14
14
|
# R509::Cert::Extensions object, and returns them in a hash. The hash is
|
15
15
|
# keyed with the R509 extension class. Extensions without an R509
|
16
16
|
# implementation are ignored (see #get_unknown_extensions).
|
17
|
-
def self.wrap_openssl_extensions(
|
17
|
+
def self.wrap_openssl_extensions(extensions)
|
18
18
|
r509_extensions = {}
|
19
19
|
extensions.each do |openssl_extension|
|
20
20
|
R509_EXTENSION_CLASSES.each do |r509_class|
|
21
|
-
if
|
22
|
-
if r509_extensions.
|
23
|
-
raise ArgumentError
|
21
|
+
if r509_class::OID.downcase == openssl_extension.oid.downcase
|
22
|
+
if r509_extensions.key?(r509_class)
|
23
|
+
raise ArgumentError, "Only one extension object allowed per OID"
|
24
24
|
end
|
25
25
|
|
26
|
-
r509_extensions[r509_class] = r509_class.new(
|
26
|
+
r509_extensions[r509_class] = r509_class.new(openssl_extension)
|
27
27
|
break
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
r509_extensions
|
33
33
|
end
|
34
34
|
|
35
35
|
# Given a list of OpenSSL::X509::Extension objects, returns those without
|
36
36
|
# an R509 implementation.
|
37
|
-
def self.get_unknown_extensions(
|
37
|
+
def self.get_unknown_extensions(extensions)
|
38
38
|
unknown_extensions = []
|
39
39
|
extensions.each do |openssl_extension|
|
40
40
|
match_found = false
|
41
41
|
R509_EXTENSION_CLASSES.each do |r509_class|
|
42
|
-
if
|
42
|
+
if r509_class::OID.downcase == openssl_extension.oid.downcase
|
43
43
|
match_found = true
|
44
44
|
break
|
45
45
|
end
|
@@ -48,21 +48,20 @@ module R509
|
|
48
48
|
unknown_extensions << openssl_extension unless match_found
|
49
49
|
end
|
50
50
|
|
51
|
-
|
51
|
+
unknown_extensions
|
52
52
|
end
|
53
53
|
|
54
|
-
|
55
54
|
# Takes an array of R509::ASN1::GeneralName objects and returns a hash that can be
|
56
55
|
# encoded to YAML (used by #to_yaml methods)
|
57
56
|
def self.names_to_h(array)
|
58
57
|
data = []
|
59
58
|
array.each do |name|
|
60
|
-
value = (name.value.
|
59
|
+
value = (name.value.is_a?(R509::Subject)) ? name.value.to_h : name.value
|
61
60
|
data.push(
|
62
|
-
|
61
|
+
|
63
62
|
:type => name.short_type,
|
64
63
|
:value => value
|
65
|
-
|
64
|
+
|
66
65
|
)
|
67
66
|
end
|
68
67
|
data
|
@@ -80,13 +79,13 @@ module R509
|
|
80
79
|
def ip_addresses
|
81
80
|
@general_names.ip_addresses
|
82
81
|
end
|
83
|
-
|
82
|
+
alias_method :ips, :ip_addresses
|
84
83
|
|
85
84
|
# @return [Array<String>] email addresses
|
86
85
|
def rfc_822_names
|
87
86
|
@general_names.rfc_822_names
|
88
87
|
end
|
89
|
-
|
88
|
+
alias_method :email_names, :rfc_822_names
|
90
89
|
|
91
90
|
# @return [Array<String>] URIs (not typically found in SAN extensions)
|
92
91
|
def uris
|
@@ -97,7 +96,7 @@ module R509
|
|
97
96
|
def directory_names
|
98
97
|
@general_names.directory_names
|
99
98
|
end
|
100
|
-
|
99
|
+
alias_method :dir_names, :directory_names
|
101
100
|
|
102
101
|
# @return [Array] array of GeneralName objects preserving order found in the extension
|
103
102
|
def names
|
@@ -106,18 +105,19 @@ module R509
|
|
106
105
|
end
|
107
106
|
|
108
107
|
private
|
108
|
+
|
109
109
|
R509_EXTENSION_CLASSES = Set.new
|
110
110
|
|
111
111
|
# Registers a class as being an R509 certificate extension class. Registered
|
112
112
|
# classes are used by #wrap_openssl_extensions to wrap OpenSSL extensions
|
113
113
|
# in R509 extensions, based on the OID.
|
114
|
-
def self.register_class(
|
115
|
-
raise
|
114
|
+
def self.register_class(r509_ext_class)
|
115
|
+
raise(ArgumentError, "R509 certificate extensions must have an OID") if r509_ext_class::OID.nil?
|
116
116
|
R509_EXTENSION_CLASSES << r509_ext_class
|
117
117
|
end
|
118
118
|
|
119
|
-
def self.calculate_critical(critical,default)
|
120
|
-
if critical.
|
119
|
+
def self.calculate_critical(critical, default)
|
120
|
+
if critical.is_a?(TrueClass) || critical.is_a?(FalseClass)
|
121
121
|
critical
|
122
122
|
else
|
123
123
|
default
|
@@ -127,8 +127,8 @@ module R509
|
|
127
127
|
# Method attempts to determine if data being passed to an extension is already
|
128
128
|
# an extension/asn.1 data or not.
|
129
129
|
def self.is_extension?(data)
|
130
|
-
return true if data.
|
131
|
-
return false
|
130
|
+
return true if data.is_a?(OpenSSL::X509::Extension)
|
131
|
+
return false unless data.is_a?(String)
|
132
132
|
begin
|
133
133
|
OpenSSL::X509::Extension.new(data)
|
134
134
|
return true
|
@@ -136,7 +136,6 @@ module R509
|
|
136
136
|
return false
|
137
137
|
end
|
138
138
|
end
|
139
|
-
|
140
139
|
end
|
141
140
|
end
|
142
141
|
end
|
@@ -12,7 +12,6 @@ module R509
|
|
12
12
|
# You can use this extension to parse an existing extension for easy access
|
13
13
|
# to the contents or create a new one.
|
14
14
|
class BasicConstraints < OpenSSL::X509::Extension
|
15
|
-
|
16
15
|
# friendly name for BasicConstraints OID
|
17
16
|
OID = "basicConstraints"
|
18
17
|
Extensions.register_class(self)
|
@@ -26,7 +25,7 @@ module R509
|
|
26
25
|
# @option arg :path_length optional [Integer] This option is only allowed if ca is set to TRUE. path_length allows you to define the maximum number of non-self-issued intermediate certificates that may follow this certificate in a valid certification path. For example, if you set this value to 0 then the certificate issued can only issue end entity certificates, not additional subroots. This must be a non-negative integer (>=0).
|
27
26
|
# @option arg :critical [Boolean] (true)
|
28
27
|
def initialize(arg)
|
29
|
-
|
28
|
+
unless R509::Cert::Extensions.is_extension?(arg)
|
30
29
|
arg = build_extension(arg)
|
31
30
|
end
|
32
31
|
|
@@ -37,7 +36,7 @@ module R509
|
|
37
36
|
# Check whether the extension value would make the parent certificate a CA
|
38
37
|
# @return [Boolean]
|
39
38
|
def is_ca?
|
40
|
-
|
39
|
+
@is_ca == true
|
41
40
|
end
|
42
41
|
|
43
42
|
# Returns true if the path length allows this certificate to be used to
|
@@ -47,13 +46,13 @@ module R509
|
|
47
46
|
def allows_sub_ca?
|
48
47
|
return false unless is_ca?
|
49
48
|
return true if @path_length.nil?
|
50
|
-
|
49
|
+
@path_length > 0
|
51
50
|
end
|
52
51
|
|
53
52
|
# @return [Hash]
|
54
53
|
def to_h
|
55
54
|
hash = { :ca => @is_ca, :critical => self.critical? }
|
56
|
-
hash[:path_length] = @path_length unless @path_length.nil?
|
55
|
+
hash[:path_length] = @path_length unless @path_length.nil? || !is_ca?
|
57
56
|
hash
|
58
57
|
end
|
59
58
|
|
@@ -71,7 +70,7 @@ module R509
|
|
71
70
|
# cA BOOLEAN DEFAULT FALSE,
|
72
71
|
# pathLenConstraint INTEGER (0..MAX) OPTIONAL }
|
73
72
|
data.entries.each do |entry|
|
74
|
-
if entry.
|
73
|
+
if entry.is_a?(OpenSSL::ASN1::Boolean)
|
75
74
|
@is_ca = entry.value
|
76
75
|
else
|
77
76
|
# There are only two kinds of entries permitted so anything
|
@@ -87,28 +86,28 @@ module R509
|
|
87
86
|
ef = OpenSSL::X509::ExtensionFactory.new
|
88
87
|
if arg[:ca] == true
|
89
88
|
bc_value = "CA:TRUE"
|
90
|
-
|
89
|
+
unless arg[:path_length].nil?
|
91
90
|
bc_value += ",pathlen:#{arg[:path_length]}"
|
92
91
|
end
|
93
92
|
else
|
94
93
|
bc_value = "CA:FALSE"
|
95
94
|
end
|
96
95
|
critical = R509::Cert::Extensions.calculate_critical(arg[:critical], true)
|
97
|
-
|
96
|
+
ef.create_extension("basicConstraints", bc_value, critical)
|
98
97
|
end
|
99
98
|
|
100
99
|
# validates the structure of the certificate policies array
|
101
100
|
def validate_basic_constraints(constraints)
|
102
|
-
if constraints.nil?
|
101
|
+
if constraints.nil? || !constraints.respond_to?(:has_key?) || !constraints.key?(:ca)
|
103
102
|
raise ArgumentError, "You must supply a hash with a key named :ca with a boolean value"
|
104
103
|
end
|
105
|
-
if constraints[:ca].nil?
|
104
|
+
if constraints[:ca].nil? || (!constraints[:ca].is_a?(TrueClass) && !constraints[:ca].is_a?(FalseClass))
|
106
105
|
raise ArgumentError, "You must supply true/false for the :ca key when specifying basic constraints"
|
107
106
|
end
|
108
|
-
if constraints[:ca] == false
|
107
|
+
if constraints[:ca] == false && constraints[:path_length]
|
109
108
|
raise ArgumentError, ":path_length is not allowed when :ca is false"
|
110
109
|
end
|
111
|
-
if constraints[:ca] == true
|
110
|
+
if constraints[:ca] == true && constraints[:path_length] && (constraints[:path_length] < 0 || !constraints[:path_length].is_a?(Integer))
|
112
111
|
raise ArgumentError, "Path length must be a positive integer (>= 0)"
|
113
112
|
end
|
114
113
|
constraints
|
@@ -15,7 +15,6 @@ module R509
|
|
15
15
|
# You can use this extension to parse an existing extension for easy access
|
16
16
|
# to the contents or create a new one.
|
17
17
|
class CertificatePolicies < OpenSSL::X509::Extension
|
18
|
-
|
19
18
|
# friendly name for CP OID
|
20
19
|
OID = "certificatePolicies"
|
21
20
|
Extensions.register_class(self)
|
@@ -35,7 +34,7 @@ module R509
|
|
35
34
|
# }
|
36
35
|
# ])
|
37
36
|
def initialize(arg)
|
38
|
-
|
37
|
+
unless R509::Cert::Extensions.is_extension?(arg)
|
39
38
|
arg = build_extension(arg)
|
40
39
|
end
|
41
40
|
|
@@ -57,6 +56,7 @@ module R509
|
|
57
56
|
end
|
58
57
|
|
59
58
|
private
|
59
|
+
|
60
60
|
def parse_extension
|
61
61
|
@policies = []
|
62
62
|
data = R509::ASN1.get_extension_payload(self)
|
@@ -72,32 +72,32 @@ module R509
|
|
72
72
|
validate_certificate_policies(arg[:value])
|
73
73
|
conf = []
|
74
74
|
policy_names = ["ia5org"]
|
75
|
-
arg[:value].each_with_index do |policy,i|
|
76
|
-
conf << build_conf("certPolicies#{i}",policy,i)
|
75
|
+
arg[:value].each_with_index do |policy, i|
|
76
|
+
conf << build_conf("certPolicies#{i}", policy, i)
|
77
77
|
policy_names << "@certPolicies#{i}"
|
78
78
|
end
|
79
79
|
ef = OpenSSL::X509::ExtensionFactory.new
|
80
80
|
ef.config = OpenSSL::Config.parse(conf.join("\n"))
|
81
81
|
critical = R509::Cert::Extensions.calculate_critical(arg[:critical], false)
|
82
|
-
|
82
|
+
ef.create_extension("certificatePolicies", policy_names.join(","), critical)
|
83
83
|
end
|
84
84
|
|
85
|
-
def build_conf(section,hash,index)
|
85
|
+
def build_conf(section, hash, index)
|
86
86
|
conf = ["[#{section}]"]
|
87
87
|
conf.push "policyIdentifier=#{hash[:policy_identifier]}" unless hash[:policy_identifier].nil?
|
88
|
-
hash[:cps_uris].each_with_index do |cps,idx|
|
89
|
-
conf.push "CPS.#{idx+1}=\"#{cps}\""
|
88
|
+
hash[:cps_uris].each_with_index do |cps, idx|
|
89
|
+
conf.push "CPS.#{idx + 1}=\"#{cps}\""
|
90
90
|
end if hash[:cps_uris].respond_to?(:each_with_index)
|
91
91
|
|
92
92
|
user_notice_confs = []
|
93
|
-
hash[:user_notices].each_with_index do |un,k|
|
94
|
-
conf.push "userNotice.#{k+1}=@user_notice#{k+1}#{index}"
|
95
|
-
user_notice_confs.push "[user_notice#{k+1}#{index}]"
|
93
|
+
hash[:user_notices].each_with_index do |un, k|
|
94
|
+
conf.push "userNotice.#{k + 1}=@user_notice#{k + 1}#{index}"
|
95
|
+
user_notice_confs.push "[user_notice#{k + 1}#{index}]"
|
96
96
|
user_notice_confs.push "explicitText=\"#{un[:explicit_text]}\"" unless un[:explicit_text].nil?
|
97
97
|
# if org is supplied notice numbers is also required (and vice versa). enforced in CAProfile
|
98
98
|
user_notice_confs.push "organization=\"#{un[:organization]}\"" unless un[:organization].nil?
|
99
99
|
user_notice_confs.push "noticeNumbers=\"#{un[:notice_numbers].join(",")}\"" unless un[:notice_numbers].nil?
|
100
|
-
end
|
100
|
+
end if hash[:user_notices].is_a?(Array)
|
101
101
|
|
102
102
|
conf.concat(user_notice_confs)
|
103
103
|
conf.join "\n"
|
@@ -105,16 +105,16 @@ module R509
|
|
105
105
|
|
106
106
|
# validates the structure of the certificate policies array
|
107
107
|
def validate_certificate_policies(policies)
|
108
|
-
raise ArgumentError, "Not a valid certificate policy structure. Must be an array of hashes" unless policies.
|
108
|
+
raise ArgumentError, "Not a valid certificate policy structure. Must be an array of hashes" unless policies.is_a?(Array)
|
109
109
|
|
110
110
|
policies.each do |policy|
|
111
111
|
raise ArgumentError, "Each policy requires a policy identifier" if policy[:policy_identifier].nil?
|
112
|
-
raise ArgumentError, "CPS URIs must be an array of strings" if
|
113
|
-
|
114
|
-
raise ArgumentError, "User notices must be an array of hashes"
|
112
|
+
raise ArgumentError, "CPS URIs must be an array of strings" if policy[:cps_uris] && !policy[:cps_uris].respond_to?(:each)
|
113
|
+
unless policy[:user_notices].nil?
|
114
|
+
raise ArgumentError, "User notices must be an array of hashes" unless policy[:user_notices].respond_to?(:each)
|
115
115
|
policy[:user_notices].each do |un|
|
116
|
-
raise ArgumentError, "If you provide an organization you must provide notice numbers" if
|
117
|
-
raise ArgumentError, "If you provide notice numbers you must provide an organization" if
|
116
|
+
raise ArgumentError, "If you provide an organization you must provide notice numbers" if un[:organization] && un[:notice_numbers].nil?
|
117
|
+
raise ArgumentError, "If you provide notice numbers you must provide an organization" if un[:notice_numbers] && un[:organization].nil?
|
118
118
|
end
|
119
119
|
end
|
120
120
|
end
|
@@ -131,12 +131,12 @@ module R509
|
|
131
131
|
def initialize(data)
|
132
132
|
# store the policy identifier OID
|
133
133
|
@policy_identifier = data.entries[0].value
|
134
|
+
|
134
135
|
# iterate the policy qualifiers if any exist
|
135
|
-
if
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
end
|
136
|
+
return if data.entries[1].nil?
|
137
|
+
@policy_qualifiers = PolicyQualifiers.new
|
138
|
+
data.entries[1].each do |pq|
|
139
|
+
@policy_qualifiers.parse(pq)
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
@@ -199,8 +199,8 @@ module R509
|
|
199
199
|
attr_reader :notice_reference, :explicit_text
|
200
200
|
def initialize(data)
|
201
201
|
data.each do |qualifier|
|
202
|
-
#if we find another sequence, that's a noticeReference, otherwise it's explicitText
|
203
|
-
if qualifier.
|
202
|
+
# if we find another sequence, that's a noticeReference, otherwise it's explicitText
|
203
|
+
if qualifier.is_a?(OpenSSL::ASN1::Sequence)
|
204
204
|
@notice_reference = NoticeReference.new(qualifier)
|
205
205
|
else
|
206
206
|
@explicit_text = qualifier.value
|
@@ -233,7 +233,7 @@ module R509
|
|
233
233
|
data.each do |notice_reference|
|
234
234
|
# if it's displaytext then it's the organization
|
235
235
|
# if it's YET ANOTHER ASN1::Sequence, then it's noticeNumbers
|
236
|
-
if notice_reference.
|
236
|
+
if notice_reference.is_a?(OpenSSL::ASN1::Sequence)
|
237
237
|
@notice_numbers = []
|
238
238
|
notice_reference.each do |ints|
|
239
239
|
@notice_numbers << ints.value.to_i
|