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