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/crl.rb CHANGED
@@ -4,376 +4,346 @@ require 'r509/exceptions'
4
4
  require 'r509/io_helpers'
5
5
 
6
6
  module R509
7
- # contains CRL related classes (generator and a pre-existing list loader)
8
- module Crl
9
-
10
- class Parser
11
- attr_reader :crl
12
-
13
- # @param [String,OpenSSL::X509::CRL] crl
14
- def initialize(crl)
15
- @crl = OpenSSL::X509::CRL.new(crl)
16
- end
17
-
18
- # Helper method to quickly load a CRL from the filesystem
19
- #
20
- # @param [String] filename Path to file you want to load
21
- # @return [R509::Crl::Parser] CRL object
22
- def self.load_from_file( filename )
23
- return R509::Crl::Parser.new( IOHelpers.read_data(filename) )
24
- end
25
-
26
- # @return [OpenSSL::X509::Name]
27
- def issuer
28
- @crl.issuer
29
- end
30
-
31
- # @return [String] The common name (CN) component of the issuer
32
- def issuer_cn
33
- return nil if self.issuer.nil?
34
-
35
- self.issuer.to_a.each do |part, value, length|
36
- return value if part.upcase == 'CN'
37
- end
38
-
39
- # return nil if we didn't find a CN part
40
- return nil
41
- end
42
-
43
- # @return [Time]
44
- def last_update
45
- @crl.last_update
46
- end
47
-
48
- # @return [Time]
49
- def next_update
50
- @crl.next_update
51
- end
52
-
53
- # @return [String]
54
- def signature_algorithm
55
- @crl.signature_algorithm
56
- end
57
-
58
- # Pass a public key to verify that the CRL is signed by a specific certificate (call cert.public_key on that object)
59
- #
60
- # @param [OpenSSL::PKey::PKey] public_key
61
- # @return [Boolean]
62
- def verify(public_key)
63
- @crl.verify(public_key)
64
- end
65
-
66
- # @param [Integer] serial number
67
- # @return [Boolean]
68
- def revoked?(serial)
69
- if @crl.revoked.find { |revoked| revoked.serial == serial }
70
- true
71
- else
72
- false
73
- end
74
- end
75
-
76
- # @return [Hash] hash of serial => { :time, :reason } hashes
77
- def revoked
78
- revoked_list = {}
79
- @crl.revoked.each do |revoked|
80
- reason = get_reason(revoked)
81
- revoked_list[revoked.serial.to_i] = { :time => revoked.time, :reason => reason }
82
- end
83
-
84
- revoked_list
85
- end
86
-
87
- # @param [Integer] serial number
88
- # @return [Hash] hash with :time and :reason
89
- def revoked_cert(serial)
90
- revoked = @crl.revoked.find { |revoked| revoked.serial == serial }
91
- if revoked
92
- reason = get_reason(revoked)
93
- { :time => revoked.time, :reason => reason }
94
- else
95
- nil
96
- end
97
- end
98
-
99
- private
100
- def get_reason(revocation_object)
101
- reason = nil
102
- revocation_object.extensions.each do |extension|
103
- if extension.oid == "CRLReason"
104
- reason = extension.value
105
- end
106
- end
107
-
108
- reason
109
- end
7
+ # contains CRL related classes (generator and a pre-existing list loader)
8
+ module CRL
9
+ # Parses CRLs
10
+ class SignedList
11
+ include R509::IOHelpers
12
+
13
+ attr_reader :crl, :issuer
14
+
15
+ # @param [String,OpenSSL::X509::CRL] crl
16
+ def initialize(crl)
17
+ @crl = OpenSSL::X509::CRL.new(crl)
18
+ @issuer = R509::Subject.new(@crl.issuer)
19
+ end
20
+
21
+ # Helper method to quickly load a CRL from the filesystem
22
+ #
23
+ # @param [String] filename Path to file you want to load
24
+ # @return [R509::CRL::SignedList] CRL object
25
+ def self.load_from_file( filename )
26
+ return R509::CRL::SignedList.new( IOHelpers.read_data(filename) )
27
+ end
28
+
29
+ # @return [String]
30
+ def signature_algorithm
31
+ @crl.signature_algorithm
32
+ end
33
+
34
+ # Writes the CRL into the PEM format
35
+ #
36
+ # @param [String, #write] filename_or_io Either a string of the path for
37
+ # the file that you'd like to write, or an IO-like object.
38
+ def write_pem(filename_or_io)
39
+ write_data(filename_or_io, @crl.to_pem)
40
+ end
41
+
42
+ # Writes the CRL into the PEM format
43
+ #
44
+ # @param [String, #write] filename_or_io Either a string of the path for
45
+ # the file that you'd like to write, or an IO-like object.
46
+ def write_der(filename_or_io)
47
+ write_data(filename_or_io, @crl.to_der)
48
+ end
49
+
50
+ # Returns the signing time of the CRL
51
+ #
52
+ # @return [Time] when the CRL was signed
53
+ def last_update
54
+ @crl.last_update
55
+ end
56
+
57
+ # Returns the next update time for the CRL
58
+ #
59
+ # @return [Time] when it will be updated next
60
+ def next_update
61
+ @crl.next_update
62
+ end
63
+
64
+ # Pass a public key to verify that the CRL is signed by a specific certificate (call cert.public_key on that object)
65
+ #
66
+ # @param [OpenSSL::PKey::PKey] public_key
67
+ # @return [Boolean]
68
+ def verify(public_key)
69
+ @crl.verify(public_key)
70
+ end
71
+
72
+ # @param [Integer] serial number
73
+ # @return [Boolean]
74
+ def revoked?(serial)
75
+ if @crl.revoked.find { |revoked| revoked.serial == serial }
76
+ true
77
+ else
78
+ false
110
79
  end
