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
@@ -1,290 +0,0 @@
1
- require 'openssl'
2
- require 'r509/config'
3
- require 'r509/cert'
4
- require 'r509/exceptions'
5
-
6
- # CertificateAuthority related classes
7
- module R509::CertificateAuthority
8
- # Contains the certification authority signing operation methods
9
- class Signer
10
- # @param [R509::Config] config
11
- def initialize(config=nil)
12
- @config = config
13
-
14
- if not @config.nil? and not @config.kind_of?(R509::Config::CaConfig)
15
- raise R509::R509Error, "config must be a kind of R509::Config::CaConfig or nil (for self-sign only)"
16
- end
17
- if not @config.nil? and not @config.ca_cert.has_private_key?
18
- raise R509::R509Error, "You must have a private key associated with your CA certificate to issue"
19
- end
20
- end
21
-
22
- # Signs a CSR
23
- # @option options :csr [R509::Csr]
24
- # @option options :spki [R509::Spki]
25
- # @option options :profile_name [String] The CA profile you want to use (eg "server in your config)
26
- # @option options :data_hash [Hash] a hash containing the subject and SAN names you want encoded for this cert. Generate by calling Csr#to_hash or Spki#to_hash
27
- # @option options :message_digest [String] the message digest to use for this certificate instead of the config's default
28
- # @option options :serial [String] the serial number you want to issue the certificate with
29
- # @option options :not_before [Time] the notBefore for the certificate
30
- # @option options :not_after [Time] the notAfter for the certificate
31
- # @return [R509::Cert] the signed cert object
32
- def sign(options)
33
- if @config.nil?
34
- raise R509::R509Error, "When instantiating the signer without a config you can only call #selfsign"
35
- elsif @config.num_profiles == 0
36
- raise R509::R509Error, "You must have at least one CaProfile on your CaConfig to issue"
37
- end
38
-
39
- if options.has_key?(:csr) and options.has_key?(:spki)
40
- raise ArgumentError, "You can't pass both :csr and :spki"
41
- elsif not options.has_key?(:csr) and not options.has_key?(:spki)
42
- raise ArgumentError, "You must supply either :csr or :spki"
43
- elsif options.has_key?(:csr)
44
- if not options[:csr].kind_of?(R509::Csr)
45
- raise ArgumentError, "You must pass an R509::Csr object for :csr"
46
- else
47
- signable_object = options[:csr]
48
- end
49
- elsif not options.has_key?(:csr) and options.has_key?(:spki)
50
- if not options[:spki].kind_of?(R509::Spki)
51
- raise ArgumentError, "You must pass an R509::Spki object for :spki"
52
- else
53
- signable_object = options[:spki]
54
- end
55
- end
56
-
57
- if options.has_key?(:data_hash)
58
- san_names = options[:data_hash][:san_names]
59
- subject = options[:data_hash][:subject]
60
- else
61
- san_names = signable_object.to_hash[:san_names]
62
- subject = signable_object.to_hash[:subject]
63
- end
64
-
65
-
66
-
67
- if options.has_key?(:csr) and not options[:csr].verify_signature
68
- raise R509::R509Error, "Certificate request signature is invalid."
69
- end
70
-
71
- #handle DSA here
72
- if options.has_key?(:message_digest)
73
- message_digest = R509::MessageDigest.new(options[:message_digest])
74
- else
75
- message_digest = R509::MessageDigest.new(@config.message_digest)
76
- end
77
-
78
- profile = @config.profile(options[:profile_name])
79
-
80
- validated_subject = validate_subject(subject,profile)
81
-
82
- cert = build_cert(
83
- :subject => validated_subject.name,
84
- :issuer => @config.ca_cert.subject,
85
- :not_before => options[:not_before],
86
- :not_after => options[:not_after],
87
- :public_key => signable_object.public_key,
88
- :serial => options[:serial]
89
- )
90
-
91
- basic_constraints = profile.basic_constraints
92
- key_usage = profile.key_usage
93
- extended_key_usage = profile.extended_key_usage
94
- certificate_policies = profile.certificate_policies
95
-
96
- build_extensions(
97
- :subject_certificate => cert,
98
- :issuer_certificate => @config.ca_cert.cert,
99
- :basic_constraints => basic_constraints,
100
- :key_usage => key_usage,
101
- :extended_key_usage => extended_key_usage,
102
- :certificate_policies => certificate_policies,
103
- :san_names => san_names
104
- )
105
-
106
-
107
- #@config.ca_cert.key.key ... ugly. ca_cert returns R509::Cert
108
- # #key returns R509::PrivateKey and #key on that returns OpenSSL object we need
109
- cert.sign( @config.ca_cert.key.key, message_digest.digest )
110
- R509::Cert.new(:cert => cert)
111
- end
112
-
113
- # Self-signs a CSR
114
- # @option options :csr [R509::Csr]
115
- # @option options :message_digest [String] the message digest to use for this certificate (defaults to sha1)
116
- # @option options :serial [String] the serial number you want to issue the certificate with (defaults to random)
117
- # @option options :not_before [Time] the notBefore for the certificate (defaults to now)
118
- # @option options :not_after [Time] the notAfter for the certificate (defaults to 1 year)
119
- # @option options :san_names [Array] Optional array of subject alternative names
120
- # @return [R509::Cert] the signed cert object
121
- def selfsign(options)
122
- if not options.kind_of?(Hash)
123
- raise ArgumentError, "You must pass a hash of options consisting of at minimum :csr"
124
- end
125
- csr = options[:csr]
126
- if csr.key.nil?
127
- raise ArgumentError, 'CSR must also have a private key to self sign'
128
- end
129
- cert = build_cert(
130
- :subject => csr.subject.name,
131
- :issuer => csr.subject.name,
132
- :not_before => options[:not_before],
133
- :not_after => options[:not_after],
134
- :public_key => csr.public_key,
135
- :serial => options[:serial]
136
- )
137
-
138
- if options.has_key?(:san_names)
139
- san_names = options[:san_names]
140
- else
141
- san_names = csr.san_names
142
- end
143
-
144
- build_extensions(
145
- :subject_certificate => cert,
146
- :issuer_certificate => cert,
147
- :basic_constraints => "CA:TRUE",
148
- :san_names => san_names
149
- )
150
-
151
-
152
- if options.has_key?(:message_digest)
153
- message_digest = R509::MessageDigest.new(options[:message_digest])
154
- else
155
- message_digest = R509::MessageDigest.new('sha1')
156
- end
157
-
158
- # Csr#key returns R509::PrivateKey and #key on that returns OpenSSL object we need
159
- cert.sign( csr.key.key, message_digest.digest )
160
- R509::Cert.new(:cert => cert)
161
- end
162
-
163
- private
164
-
165
- def process_san_names(domains)
166
- domains.map { |domain| 'DNS: '+domain }.join(",")
167
- end
168
-
169
- def build_conf(section,data)
170
- conf = ["[#{section}]"]
171
- conf.concat data
172
- conf.join "\n"
173
- end
174
-
175
- def validate_subject(subject,profile)
176
- if profile.subject_item_policy.nil? then
177
- subject
178
- else
179
- profile.subject_item_policy.validate_subject(subject)
180
- end
181
- end
182
-
183
- def build_cert(options)
184
-
185
- cert = OpenSSL::X509::Certificate.new
186
-
187
- cert.subject = options[:subject]
188
- cert.issuer = options[:issuer]
189
- cert.not_before = calculate_not_before(options[:not_before])
190
- cert.not_after = calculate_not_after(options[:not_after],cert.not_before)
191
- cert.public_key = options[:public_key]
192
- cert.serial = create_serial(options[:serial])
193
- cert.version = 2 #2 means v3
194
- cert
195
- end
196
-
197
- def create_serial(serial)
198
- if not serial.nil?
199
- serial = OpenSSL::BN.new(serial.to_s)
200
- else
201
- # generate random serial in accordance with best practices
202
- # guidelines state 20-bits of entropy, but we can cram more in
203
- # per rfc5280 conforming CAs can make the serial field up to 20 octets
204
- # to prevent even the incredibly remote possibility of collision we'll
205
- # concatenate current time (to the microsecond) with a random num
206
- rand = OpenSSL::BN.rand(96,0) # 96 bits is 12 bytes (octets).
207
- serial = OpenSSL::BN.new((Time.now.to_f*1000000).to_i.to_s + rand.to_s)
208
- # since second param is 0 the most significant bit must always be 1
209
- # this theoretically gives us 95 bits of entropy + microtime, which
210
- # adds a non-zero quantity of entropy. depending upon how predictable
211
- # your issuance is, this could range from a reasonably large quantity
212
- # of entropy to very little
213
- end
214
- serial
215
- end
216
-
217
- def build_extensions(options)
218
- ef = OpenSSL::X509::ExtensionFactory.new
219
-
220
- ef.subject_certificate = options[:subject_certificate]
221
-
222
- ef.issuer_certificate = options[:issuer_certificate]
223
-
224
- ext = []
225
- if not options[:basic_constraints].nil?
226
- ext << ef.create_extension("basicConstraints", options[:basic_constraints], true)
227
- end
228
- if options.has_key?(:key_usage) and not options[:key_usage].empty?
229
- ext << ef.create_extension("keyUsage", options[:key_usage].join(","))
230
- end
231
- if options.has_key?(:extended_key_usage) and not options[:extended_key_usage].empty?
232
- ext << ef.create_extension("extendedKeyUsage", options[:extended_key_usage].join(","))
233
- end
234
- ext << ef.create_extension("subjectKeyIdentifier", "hash")
235
-
236
- #attach the key identifier if it's not a self-sign
237
- if not ef.subject_certificate == ef.issuer_certificate and R509::Cert.new(:cert=>options[:issuer_certificate]).extensions['subjectKeyIdentifier']
238
- ext << ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
239
- end
240
-
241
- if not options[:certificate_policies].nil? and not options[:certificate_policies].empty?
242
- conf = []
243
- conf_names = []
244
- i = 0
245
- options[:certificate_policies].each do |policy|
246
- conf << build_conf("certPolicies#{i}",policy)
247
- conf_names << "@certPolicies#{i}"
248
- i+=1
249
- end
250
- ef.config = OpenSSL::Config.parse(conf.join("\n"))
251
- ext << ef.create_extension("certificatePolicies", conf_names.join(","))
252
- end
253
- #ef.config = OpenSSL::Config.parse(<<-_end_of_cnf_)
254
- #[certPolicies]
255
- #CPS.1 = http://www.example.com/cps
256
- #_end_of_cnf_
257
-
258
- if options.has_key?(:san_names) and not options[:san_names].empty?
259
- ext << ef.create_extension("subjectAltName", process_san_names(options[:san_names]))
260
- end
261
-
262
- if not @config.nil? and not @config.cdp_location.nil?
263
- ext << ef.create_extension("crlDistributionPoints", @config.cdp_location)
264
- end
265
-
266
- if not @config.nil? and not @config.ocsp_location.nil? then
267
- ext << ef.create_extension("authorityInfoAccess",
268
- "OCSP;" << @config.ocsp_location)
269
- end
270
- options[:subject_certificate].extensions = ext
271
- nil
272
- end
273
-
274
- def calculate_not_before(not_before)
275
- if not_before.nil?
276
- #not_before will be set to 6 hours before now to prevent issues with bad system clocks (clients don't sync)
277
- not_before = Time.now - 6 * 60 * 60
278
- end
279
- not_before
280
- end
281
-
282
- def calculate_not_after(not_after,not_before)
283
- if not_after.nil?
284
- not_after = not_before + 365 * 24 * 60 * 60
285
- end
286
- not_after
287
- end
288
-
289
- end
290
- end
@@ -1,49 +0,0 @@
1
- require 'openssl'
2
-
3
- module R509
4
- #MessageDigest allows you to specify MDs in a more friendly fashion
5
- class MessageDigest
6
- attr_reader :name, :digest
7
-
8
- # @param [String,OpenSSL::Digest] arg
9
- def initialize(arg)
10
- if arg.kind_of?(String)
11
- @name = arg.downcase
12
- @digest = translate_name_to_digest
13
- else
14
- @digest = arg
15
- @name = translate_digest_to_name
16
- end
17
- end
18
-
19
- private
20
-
21
- # @return [OpenSSL::Digest]
22
- def translate_name_to_digest
23
- case @name
24
- when 'sha1' then OpenSSL::Digest::SHA1.new
25
- when 'sha256' then OpenSSL::Digest::SHA256.new
26
- when 'sha512' then OpenSSL::Digest::SHA512.new
27
- when 'md5' then OpenSSL::Digest::MD5.new
28
- when 'dss1' then OpenSSL::Digest::DSS1.new
29
- else
30
- @name = "sha1"
31
- OpenSSL::Digest::SHA1.new
32
- end
33
- end
34
-
35
- # @return [String]
36
- def translate_digest_to_name
37
- case @digest
38
- when OpenSSL::Digest::SHA1 then 'sha1'
39
- when OpenSSL::Digest::SHA256 then 'sha256'
40
- when OpenSSL::Digest::SHA512 then 'sha512'
41
- when OpenSSL::Digest::MD5 then 'md5'
42
- when OpenSSL::Digest::DSS1 then 'dss1'
43
- else
44
- raise ArgumentError, "Unknown digest"
45
- end
46
- end
47
- end
48
- end
49
-
@@ -1,32 +0,0 @@
1
- require 'openssl'
2
-
3
- module R509
4
- # Helps map raw OIDs to friendlier short names
5
- class OidMapper
6
- # Register an OID so we have a friendly short name
7
- # @param [String] oid A string representation of the OID you want to map (e.g. "1.6.2.3.55")
8
- # @param [String] short_name The short name (e.g. CN, O, OU, emailAddress)
9
- # @param [String] long_name Optional long name. Defaults to the same as short_name
10
- # @return [Boolean] success/failure
11
- def self.register(oid,short_name,long_name=nil)
12
- if long_name.nil?
13
- long_name = short_name
14
- end
15
- OpenSSL::ASN1::ObjectId.register(oid, short_name, long_name)
16
- end
17
-
18
- # Register a batch of OIDs so we have friendly short names
19
- # @param [Array] oids An array of hashes
20
- # @example
21
- # R509::OidMapper.batch_register([
22
- # {:oid => "1.2.3.4.5", :short_name => "sName", :long_name => "lName"},
23
- # {:oid => "1.2.3.4.6", :short_name => "oName"}
24
- # ]
25
- def self.batch_register(oids)
26
- oids.each do |oid_hash|
27
- self.register(oid_hash[:oid],oid_hash[:short_name],oid_hash[:long_name])
28
- end
29
- nil
30
- end
31
- end
32
- end
@@ -1,185 +0,0 @@
1
- require 'openssl'
2
- require 'r509/io_helpers'
3
- require 'r509/exceptions'
4
-
5
- module R509
6
- #private key management
7
- class PrivateKey
8
- include R509::IOHelpers
9
-
10
- # @option opts [Symbol] :type :rsa/:dsa
11
- # @option opts [Integer] :bit_strength
12
- # @option opts [String] :password
13
- # @option opts [String,OpenSSL::PKey::RSA,OpenSSL::PKey::DSA] :key
14
- # @option opts [OpenSSL::Engine] :engine
15
- # @option opts [string] :key_name (used with engine)
16
- def initialize(opts)
17
- if not opts.kind_of?(Hash)
18
- raise ArgumentError, 'Must provide a hash of options'
19
- end
20
-
21
- if opts.has_key?(:engine) and opts.has_key?(:key)
22
- raise ArgumentError, 'You can\'t pass both :key and :engine'
23
- elsif opts.has_key?(:key_name) and not opts.has_key?(:engine)
24
- raise ArgumentError, 'When providing a :key_name you MUST provide an :engine'
25
- elsif opts.has_key?(:engine) and not opts.has_key?(:key_name)
26
- raise ArgumentError, 'When providing an :engine you MUST provide a :key_name'
27
- elsif opts.has_key?(:engine) and opts.has_key?(:key_name)
28
- if not opts[:engine].kind_of?(OpenSSL::Engine)
29
- raise ArgumentError, 'When providing an engine, it must be of type OpenSSL::Engine'
30
- end
31
- @engine = opts[:engine]
32
- @key_name = opts[:key_name]
33
- end
34
-
35
- if opts.has_key?(:key)
36
- password = opts[:password] || nil
37
- #OpenSSL::PKey.read solves this begin/rescue garbage but is only
38
- #available to Ruby 1.9.3+
39
- begin
40
- @key = OpenSSL::PKey::RSA.new(opts[:key],password)
41
- rescue OpenSSL::PKey::RSAError
42
- begin
43
- @key = OpenSSL::PKey::DSA.new(opts[:key],password)
44
- rescue
45
- raise R509::R509Error, "Failed to load private key. Invalid key or incorrect password."
46
- end
47
- end
48
- else
49
- bit_strength = opts[:bit_strength] || 2048
50
- type = opts[:type] || :rsa
51
- case type
52
- when :rsa
53
- @key = OpenSSL::PKey::RSA.new(bit_strength)
54
- when :dsa
55
- @key = OpenSSL::PKey::DSA.new(bit_strength)
56
- else
57
- raise ArgumentError, 'Must provide :rsa or :dsa as type when key or engine is nil'
58
- end
59
- end
60
- end
61
-
62
- # Helper method to quickly load a private key from the filesystem
63
- #
64
- # @param [String] filename Path to file you want to load
65
- # @return [R509::PrivateKey] PrivateKey object
66
- def self.load_from_file( filename, password = nil )
67
- return R509::PrivateKey.new(:key => IOHelpers.read_data(filename), :password => password )
68
- end
69
-
70
-
71
- # @return [Integer]
72
- def bit_strength
73
- if self.rsa?
74
- return self.public_key.n.num_bits
75
- elsif self.dsa?
76
- return self.public_key.p.num_bits
77
- end
78
- end
79
-
80
- # @return [OpenSSL::PKey::RSA,OpenSSL::PKey::DSA,OpenSSL::Engine pkey] this method may return the PKey object itself or a handle to the private key in the HSM (which will not show the private key, just public)
81
- def key
82
- if in_hardware?
83
- @engine.load_private_key(@key_name)
84
- else
85
- @key
86
- end
87
- end
88
-
89
- # @return [Boolean] whether the key is resident in hardware or not
90
- def in_hardware?
91
- if not @engine.nil?
92
- true
93
- else
94
- false
95
- end
96
- end
97
-
98
- # @return [OpenSSL::PKey::RSA,OpenSSL::PKey::DSA] public key
99
- def public_key
100
- self.key.public_key
101
- end
102
-
103
- alias :to_s :public_key
104
-
105
- # Converts the key into the PEM format
106
- #
107
- # @return [String] the key converted into PEM format.
108
- def to_pem
109
- if in_hardware?
110
- raise R509::R509Error, "This method cannot be called when using keys in hardware"
111
- end
112
- self.key.to_pem
113
- end
114
-
115
- # Converts the key into encrypted PEM format
116
- #
117
- # @param [String,OpenSSL::Cipher] cipher to use for encryption
118
- # full list of available ciphers can be obtained with OpenSSL::Cipher.ciphers
119
- # (common ones are des3, aes256, aes128)
120
- # @param [String] password password
121
- # @return [String] the key converted into encrypted PEM format.
122
- def to_encrypted_pem(cipher,password)
123
- if in_hardware?
124
- raise R509::R509Error, "This method cannot be called when using keys in hardware"
125
- end
126
- cipher = OpenSSL::Cipher::Cipher.new(cipher)
127
- self.key.to_pem(cipher,password)
128
- end
129
-
130
-
131
- # Converts the key into the DER format
132
- #
133
- # @return [String] the key converted into DER format.
134
- def to_der
135
- if in_hardware?
136
- raise R509::R509Error, "This method cannot be called when using keys in hardware"
137
- end
138
- self.key.to_der
139
- end
140
-
141
- # Writes the key into the PEM format
142
- #
143
- # @param [String, #write] filename_or_io Either a string of the path for
144
- # the file that you'd like to write, or an IO-like object.
145
- def write_pem(filename_or_io)
146
- write_data(filename_or_io, self.to_pem)
147
- end
148
-
149
-
150
- # Writes the key into encrypted PEM format with specified cipher
151
- #
152
- # @param [String, #write] filename_or_io Either a string of the path for
153
- # the file that you'd like to write, or an IO-like object.
154
- # @param [String,OpenSSL::Cipher] cipher to use for encryption
155
- # full list of available ciphers can be obtained with OpenSSL::Cipher.ciphers
156
- # (common ones are des3, aes256, aes128)
157
- # @param [String] password password
158
- def write_encrypted_pem(filename_or_io,cipher,password)
159
- write_data(filename_or_io, to_encrypted_pem(cipher,password))
160
- end
161
-
162
- # Writes the key into the DER format
163
- #
164
- # @param [String, #write] filename_or_io Either a string of the path for
165
- # the file that you'd like to write, or an IO-like object.
166
- def write_der(filename_or_io)
167
- write_data(filename_or_io, self.to_der)
168
- end
169
-
170
-
171
- # Returns whether the public key is RSA
172
- #
173
- # @return [Boolean] true if the public key is RSA, false otherwise
174
- def rsa?
175
- self.key.kind_of?(OpenSSL::PKey::RSA)
176
- end
177
-
178
- # Returns whether the public key is DSA
179
- #
180
- # @return [Boolean] true if the public key is DSA, false otherwise
181
- def dsa?
182
- self.key.kind_of?(OpenSSL::PKey::DSA)
183
- end
184
- end
185
- end