r509 0.8.1 → 0.9
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.
- data/README.md +343 -151
- data/Rakefile +26 -23
- data/bin/r509 +126 -112
- data/bin/r509-parse +24 -24
- data/doc/R509.html +169 -7
- data/doc/R509/ASN1.html +370 -0
- data/doc/R509/ASN1/GeneralName.html +1121 -0
- data/doc/R509/ASN1/GeneralNames.html +843 -0
- data/doc/R509/ASN1/NoticeReference.html +392 -0
- data/doc/R509/ASN1/PolicyInformation.html +387 -0
- data/doc/R509/ASN1/PolicyQualifiers.html +455 -0
- data/doc/R509/ASN1/UserNotice.html +386 -0
- data/doc/R509/{Crl.html → CRL.html} +7 -7
- data/doc/R509/CRL/Administrator.html +1559 -0
- data/doc/R509/{Crl/Parser.html → CRL/SignedList.html} +501 -210
- data/doc/R509/{Csr.html → CSR.html} +444 -314
- data/doc/R509/Cert.html +866 -617
- data/doc/R509/Cert/Extensions.html +52 -41
- data/doc/R509/Cert/Extensions/AuthorityInfoAccess.html +70 -35
- data/doc/R509/Cert/Extensions/AuthorityKeyIdentifier.html +387 -4
- data/doc/R509/Cert/Extensions/BasicConstraints.html +61 -25
- data/doc/R509/Cert/Extensions/CRLDistributionPoints.html +354 -0
- data/doc/R509/Cert/Extensions/CertificatePolicies.html +340 -0
- data/doc/R509/Cert/Extensions/ExtendedKeyUsage.html +440 -49
- data/doc/R509/Cert/Extensions/{CrlDistributionPoints.html → InhibitAnyPolicy.html} +52 -35
- data/doc/R509/Cert/Extensions/KeyUsage.html +247 -121
- data/doc/R509/Cert/Extensions/NameConstraints.html +445 -0
- data/doc/R509/Cert/Extensions/OCSPNoCheck.html +239 -0
- data/doc/R509/Cert/Extensions/PolicyConstraints.html +424 -0
- data/doc/R509/Cert/Extensions/SubjectAlternativeName.html +437 -62
- data/doc/R509/Cert/Extensions/SubjectKeyIdentifier.html +52 -10
- data/doc/R509/CertificateAuthority.html +4 -4
- data/doc/R509/CertificateAuthority/Signer.html +154 -187
- data/doc/R509/Config.html +6 -6
- data/doc/R509/Config/{CaConfig.html → CAConfig.html} +451 -348
- data/doc/R509/Config/{CaConfigPool.html → CAConfigPool.html} +47 -47
- data/doc/R509/Config/CAProfile.html +1015 -0
- data/doc/R509/Config/SubjectItemPolicy.html +86 -86
- data/doc/R509/IOHelpers.html +22 -22
- data/doc/R509/MessageDigest.html +14 -14
- data/doc/R509/NameSanitizer.html +53 -53
- data/doc/R509/{Ocsp.html → OCSP.html} +9 -9
- data/doc/R509/{Ocsp → OCSP}/Request.html +7 -7
- data/doc/R509/{Ocsp → OCSP}/Request/Nonce.html +56 -11
- data/doc/R509/{Ocsp → OCSP}/Response.html +44 -44
- data/doc/R509/{OidMapper.html → OIDMapper.html} +23 -39
- data/doc/R509/PrivateKey.html +415 -168
- data/doc/R509/R509Error.html +3 -3
- data/doc/R509/{Spki.html → SPKI.html} +354 -192
- data/doc/R509/Subject.html +224 -113
- data/doc/R509/Validity.html +27 -5
- data/doc/R509/Validity/Checker.html +13 -13
- data/doc/R509/Validity/DefaultChecker.html +13 -13
- data/doc/R509/Validity/DefaultWriter.html +14 -14
- data/doc/R509/Validity/Status.html +39 -39
- data/doc/R509/Validity/Writer.html +18 -18
- data/doc/_index.html +138 -35
- data/doc/class_list.html +1 -1
- data/doc/css/style.css +10 -0
- data/doc/file.README.html +368 -171
- data/doc/file.r509.html +92 -69
- data/doc/frames.html +1 -1
- data/doc/index.html +368 -171
- data/doc/method_list.html +910 -390
- data/doc/top-level-namespace.html +3 -3
- data/lib/r509.rb +32 -16
- data/lib/r509/asn1.rb +375 -0
- data/lib/r509/cert.rb +381 -364
- data/lib/r509/cert/extensions.rb +443 -76
- data/lib/r509/certificate_authority.rb +407 -0
- data/lib/r509/config.rb +547 -351
- data/lib/r509/crl.rb +336 -366
- data/lib/r509/csr.rb +278 -289
- data/lib/r509/ec-hack.rb +37 -0
- data/lib/r509/exceptions.rb +3 -3
- data/lib/r509/io_helpers.rb +44 -44
- data/lib/r509/message_digest.rb +53 -0
- data/lib/r509/ocsp.rb +80 -70
- data/lib/r509/oid_mapper.rb +32 -0
- data/lib/r509/private_key.rb +228 -0
- data/lib/r509/spki.rb +145 -93
- data/lib/r509/subject.rb +203 -110
- data/lib/r509/validity.rb +70 -68
- data/lib/r509/version.rb +2 -2
- data/r509.yaml +92 -69
- data/spec/asn1_spec.rb +402 -0
- data/spec/cert/extensions_spec.rb +957 -494
- data/spec/cert_spec.rb +382 -307
- data/spec/certificate_authority_spec.rb +668 -250
- data/spec/config_spec.rb +515 -302
- data/spec/crl_spec.rb +197 -198
- data/spec/csr_spec.rb +334 -289
- data/spec/fixtures.rb +247 -171
- data/spec/fixtures/cert1.der +0 -0
- data/spec/fixtures/cert1.pem +0 -0
- data/spec/fixtures/cert1_public_key_modulus.txt +0 -0
- data/spec/fixtures/cert3.p12 +0 -0
- data/spec/fixtures/cert3.pem +0 -0
- data/spec/fixtures/cert3_key.pem +0 -0
- data/spec/fixtures/cert3_key_des3.pem +0 -0
- data/spec/fixtures/cert4.pem +0 -0
- data/spec/fixtures/cert5.pem +0 -0
- data/spec/fixtures/cert6.pem +0 -0
- data/spec/fixtures/cert_expired.pem +0 -0
- data/spec/fixtures/cert_inhibit.pem +24 -0
- data/spec/fixtures/cert_name_constraints.pem +29 -0
- data/spec/fixtures/cert_not_yet_valid.pem +0 -0
- data/spec/fixtures/cert_ocsp_no_check.pem +18 -0
- data/spec/fixtures/cert_policy_constraints.pem +31 -0
- data/spec/fixtures/cert_san.pem +0 -0
- data/spec/fixtures/cert_san2.pem +0 -0
- data/spec/fixtures/cert_unknown_extension.pem +28 -0
- data/spec/fixtures/config_pool_test_minimal.yaml +11 -11
- data/spec/fixtures/config_test.yaml +54 -36
- data/spec/fixtures/config_test_dsa.yaml +35 -0
- data/spec/fixtures/config_test_ec.yaml +35 -0
- data/spec/fixtures/config_test_engine_key.yaml +5 -5
- data/spec/fixtures/config_test_engine_no_key_name.yaml +4 -4
- data/spec/fixtures/config_test_minimal.yaml +4 -4
- data/spec/fixtures/config_test_password.yaml +5 -5
- data/spec/fixtures/config_test_various.yaml +111 -74
- data/spec/fixtures/crl_list_file.txt +0 -0
- data/spec/fixtures/crl_with_reason.pem +0 -0
- data/spec/fixtures/csr1.der +0 -0
- data/spec/fixtures/csr1.pem +0 -0
- data/spec/fixtures/csr1_key.der +0 -0
- data/spec/fixtures/csr1_key.pem +0 -0
- data/spec/fixtures/csr1_key_encrypted_des3.pem +0 -0
- data/spec/fixtures/csr1_newlines.pem +0 -0
- data/spec/fixtures/csr1_no_begin_end.pem +0 -0
- data/spec/fixtures/csr1_public_key_modulus.txt +0 -0
- data/spec/fixtures/csr2.pem +0 -0
- data/spec/fixtures/csr2_key.pem +0 -0
- data/spec/fixtures/csr3.pem +0 -0
- data/spec/fixtures/csr4.pem +0 -0
- data/spec/fixtures/csr_dsa.pem +0 -0
- data/spec/fixtures/csr_invalid_signature.pem +0 -0
- data/spec/fixtures/dsa_key.pem +0 -0
- data/spec/fixtures/dsa_root.cer +28 -0
- data/spec/fixtures/dsa_root.key +20 -0
- data/spec/fixtures/ec_csr2.der +0 -0
- data/spec/fixtures/ec_csr2.pem +8 -0
- data/spec/fixtures/ec_key1.der +0 -0
- data/spec/fixtures/ec_key1.pem +6 -0
- data/spec/fixtures/ec_key1_encrypted.pem +9 -0
- data/spec/fixtures/ec_key2.pem +6 -0
- data/spec/fixtures/hmacsha1.sig +1 -0
- data/spec/fixtures/hmacsha512.sig +1 -0
- data/spec/fixtures/key4.pem +0 -0
- data/spec/fixtures/key4_encrypted_des3.pem +0 -0
- data/spec/fixtures/missing_key_identifier_ca.cer +0 -0
- data/spec/fixtures/missing_key_identifier_ca.key +0 -0
- data/spec/fixtures/ocsptest.r509.local.pem +0 -0
- data/spec/fixtures/ocsptest.r509.local_ocsp_request.der +0 -0
- data/spec/fixtures/ocsptest2.r509.local.pem +0 -0
- data/spec/fixtures/second_ca.cer +0 -0
- data/spec/fixtures/second_ca.key +0 -0
- data/spec/fixtures/spkac.der +0 -0
- data/spec/fixtures/spkac.txt +0 -0
- data/spec/fixtures/spkac_dsa.txt +1 -1
- data/spec/fixtures/spkac_dsa_no_verify.txt +1 -0
- data/spec/fixtures/spkac_ec.txt +1 -0
- data/spec/fixtures/spkac_rsa_newlines.txt +13 -0
- data/spec/fixtures/stca.pem +0 -0
- data/spec/fixtures/stca_ocsp_request.der +0 -0
- data/spec/fixtures/stca_ocsp_response.der +0 -0
- data/spec/fixtures/test1.csr +0 -0
- data/spec/fixtures/test_ca.cer +0 -0
- data/spec/fixtures/test_ca.key +0 -0
- data/spec/fixtures/test_ca.p12 +0 -0
- data/spec/fixtures/test_ca_des3.key +0 -0
- data/spec/fixtures/test_ca_ec.cer +14 -0
- data/spec/fixtures/test_ca_ec.key +6 -0
- data/spec/fixtures/test_ca_ec_ee.cer +22 -0
- data/spec/fixtures/test_ca_ec_ee.key +6 -0
- data/spec/fixtures/test_ca_ocsp.cer +0 -0
- data/spec/fixtures/test_ca_ocsp.key +0 -0
- data/spec/fixtures/test_ca_ocsp.p12 +0 -0
- data/spec/fixtures/test_ca_ocsp_chain.txt +0 -0
- data/spec/fixtures/test_ca_ocsp_response.der +0 -0
- data/spec/fixtures/test_ca_subroot.cer +0 -0
- data/spec/fixtures/test_ca_subroot.key +0 -0
- data/spec/fixtures/test_ca_subroot_ocsp.cer +0 -0
- data/spec/fixtures/test_ca_subroot_ocsp.key +0 -0
- data/spec/fixtures/test_ca_subroot_ocsp_response.der +0 -0
- data/spec/fixtures/unknown_oid.csr +0 -0
- data/spec/message_digest_spec.rb +104 -84
- data/spec/ocsp_spec.rb +105 -105
- data/spec/oid_mapper_spec.rb +21 -21
- data/spec/private_key_spec.rb +275 -0
- data/spec/r509_spec.rb +35 -0
- data/spec/spec_helper.rb +15 -6
- data/spec/spki_spec.rb +221 -142
- data/spec/subject_spec.rb +232 -164
- data/spec/validity_spec.rb +91 -91
- metadata +79 -25
- data/doc/R509/Config/CaProfile.html +0 -651
- data/doc/R509/Crl/Administrator.html +0 -2073
- data/lib/r509/certificateauthority.rb +0 -290
- data/lib/r509/messagedigest.rb +0 -49
- data/lib/r509/oidmapper.rb +0 -32
- data/lib/r509/privatekey.rb +0 -185
- data/spec/privatekey_spec.rb +0 -198
data/lib/r509/cert.rb
CHANGED
@@ -4,411 +4,428 @@ require 'r509/io_helpers'
|
|
4
4
|
require 'r509/cert/extensions'
|
5
5
|
|
6
6
|
module R509
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
raise R509Error, 'Key does not match cert.'
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Helper method to quickly load a cert from the filesystem
|
49
|
-
#
|
50
|
-
# @param [String] filename Path to file you want to load
|
51
|
-
# @return [R509::Cert] cert object
|
52
|
-
def self.load_from_file( filename )
|
53
|
-
return R509::Cert.new(:cert => IOHelpers.read_data(filename) )
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
# Converts the Cert into the PEM format
|
59
|
-
#
|
60
|
-
# @return [String] the Cert converted into PEM format.
|
61
|
-
def to_pem
|
62
|
-
if @cert.kind_of?(OpenSSL::X509::Certificate)
|
63
|
-
return @cert.to_pem.chomp
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
alias :to_s :to_pem
|
68
|
-
|
69
|
-
# Converts the Cert into the DER format
|
70
|
-
#
|
71
|
-
# @return [String] the Cert converted into DER format.
|
72
|
-
def to_der
|
73
|
-
if @cert.kind_of?(OpenSSL::X509::Certificate)
|
74
|
-
return @cert.to_der
|
75
|
-
end
|
76
|
-
end
|
7
|
+
# The primary certificate object.
|
8
|
+
class Cert
|
9
|
+
include R509::IOHelpers
|
10
|
+
|
11
|
+
attr_reader :cert, :key, :subject, :issuer
|
12
|
+
|
13
|
+
# @option opts [String,OpenSSL::X509::Certificate] :cert a cert
|
14
|
+
# @option opts [R509::PrivateKey,String] :key optional private key to supply. either an unencrypted PEM/DER string or an R509::PrivateKey object (use the latter if you need password/hardware support)
|
15
|
+
# @option opts [String] :pkcs12 a PKCS12 object containing both key and cert
|
16
|
+
# @option opts [String] :password password for PKCS12 or private key (if supplied)
|
17
|
+
def initialize(opts={})
|
18
|
+
if not opts.kind_of?(Hash)
|
19
|
+
raise ArgumentError, 'Must provide a hash of options'
|
20
|
+
end
|
21
|
+
if opts.has_key?(:pkcs12) and ( opts.has_key?(:key) or opts.has_key?(:cert) )
|
22
|
+
raise ArgumentError, "When providing pkcs12, do not pass cert or key"
|
23
|
+
elsif opts.has_key?(:pkcs12)
|
24
|
+
pkcs12 = OpenSSL::PKCS12.new( opts[:pkcs12], opts[:password] )
|
25
|
+
parse_certificate(pkcs12.certificate)
|
26
|
+
key = R509::PrivateKey.new( :key => pkcs12.key )
|
27
|
+
elsif not opts.has_key?(:cert)
|
28
|
+
raise ArgumentError, 'Must provide :cert or :pkcs12'
|
29
|
+
else
|
30
|
+
csr_check(opts[:cert])
|
31
|
+
parse_certificate(opts[:cert])
|
32
|
+
end
|
33
|
+
|
34
|
+
if opts.has_key?(:key)
|
35
|
+
if opts[:key].kind_of?(R509::PrivateKey)
|
36
|
+
key = opts[:key]
|
37
|
+
else
|
38
|
+
key = R509::PrivateKey.new( :key => opts[:key], :password => opts[:password] )
|
39
|
+
end
|
40
|
+
end
|
41
|
+
associate_private_key(key)
|
42
|
+
end
|
77
43
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
44
|
+
# Helper method to quickly load a cert from the filesystem
|
45
|
+
#
|
46
|
+
# @param [String] filename Path to file you want to load
|
47
|
+
# @return [R509::Cert] cert object
|
48
|
+
def self.load_from_file( filename )
|
49
|
+
return R509::Cert.new(:cert => IOHelpers.read_data(filename) )
|
50
|
+
end
|
84
51
|
|
85
|
-
# Returns the serial number of the certificate in decimal form
|
86
|
-
#
|
87
|
-
# @return [Integer]
|
88
|
-
def serial
|
89
|
-
@cert.serial.to_i
|
90
|
-
end
|
91
52
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
53
|
+
# Converts the Cert into the PEM format
|
54
|
+
#
|
55
|
+
# @return [String] the Cert converted into PEM format.
|
56
|
+
def to_pem
|
57
|
+
if @cert.kind_of?(OpenSSL::X509::Certificate)
|
58
|
+
return @cert.to_pem.chomp
|
59
|
+
end
|
60
|
+
end
|
98
61
|
|
99
|
-
|
100
|
-
#
|
101
|
-
# @return [OpenSSL::PKey::RSA] public key object
|
102
|
-
def public_key
|
103
|
-
@cert.public_key
|
104
|
-
end
|
62
|
+
alias :to_s :to_pem
|
105
63
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
64
|
+
# Converts the Cert into the DER format
|
65
|
+
#
|
66
|
+
# @return [String] the Cert converted into DER format.
|
67
|
+
def to_der
|
68
|
+
if @cert.kind_of?(OpenSSL::X509::Certificate)
|
69
|
+
return @cert.to_der
|
70
|
+
end
|
71
|
+
end
|
112
72
|
|
113
|
-
|
114
|
-
|
115
|
-
|
73
|
+
# Returns beginning (notBefore) of certificate validity period
|
74
|
+
#
|
75
|
+
# @return [Time] time object
|
76
|
+
def not_before
|
77
|
+
@cert.not_before
|
78
|
+
end
|
116
79
|
|
117
|
-
|
118
|
-
|
119
|
-
|
80
|
+
# Returns the serial number of the certificate in decimal form
|
81
|
+
#
|
82
|
+
# @return [Integer]
|
83
|
+
def serial
|
84
|
+
@cert.serial.to_i
|
85
|
+
end
|
120
86
|
|
121
|
-
|
122
|
-
|
123
|
-
|
87
|
+
# Returns the serial number of the certificate in hexadecimal form
|
88
|
+
#
|
89
|
+
# @return [String]
|
90
|
+
def hexserial
|
91
|
+
@cert.serial.to_s(16)
|
92
|
+
end
|
124
93
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
md = message_digest.digest
|
132
|
-
md.update(@cert.to_der)
|
133
|
-
md.to_s
|
134
|
-
end
|
94
|
+
# Returns ending (notAfter) of certificate validity period
|
95
|
+
#
|
96
|
+
# @return [Time] time object
|
97
|
+
def not_after
|
98
|
+
@cert.not_after
|
99
|
+
end
|
135
100
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
end
|
101
|
+
# Returns the certificate public key
|
102
|
+
#
|
103
|
+
# @return [OpenSSL::PKey::RSA] public key object
|
104
|
+
def public_key
|
105
|
+
@cert.public_key
|
106
|
+
end
|
143
107
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
false
|
155
|
-
else
|
156
|
-
true
|
157
|
-
end
|
158
|
-
end
|
108
|
+
# Returns the certificate fingerprint with the specified algorithm (default sha1)
|
109
|
+
#
|
110
|
+
# @param [String] algorithm Which algorithm to use for the fingerprint. See R509::MessageDigest for supported algorithm names
|
111
|
+
# @return [String] hex digest of the certificate
|
112
|
+
def fingerprint(algorithm='sha1')
|
113
|
+
message_digest = R509::MessageDigest.new(algorithm)
|
114
|
+
md = message_digest.digest
|
115
|
+
md.update(@cert.to_der)
|
116
|
+
md.to_s
|
117
|
+
end
|
159
118
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
119
|
+
# Returns whether the current time is between the notBefore and notAfter times in
|
120
|
+
# the certificate.
|
121
|
+
#
|
122
|
+
# @return [Boolean]
|
123
|
+
def valid?
|
124
|
+
valid_at?(Time.now)
|
125
|
+
end
|
166
126
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
127
|
+
# Returns whether the certificate was between its notBefore and notAfter at the time provided
|
128
|
+
#
|
129
|
+
# @param [Time,Integer] time Time object or integer timestamp
|
130
|
+
# @return [Boolean]
|
131
|
+
def valid_at?(time)
|
132
|
+
if time.kind_of?(Integer)
|
133
|
+
time = Time.at(time)
|
134
|
+
end
|
135
|
+
|
136
|
+
if (self.not_after < time) or (self.not_before > time)
|
137
|
+
false
|
138
|
+
else
|
139
|
+
true
|
140
|
+
end
|
141
|
+
end
|
175
142
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
143
|
+
# @return [Boolean] Boolean of whether the object contains a private key
|
144
|
+
def has_private_key?
|
145
|
+
if not @key.nil?
|
146
|
+
true
|
147
|
+
else
|
148
|
+
false
|
149
|
+
end
|
150
|
+
end
|
184
151
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
152
|
+
# Return the CN, as well as all the subject alternative names (SANs).
|
153
|
+
#
|
154
|
+
# @return [Array] the array of names. Returns an empty array if
|
155
|
+
# there are no names, at all. Discards SAN types
|
156
|
+
def all_names
|
157
|
+
ret = []
|
158
|
+
ret << @subject.CN unless @subject.CN.nil?
|
159
|
+
ret.concat( self.san.names.map { |n| n.value } ) unless self.san.nil?
|
191
160
|
|
192
|
-
|
193
|
-
|
194
|
-
# @return [String] value of the subject component requested
|
195
|
-
def subject_component short_name
|
196
|
-
match = @cert.subject.to_a.find { |x| x[0] == short_name }
|
197
|
-
return nil if match.nil?
|
198
|
-
return match[1]
|
199
|
-
end
|
161
|
+
return ret.sort.uniq
|
162
|
+
end
|
200
163
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
ret << subject_cn unless subject_cn.nil?
|
208
|
-
ret.concat( self.san_names )
|
164
|
+
# Returns whether the public key is RSA
|
165
|
+
#
|
166
|
+
# @return [Boolean] true if the public key is RSA, false otherwise
|
167
|
+
def rsa?
|
168
|
+
@cert.public_key.kind_of?(OpenSSL::PKey::RSA)
|
169
|
+
end
|
209
170
|
|
210
|
-
|
211
|
-
|
171
|
+
# Returns whether the public key is DSA
|
172
|
+
#
|
173
|
+
# @return [Boolean] true if the public key is DSA, false otherwise
|
174
|
+
def dsa?
|
175
|
+
@cert.public_key.kind_of?(OpenSSL::PKey::DSA)
|
176
|
+
end
|
212
177
|
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
178
|
+
# Returns whether the public key is EC
|
179
|
+
#
|
180
|
+
# @return [Boolean] true if the public key is EC, false otherwise
|
181
|
+
def ec?
|
182
|
+
@cert.public_key.kind_of?(OpenSSL::PKey::EC)
|
183
|
+
end
|
219
184
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
185
|
+
# Returns the bit strength of the key used to create the certificate
|
186
|
+
#
|
187
|
+
# @return [Integer] integer value of bit strength
|
188
|
+
def bit_strength
|
189
|
+
if self.rsa?
|
190
|
+
return @cert.public_key.n.num_bits
|
191
|
+
elsif self.dsa?
|
192
|
+
return @cert.public_key.p.num_bits
|
193
|
+
elsif self.ec?
|
194
|
+
raise R509::R509Error, 'Bit strength is not available for EC at this time.'
|
195
|
+
end
|
196
|
+
end
|
226
197
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
198
|
+
# Returns the short name of the elliptic curve used to generate the public key
|
199
|
+
# if the key is EC. If not, raises an error.
|
200
|
+
#
|
201
|
+
# @return [String] elliptic curve name
|
202
|
+
def curve_name
|
203
|
+
if self.ec?
|
204
|
+
@cert.public_key.group.curve_name
|
205
|
+
else
|
206
|
+
raise R509::R509Error, 'Curve name is only available with EC certs'
|
207
|
+
end
|
208
|
+
end
|
237
209
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
210
|
+
# Returns signature algorithm
|
211
|
+
#
|
212
|
+
# @return [String] value of the signature algorithm. E.g. sha1WithRSAEncryption, sha256WithRSAEncryption, md5WithRSAEncryption, et cetera
|
213
|
+
def signature_algorithm
|
214
|
+
@cert.signature_algorithm
|
215
|
+
end
|
244
216
|
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
217
|
+
# Returns key algorithm (RSA, DSA, EC)
|
218
|
+
#
|
219
|
+
# @return [Symbol] value of the key algorithm. :rsa, :dsa, :ec
|
220
|
+
def key_algorithm
|
221
|
+
if self.rsa?
|
222
|
+
:rsa
|
223
|
+
elsif self.dsa?
|
224
|
+
:dsa
|
225
|
+
elsif self.ec?
|
226
|
+
:ec
|
227
|
+
end
|
228
|
+
end
|
255
229
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
230
|
+
# Writes the Cert into the PEM format
|
231
|
+
# @param [String, #write] filename_or_io Either a string of the path for
|
232
|
+
# the file that you'd like to write, or an IO-like object.
|
233
|
+
def write_pem(filename_or_io)
|
234
|
+
write_data(filename_or_io, @cert.to_pem)
|
235
|
+
end
|
262
236
|
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
237
|
+
# Writes the Cert into the DER format
|
238
|
+
# @param [String, #write] filename_or_io Either a string of the path for
|
239
|
+
# the file that you'd like to write, or an IO-like object.
|
240
|
+
def write_der(filename_or_io)
|
241
|
+
write_data(filename_or_io, @cert.to_der)
|
242
|
+
end
|
269
243
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
244
|
+
# Writes cert and key into PKCS12 format using OpenSSL defaults for encryption (des3)
|
245
|
+
# @param [String, #write] filename_or_io Either a string of the path for
|
246
|
+
# the file that you'd like to write, or an IO-like object.
|
247
|
+
# @param [String] password password
|
248
|
+
# @param [String] friendly_name An optional string to encode in the PKCS12 for friendlyName. defaults to "r509 pkcs12"
|
249
|
+
def write_pkcs12(filename_or_io,password,friendly_name='r509 pkcs12')
|
250
|
+
if @key.nil?
|
251
|
+
raise R509::R509Error, "Writing a PKCS12 requires both key and cert"
|
252
|
+
end
|
253
|
+
pkcs12 = OpenSSL::PKCS12.create(password,friendly_name,@key.key,@cert)
|
254
|
+
write_data(filename_or_io, pkcs12.to_der)
|
255
|
+
end
|
282
256
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
257
|
+
# Checks the given CRL for this certificate's serial number. Note that this does NOT
|
258
|
+
# check to verify that the CRL you're checking is signed by the same CA as the cert
|
259
|
+
# so do that check yourself
|
260
|
+
#
|
261
|
+
# @param [R509::CRL::SignedList] r509_crl A CRL from the CA that issued this certificate.
|
262
|
+
def is_revoked_by_crl?( r509_crl )
|
263
|
+
return r509_crl.revoked?( self.serial )
|
264
|
+
end
|
291
265
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
266
|
+
# Returns the certificate extensions as a hash of R509::Cert::Extensions
|
267
|
+
# specific objects.
|
268
|
+
#
|
269
|
+
# @return [Hash] A hash, in which the values are classes from the
|
270
|
+
# R509::Cert::Extensions module, each specific to the extension. The hash
|
271
|
+
# is keyed with the R509 extension class. Extensions without an R509
|
272
|
+
# implementation are ignored (see #get_unknown_extensions).
|
273
|
+
def extensions
|
274
|
+
if @r509_extensions.nil?
|
275
|
+
@r509_extensions = Extensions.wrap_openssl_extensions( self.cert.extensions )
|
276
|
+
end
|
277
|
+
|
278
|
+
return @r509_extensions
|
279
|
+
end
|
305
280
|
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
def r509_extensions
|
314
|
-
if @r509_extensions.nil?
|
315
|
-
@r509_extensions = Extensions.wrap_openssl_extensions( self.cert.extensions )
|
316
|
-
end
|
317
|
-
|
318
|
-
return @r509_extensions
|
319
|
-
end
|
281
|
+
# Returns an array of OpenSSL::X509::Extension objects representing the
|
282
|
+
# extensions that do not have R509 implementations.
|
283
|
+
#
|
284
|
+
# @return [Array] An array of OpenSSL::X509::Extension objects.
|
285
|
+
def unknown_extensions
|
286
|
+
return Extensions.get_unknown_extensions( self.cert.extensions )
|
287
|
+
end
|
320
288
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
# @return [Array] An array of OpenSSL::X509::Extension objects.
|
325
|
-
def unknown_extensions
|
326
|
-
return Extensions.get_unknown_extensions( self.cert.extensions )
|
327
|
-
end
|
289
|
+
#
|
290
|
+
# Shortcuts to extensions
|
291
|
+
#
|
328
292
|
|
329
|
-
|
330
|
-
|
331
|
-
|
293
|
+
# Returns this object's BasicConstraints extension as an R509 extension
|
294
|
+
#
|
295
|
+
# @return [R509::Cert::Extensions::BasicConstraints] The object, or nil
|
296
|
+
# if this cert does not have a BasicConstraints extension.
|
297
|
+
def basic_constraints
|
298
|
+
return extensions[R509::Cert::Extensions::BasicConstraints]
|
299
|
+
end
|
332
300
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
301
|
+
# Returns this object's KeyUsage extension as an R509 extension
|
302
|
+
#
|
303
|
+
# @return [R509::Cert::Extensions::KeyUsage] The object, or nil
|
304
|
+
# if this cert does not have a KeyUsage extension.
|
305
|
+
def key_usage
|
306
|
+
return extensions[R509::Cert::Extensions::KeyUsage]
|
307
|
+
end
|
308
|
+
alias_method :ku, :key_usage
|
309
|
+
|
310
|
+
# Returns this object's ExtendedKeyUsage extension as an R509 extension
|
311
|
+
#
|
312
|
+
# @return [R509::Cert::Extensions::ExtendedKeyUsage] The object, or nil
|
313
|
+
# if this cert does not have a ExtendedKeyUsage extension.
|
314
|
+
def extended_key_usage
|
315
|
+
return extensions[R509::Cert::Extensions::ExtendedKeyUsage]
|
316
|
+
end
|
317
|
+
alias_method :eku, :extended_key_usage
|
318
|
+
|
319
|
+
# Returns this object's SubjectKeyIdentifier extension as an R509 extension
|
320
|
+
#
|
321
|
+
# @return [R509::Cert::Extensions::SubjectKeyIdentifier] The object, or nil
|
322
|
+
# if this cert does not have a SubjectKeyIdentifier extension.
|
323
|
+
def subject_key_identifier
|
324
|
+
return extensions[R509::Cert::Extensions::SubjectKeyIdentifier]
|
325
|
+
end
|
340
326
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
327
|
+
# Returns this object's AuthorityKeyIdentifier extension as an R509 extension
|
328
|
+
#
|
329
|
+
# @return [R509::Cert::Extensions::AuthorityKeyIdentifier] The object, or nil
|
330
|
+
# if this cert does not have a AuthorityKeyIdentifier extension.
|
331
|
+
def authority_key_identifier
|
332
|
+
return extensions[R509::Cert::Extensions::AuthorityKeyIdentifier]
|
333
|
+
end
|
348
334
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
335
|
+
# Returns this object's SubjectAlternativeName extension as an R509 extension
|
336
|
+
#
|
337
|
+
# @return [R509::Cert::Extensions::SubjectAlternativeName] The object, or nil
|
338
|
+
# if this cert does not have a SubjectAlternativeName extension.
|
339
|
+
def subject_alternative_name
|
340
|
+
return extensions[R509::Cert::Extensions::SubjectAlternativeName]
|
341
|
+
end
|
342
|
+
alias_method :san, :subject_alternative_name
|
343
|
+
alias_method :subject_alt_name, :subject_alternative_name
|
344
|
+
|
345
|
+
# Returns this object's AuthorityInfoAccess extension as an R509 extension
|
346
|
+
#
|
347
|
+
# @return [R509::Cert::Extensions::AuthorityInfoAccess] The object, or nil
|
348
|
+
# if this cert does not have a AuthorityInfoAccess extension.
|
349
|
+
def authority_info_access
|
350
|
+
return extensions[R509::Cert::Extensions::AuthorityInfoAccess]
|
351
|
+
end
|
352
|
+
alias_method :aia, :authority_info_access
|
353
|
+
|
354
|
+
# Returns this object's CRLDistributionPoints extension as an R509 extension
|
355
|
+
#
|
356
|
+
# @return [R509::Cert::Extensions::CRLDistributionPoints] The object, or nil
|
357
|
+
# if this cert does not have a CRLDistributionPoints extension.
|
358
|
+
def crl_distribution_points
|
359
|
+
return extensions[R509::Cert::Extensions::CRLDistributionPoints]
|
360
|
+
end
|
361
|
+
alias_method :cdp, :crl_distribution_points
|
362
|
+
|
363
|
+
# Returns true if the OCSP No Check extension is present
|
364
|
+
# (value is irrelevant to this extension)
|
365
|
+
#
|
366
|
+
# @return [Boolean] presence/absence of the nocheck extension
|
367
|
+
def ocsp_no_check?
|
368
|
+
return (extensions.has_key?(R509::Cert::Extensions::OCSPNoCheck))
|
369
|
+
end
|
356
370
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
371
|
+
# Returns this object's CertificatePolicies extension as an R509 extension
|
372
|
+
#
|
373
|
+
# @return [R509::Cert::Extensions::CertificatePolicies] The object, or nil
|
374
|
+
# if this cert does not have a CertificatePolicies extension.
|
375
|
+
def certificate_policies
|
376
|
+
return extensions[R509::Cert::Extensions::CertificatePolicies]
|
377
|
+
end
|
364
378
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
379
|
+
# Returns this object's InhibitAnyPolicy extension as an R509 extension
|
380
|
+
#
|
381
|
+
# @return [R509::Cert::Extensions::InhibitAnyPolicy] The object, or nil
|
382
|
+
# if this cert does not have a InhibitAnyPolicy extension.
|
383
|
+
def inhibit_any_policy
|
384
|
+
return extensions[R509::Cert::Extensions::InhibitAnyPolicy]
|
385
|
+
end
|
372
386
|
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
387
|
+
# Returns this object's PolicyConstraints extension as an R509 extension
|
388
|
+
#
|
389
|
+
# @return [R509::Cert::Extensions::PolicyConstraints] The object, or nil
|
390
|
+
# if this cert does not have a PolicyConstraints extension.
|
391
|
+
def policy_constraints
|
392
|
+
return extensions[R509::Cert::Extensions::PolicyConstraints]
|
393
|
+
end
|
380
394
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
395
|
+
# Returns this object's NameConstraints extension as an R509 extension
|
396
|
+
#
|
397
|
+
# @return [R509::Cert::Extensions::NameConstraints] The object, or nil
|
398
|
+
# if this cert does not have a NameConstraints extension.
|
399
|
+
def name_constraints
|
400
|
+
return extensions[R509::Cert::Extensions::NameConstraints]
|
401
|
+
end
|
388
402
|
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
403
|
+
private
|
404
|
+
# This method exists only to provide a friendlier error msg if you attempt to
|
405
|
+
# parse a CSR as a certificate. All for Sean
|
406
|
+
def csr_check(cert)
|
407
|
+
begin
|
408
|
+
csr = OpenSSL::X509::Request.new cert
|
409
|
+
raise ArgumentError, 'Cert provided is actually a certificate signing request.'
|
410
|
+
rescue OpenSSL::X509::RequestError
|
411
|
+
# do nothing, it shouldn't be a CSR anyway!
|
412
|
+
end
|
413
|
+
end
|
396
414
|
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
csr = OpenSSL::X509::Request.new cert
|
403
|
-
raise R509Error, 'Cert provided is actually a certificate signing request.'
|
404
|
-
rescue OpenSSL::X509::RequestError
|
405
|
-
# do nothing, it shouldn't be a CSR anyway!
|
406
|
-
end
|
407
|
-
end
|
415
|
+
def parse_certificate(cert)
|
416
|
+
@cert = OpenSSL::X509::Certificate.new cert
|
417
|
+
@subject = R509::Subject.new(@cert.subject)
|
418
|
+
@issuer = R509::Subject.new(@cert.issuer)
|
419
|
+
end
|
408
420
|
|
409
|
-
|
410
|
-
|
421
|
+
def associate_private_key(key)
|
422
|
+
if not key.nil?
|
423
|
+
if not @cert.public_key.to_der == key.public_key.to_der then
|
424
|
+
raise R509Error, 'Key does not match cert.'
|
411
425
|
end
|
412
|
-
|
426
|
+
@key = key
|
427
|
+
end
|
413
428
|
end
|
429
|
+
|
430
|
+
end
|
414
431
|
end
|