80
+ end
81
+
82
+ # Returns the CRL in PEM format
83
+ #
84
+ # @return [String] the CRL in PEM format
85
+ def to_pem
86
+ @crl.to_pem
87
+ end
88
+
89
+ alias :to_s :to_pem
90
+
91
+ # Returns the CRL in DER format
92
+ #
93
+ # @return [String] the CRL in DER format
94
+ def to_der
95
+ @crl.to_der
96
+ end
97
+
98
+ # @return [Hash] hash of serial => { :time, :reason } hashes
99
+ def revoked
100
+ revoked_list = {}
101
+ @crl.revoked.each do |revoked|
102
+ reason = get_reason(revoked)
103
+ revoked_list[revoked.serial.to_i] = { :time => revoked.time, :reason => reason }
104
+ end
105
+
106
+ revoked_list
107
+ end
108
+
109
+ # @param [Integer] serial number
110
+ # @return [Hash] hash with :time and :reason
111
+ def revoked_cert(serial)
112
+ revoked = @crl.revoked.find { |revoked| revoked.serial == serial }
113
+ if revoked
114
+ reason = get_reason(revoked)
115
+ { :time => revoked.time, :reason => reason }
116
+ else
117
+ nil
118
+ end
119
+ end
120
+
121
+ private
122
+ def get_reason(revocation_object)
123
+ reason = nil
124
+ revocation_object.extensions.each do |extension|
125
+ if extension.oid == "CRLReason"
126
+ reason = extension.value
127
+ end
128
+ end
129
+
130
+ reason
131
+ end
132
+ end
133
+
134
+ # Used to manage revocations and generate CRLs
135
+ class Administrator
136
+ include R509::IOHelpers
111
137
 
112
- # Used to manage revocations and generate CRLs
113
- class Administrator
114
- include R509::IOHelpers
115
-
116
- attr_reader :crl_number,:crl_list_file,:crl_number_file, :validity_hours
117
-
118
- # @param [R509::Config::CaConfig] config
119
- def initialize(config)
120
- @config = config
121
-
122
- unless @config.kind_of?(R509::Config::CaConfig)
123
- raise R509Error, "config must be a kind of R509::Config::CaConfig"
124
- end
125
-
126
- @validity_hours = @config.crl_validity_hours
127
- @start_skew_seconds = @config.crl_start_skew_seconds
128
- @crl = nil
129
-
130
- @crl_number_file = @config.crl_number_file
131
- if not @crl_number_file.nil?
132
- @crl_number = read_data(@crl_number_file).to_i
133
- else
134
- @crl_number = 0
135
- end
136
-
137
-
138
- @crl_list_file = @config.crl_list_file
139
- load_crl_list(@crl_list_file)
140
- end
141
-
142
- # Indicates whether the serial number has been revoked, or not.
143
- #
144
- # @param [Integer] serial The serial number we want to check
145
- # @return [Boolean] True if the serial number was revoked. False, otherwise.
146
- def revoked?(serial)
147
- @revoked_certs.has_key?(serial)
148
- end
149
-
150
- # @return [Array] serial, reason, revoke_time tuple
151
- def revoked_cert(serial)
152
- @revoked_certs[serial]
153
- end
154
-
155
- # Returns the CRL in PEM format
156
- #
157
- # @return [String] the CRL in PEM format
158
- def to_pem
159
- @crl.to_pem
160
- end
161
-
162
- alias :to_s :to_pem
163
-
164
- # Returns the CRL in DER format
165
- #
166
- # @return [String] the CRL in DER format
167
- def to_der
168
- @crl.to_der
169
- end
170
-
171
- # @return [R509::Crl::Parser]
172
- def to_crl
173
- return nil if @crl.nil?
174
- return R509::Crl::Parser.new(@crl)
175
- end
176
-
177
- # Writes the CRL into the PEM format
178
- #
179
- # @param [String, #write] filename_or_io Either a string of the path for
180
- # the file that you'd like to write, or an IO-like object.
181
- def write_pem(filename_or_io)
182
- write_data(filename_or_io, @crl.to_pem)
183
- end
184
-
185
- # Writes the CRL into the PEM format
186
- #
187
- # @param [String, #write] filename_or_io Either a string of the path for
188
- # the file that you'd like to write, or an IO-like object.
189
- def write_der(filename_or_io)
190
- write_data(filename_or_io, @crl.to_der)
191
- end
192
-
193
- # Returns the signing time of the CRL
194
- #
195
- # @return [Time] when the CRL was signed
196
- def last_update
197
- @crl.last_update
198
- end
199
-
200
- # Returns the next update time for the CRL
201
- #
202
- # @return [Time] when it will be updated next
203
- def next_update
204
- @crl.next_update
205
- end
206
-
207
- # Adds a certificate to the revocation list. After calling you must call generate_crl to sign a new CRL
208
- #
209
- # @param serial [Integer] serial number of the certificate to revoke
210
- # @param reason [Integer] reason for revocation
211
- # @param revoke_time [Integer]
212
- # @param generate_and_save [Boolean] whether we want to generate the CRL and save its file (default=true)
213
- #
214
- # reason codes defined by rfc 5280
215
- #
216
- # CRLReason ::= ENUMERATED {
217
- # unspecified (0),
218
- # keyCompromise (1),
219
- # cACompromise (2),
220
- # affiliationChanged (3),
221
- # superseded (4),
222
- # cessationOfOperation (5),
223
- # certificateHold (6),
224
- # removeFromCRL (8),
225
- # privilegeWithdrawn (9),
226
- # aACompromise (10) }
227
- def revoke_cert(serial,reason=nil, revoke_time=Time.now.to_i, generate_and_save=true)
228
- if not reason.to_i.between?(0,10)
229
- reason = 0
230
- end
231
- serial = serial.to_i
232
- reason = reason.to_i
233
- revoke_time = revoke_time.to_i
234
- if revoked?(serial)
235
- raise R509::R509Error, "Cannot revoke a previously revoked certificate"
236
- end
237
- @revoked_certs[serial] = {:reason => reason, :revoke_time => revoke_time}
238
- if generate_and_save
239
- generate_crl()
240
- save_crl_list()
241
- end
242
- nil
243
- end
244
-
245
- # Remove serial from revocation list. After unrevoking you must call generate_crl to sign a new CRL
246
- #
247
- # @param serial [Integer] serial number of the certificate to remove from revocation
248
- def unrevoke_cert(serial)
249
- @revoked_certs.delete(serial)
250
- generate_crl()
251
- save_crl_list()
252
- nil
253
- end
254
-
255
- # Remove serial from revocation list
256
- #
257
- # @return [String] PEM encoded signed CRL
258
- def generate_crl
259
- crl = OpenSSL::X509::CRL.new
260
- crl.version = 1
261
- now = Time.at Time.now.to_i
262
- crl.last_update = now-@start_skew_seconds
263
- crl.next_update = now+@validity_hours*3600
264
- crl.issuer = @config.ca_cert.subject
265
-
266
- self.revoked_certs.each do |serial, reason, revoke_time|
267
- revoked = OpenSSL::X509::Revoked.new
268
- revoked.serial = OpenSSL::BN.new serial.to_s
269
- revoked.time = Time.at(revoke_time)
270
- if !reason.nil?
271
- enum = OpenSSL::ASN1::Enumerated(reason) #see reason codes below
272
- ext = OpenSSL::X509::Extension.new("CRLReason", enum)
273
- revoked.add_extension(ext)
274
- end
275
- #now add it to the crl
276
- crl.add_revoked(revoked)
277
- end
278
-
279
- ef = OpenSSL::X509::ExtensionFactory.new
280
- ef.issuer_certificate = @config.ca_cert.cert
281
- ef.crl = crl
282
- #grab crl number from file, increment, write back
283
- crl_number = increment_crl_number
284
- crlnum = OpenSSL::ASN1::Integer(crl_number)
285
- crl.add_extension(OpenSSL::X509::Extension.new("crlNumber", crlnum))
286
- extensions = []
287
- extensions << ["authorityKeyIdentifier", "keyid:always,issuer:always", false]
288
- extensions.each{|oid, value, critical|
289
- crl.add_extension(ef.create_extension(oid, value, critical))
290
- }
291
- crl.sign(@config.ca_cert.key.key, OpenSSL::Digest::SHA1.new)
292
- @crl = crl
293
- @crl.to_pem
294
- end
295
-
296
- # @return [Array<Array>] Returns an array of serial, reason, revoke_time
297
- # tuples.
298
- def revoked_certs
299
- ret = []
300
- @revoked_certs.keys.sort.each do |serial|
301
- ret << [serial, @revoked_certs[serial][:reason], @revoked_certs[serial][:revoke_time]]
302
- end
303
- ret
304
- end
305
-
306
- # Saves the CRL list to a filename or IO. If the class was initialized
307
- # with :crl_list_file, then the filename specified by that will be used
308
- # by default.
309
- # @param [String, #write, nil] filename_or_io If provided, the generated
310
- # crl will be written to either the file (if a string), or IO. If nil,
311
- # then the @crl_list_file will be used. If that is nil, then an error
312
- # will be raised.
313
- def save_crl_list(filename_or_io = @crl_list_file)
314
- return nil if filename_or_io.nil?
315
-
316
- data = []
317
- self.revoked_certs.each do |serial, reason, revoke_time|
318
- data << [serial, revoke_time, reason].join(',')
319
- end
320
- write_data(filename_or_io, data.join("\n"))
321
- nil
322
- end
323
-
324
- # Save the CRL number to a filename or IO. If the class was initialized
325
- # with :crl_number_file, then the filename specified by that will be used
326
- # by default.
327
- # @param [String, #write, nil] filename_or_io If provided, the current
328
- # crl number will be written to either the file (if a string), or IO. If nil,
329
- # then the @crl_number_file will be used. If that is nil, then an error
330
- # will be raised.
331
- def save_crl_number(filename_or_io = @crl_number_file)
332
- return nil if filename_or_io.nil?
333
- # No valid filename or IO was specified, so bail.
334
-
335
- write_data(filename_or_io, self.crl_number.to_s)
336
- nil
337
- end
338
-
339
- private
340
-
341
- # Increments the crl_number.
342
- # @return [Integer] the new CRL number
343
- #
344
- def increment_crl_number
345
- @crl_number += 1
346
- save_crl_number()
347
- @crl_number
348
- end
349
-
350
- # Loads the certificate revocation list from file.
351
- # @param [String, #read, nil] filename_or_io The
352
- # crl will be read from either the file (if a string), or IO.
353
- def load_crl_list(filename_or_io)
354
- @revoked_certs = {}
355
-
356
- if filename_or_io.nil?
357
- generate_crl
358
- return nil
359
- end
360
-
361
- data = read_data(filename_or_io)
362
-
363
- data.each_line do |line|
364
- line.chomp!
365
- serial, revoke_time, reason = line.split(',', 3)
366
- serial = serial.to_i
367
- reason = (reason == '') ? nil : reason.to_i
368
- revoke_time = (revoke_time == '') ? nil : revoke_time.to_i
369
- self.revoke_cert(serial, reason, revoke_time, false)
370
- end
371
- generate_crl
372
- save_crl_list
373
- nil
374
- end
138
+ attr_reader :crl_number,:crl_list_file,:crl_number_file, :validity_hours, :crl
375
139
 
140
+ # @param [R509::Config::CAConfig] config
141
+ def initialize(config)
142
+ @config = config
143
+
144
+ unless @config.kind_of?(R509::Config::CAConfig)
145
+ raise R509Error, "config must be a kind of R509::Config::CAConfig"
146
+ end
147
+
148
+ @validity_hours = @config.crl_validity_hours
149
+ @start_skew_seconds = @config.crl_start_skew_seconds
150
+ @crl = nil
151
+
152
+ @crl_number_file = @config.crl_number_file
153
+ if not @crl_number_file.nil?
154
+ @crl_number = read_data(@crl_number_file).to_i
155
+ else
156
+ @crl_number = 0
376
157
  end
158
+
159
+
160
+ @crl_list_file = @config.crl_list_file
161
+ load_crl_list(@crl_list_file)
162
+ end
163
+
164
+ # Indicates whether the serial number has been revoked, or not.
165
+ #
166
+ # @param [Integer] serial The serial number we want to check
167
+ # @return [Boolean] True if the serial number was revoked. False, otherwise.
168
+ def revoked?(serial)
169
+ @revoked_certs.has_key?(serial)
170
+ end
171
+
172
+ # @return [Array] serial, reason, revoke_time tuple
173
+ def revoked_cert(serial)
174
+ @revoked_certs[serial]
175
+ end
176
+
177
+ # Adds a certificate to the revocation list. After calling you must call generate_crl to sign a new CRL
178
+ #
179
+ # @param serial [Integer] serial number of the certificate to revoke
180
+ # @param reason [Integer] reason for revocation
181
+ # @param revoke_time [Integer]
182
+ # @param generate_and_save [Boolean] whether we want to generate the CRL and save its file (default=true)
183
+ #
184
+ # reason codes defined by rfc 5280
185
+ #
186
+ # CRLReason ::= ENUMERATED {
187
+ # unspecified (0),
188
+ # keyCompromise (1),
189
+ # cACompromise (2),
190
+ # affiliationChanged (3),
191
+ # superseded (4),
192
+ # cessationOfOperation (5),
193
+ # certificateHold (6),
194
+ # removeFromCRL (8),
195
+ # privilegeWithdrawn (9),
196
+ # aACompromise (10) }
197
+ def revoke_cert(serial,reason=nil, revoke_time=Time.now.to_i, generate_and_save=true)
198
+ if not reason.to_i.between?(0,10)
199
+ reason = 0
200
+ end
201
+ serial = serial.to_i
202
+ reason = reason.to_i
203
+ revoke_time = revoke_time.to_i
204
+ if revoked?(serial)
205
+ raise R509::R509Error, "Cannot revoke a previously revoked certificate"
206
+ end
207
+ @revoked_certs[serial] = {:reason => reason, :revoke_time => revoke_time}
208
+ if generate_and_save
209
+ generate_crl
210
+ save_crl_list
211
+ end
212
+ nil
213
+ end
214
+
215
+ # Remove serial from revocation list. After unrevoking you must call generate_crl to sign a new CRL
216
+ #
217
+ # @param serial [Integer] serial number of the certificate to remove from revocation
218
+ def unrevoke_cert(serial)
219
+ @revoked_certs.delete(serial)
220
+ generate_crl
221
+ save_crl_list
222
+ nil
223
+ end
224
+
225
+ # Remove serial from revocation list
226
+ #
227
+ # @return [String] PEM encoded signed CRL
228
+ def generate_crl
229
+ crl = OpenSSL::X509::CRL.new
230
+ crl.version = 1
231
+ now = Time.at Time.now.to_i
232
+ crl.last_update = now-@start_skew_seconds
233
+ crl.next_update = now+@validity_hours*3600
234
+ crl.issuer = @config.ca_cert.subject.name
235
+
236
+ self.revoked_certs.each do |serial, reason, revoke_time|
237
+ revoked = OpenSSL::X509::Revoked.new
238
+ revoked.serial = OpenSSL::BN.new serial.to_s
239
+ revoked.time = Time.at(revoke_time)
240
+ if !reason.nil?
241
+ enum = OpenSSL::ASN1::Enumerated(reason) #see reason codes below
242
+ ext = OpenSSL::X509::Extension.new("CRLReason", enum)
243
+ revoked.add_extension(ext)
244
+ end
245
+ #now add it to the crl
246
+ crl.add_revoked(revoked)
247
+ end
248
+
249
+ ef = OpenSSL::X509::ExtensionFactory.new
250
+ ef.issuer_certificate = @config.ca_cert.cert
251
+ ef.crl = crl
252
+ #grab crl number from file, increment, write back
253
+ crl_number = increment_crl_number
254
+ crlnum = OpenSSL::ASN1::Integer(crl_number)
255
+ crl.add_extension(OpenSSL::X509::Extension.new("crlNumber", crlnum))
256
+ extensions = []
257
+ extensions << ["authorityKeyIdentifier", "keyid:always,issuer:always", false]
258
+ extensions.each{|oid, value, critical|
259
+ crl.add_extension(ef.create_extension(oid, value, critical))
260
+ }
261
+ crl.sign(@config.ca_cert.key.key, OpenSSL::Digest::SHA1.new)
262
+ @crl = R509::CRL::SignedList.new crl
263
+ @crl.to_pem
264
+ end
265
+
266
+ # @return [Array<Array>] Returns an array of serial, reason, revoke_time
267
+ # tuples.
268
+ def revoked_certs
269
+ ret = []
270
+ @revoked_certs.keys.sort.each do |serial|
271
+ ret << [serial, @revoked_certs[serial][:reason], @revoked_certs[serial][:revoke_time]]
272
+ end
273
+ ret
274
+ end
275
+
276
+ # Saves the CRL list to a filename or IO. If the class was initialized
277
+ # with :crl_list_file, then the filename specified by that will be used
278
+ # by default.
279
+ # @param [String, #write, nil] filename_or_io If provided, the generated
280
+ # crl will be written to either the file (if a string), or IO. If nil,
281
+ # then the @crl_list_file will be used. If that is nil, then an error
282
+ # will be raised.
283
+ def save_crl_list(filename_or_io = @crl_list_file)
284
+ return nil if filename_or_io.nil?
285
+
286
+ data = []
287
+ self.revoked_certs.each do |serial, reason, revoke_time|
288
+ data << [serial, revoke_time, reason].join(',')
289
+ end
290
+ write_data(filename_or_io, data.join("\n"))
291
+ nil
292
+ end
293
+
294
+ # Save the CRL number to a filename or IO. If the class was initialized
295
+ # with :crl_number_file, then the filename specified by that will be used
296
+ # by default.
297
+ # @param [String, #write, nil] filename_or_io If provided, the current
298
+ # crl number will be written to either the file (if a string), or IO. If nil,
299
+ # then the @crl_number_file will be used. If that is nil, then an error
300
+ # will be raised.
301
+ def save_crl_number(filename_or_io = @crl_number_file)
302
+ return nil if filename_or_io.nil?
303
+ # No valid filename or IO was specified, so bail.
304
+
305
+ write_data(filename_or_io, self.crl_number.to_s)
306
+ nil
307
+ end
308
+
309
+ private
310
+
311
+ # Increments the crl_number.
312
+ # @return [Integer] the new CRL number
313
+ #
314
+ def increment_crl_number
315
+ @crl_number += 1
316
+ save_crl_number
317
+ @crl_number
318
+ end
319
+
320
+ # Loads the certificate revocation list from file.
321
+ # @param [String, #read, nil] filename_or_io The
322
+ # crl will be read from either the file (if a string), or IO.
323
+ def load_crl_list(filename_or_io)
324
+ @revoked_certs = {}
325
+
326
+ if filename_or_io.nil?
327
+ generate_crl
328
+ return nil
329
+ end
330
+
331
+ data = read_data(filename_or_io)
332
+
333
+ data.each_line do |line|
334
+ line.chomp!
335
+ serial, revoke_time, reason = line.split(',', 3)
336
+ serial = serial.to_i
337
+ reason = (reason == '') ? nil : reason.to_i
338
+ revoke_time = (revoke_time == '') ? nil : revoke_time.to_i
339
+ self.revoke_cert(serial, reason, revoke_time, false)
340
+ end
341
+ generate_crl
342
+ save_crl_list
343
+ nil
344
+ end
345
+
377
346
  end
347
+ end
378
348
  end
379
349