trocla-ruby2 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.document +4 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +10 -0
  5. data/CHANGELOG.md +71 -0
  6. data/Gemfile +51 -0
  7. data/LICENSE.txt +15 -0
  8. data/README.md +351 -0
  9. data/Rakefile +53 -0
  10. data/bin/trocla +148 -0
  11. data/ext/redhat/rubygem-trocla.spec +120 -0
  12. data/lib/VERSION +4 -0
  13. data/lib/trocla.rb +162 -0
  14. data/lib/trocla/default_config.yaml +47 -0
  15. data/lib/trocla/encryptions.rb +54 -0
  16. data/lib/trocla/encryptions/none.rb +10 -0
  17. data/lib/trocla/encryptions/ssl.rb +51 -0
  18. data/lib/trocla/formats.rb +54 -0
  19. data/lib/trocla/formats/bcrypt.rb +7 -0
  20. data/lib/trocla/formats/md5crypt.rb +6 -0
  21. data/lib/trocla/formats/mysql.rb +6 -0
  22. data/lib/trocla/formats/pgsql.rb +7 -0
  23. data/lib/trocla/formats/plain.rb +7 -0
  24. data/lib/trocla/formats/sha1.rb +7 -0
  25. data/lib/trocla/formats/sha256crypt.rb +6 -0
  26. data/lib/trocla/formats/sha512crypt.rb +6 -0
  27. data/lib/trocla/formats/ssha.rb +9 -0
  28. data/lib/trocla/formats/sshkey.rb +46 -0
  29. data/lib/trocla/formats/x509.rb +197 -0
  30. data/lib/trocla/store.rb +80 -0
  31. data/lib/trocla/stores.rb +39 -0
  32. data/lib/trocla/stores/memory.rb +56 -0
  33. data/lib/trocla/stores/moneta.rb +58 -0
  34. data/lib/trocla/util.rb +71 -0
  35. data/lib/trocla/version.rb +22 -0
  36. data/spec/data/.keep +0 -0
  37. data/spec/spec_helper.rb +290 -0
  38. data/spec/trocla/encryptions/none_spec.rb +22 -0
  39. data/spec/trocla/encryptions/ssl_spec.rb +26 -0
  40. data/spec/trocla/formats/x509_spec.rb +375 -0
  41. data/spec/trocla/store/memory_spec.rb +6 -0
  42. data/spec/trocla/store/moneta_spec.rb +6 -0
  43. data/spec/trocla/util_spec.rb +54 -0
  44. data/spec/trocla_spec.rb +248 -0
  45. data/trocla-ruby2.gemspec +104 -0
  46. metadata +202 -0
@@ -0,0 +1,22 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Trocla::Encryptions::None" do
4
+
5
+ before(:each) do
6
+ expect_any_instance_of(Trocla).to receive(:read_config).and_return(test_config_persistent)
7
+ @trocla = Trocla.new
8
+ end
9
+
10
+ after(:each) do
11
+ remove_yaml_store
12
+ end
13
+
14
+ describe "none" do
15
+ include_examples 'encryption_basics'
16
+
17
+ it "stores plaintext passwords" do
18
+ @trocla.set_password('noplain', 'plain', 'plaintext_password')
19
+ expect(File.readlines(trocla_yaml_file).grep(/plaintext_password/)).to eq([" plain: plaintext_password\n"])
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Trocla::Encryptions::Ssl" do
4
+
5
+ before(:all) do
6
+ generate_ssl_keys
7
+ end
8
+
9
+ after(:all) do
10
+ remove_ssl_keys
11
+ end
12
+
13
+ before(:each) do
14
+ expect_any_instance_of(Trocla).to receive(:read_config).and_return(ssl_test_config)
15
+ @trocla = Trocla.new
16
+ end
17
+
18
+ after(:each) do
19
+ remove_yaml_store
20
+ end
21
+
22
+ describe "encrypt" do
23
+ include_examples 'encryption_basics'
24
+ include_examples 'verify_encryption'
25
+ end
26
+ end
@@ -0,0 +1,375 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'date'
3
+
4
+ describe "Trocla::Format::X509" do
5
+
6
+ before(:each) do
7
+ expect_any_instance_of(Trocla).to receive(:read_config).and_return(test_config)
8
+ @trocla = Trocla.new
9
+ end
10
+
11
+ let(:ca_options) do
12
+ {
13
+ 'CN' => 'This is my self-signed certificate which doubles as CA',
14
+ 'become_ca' => true,
15
+ }
16
+ end
17
+ let(:cert_options) do
18
+ {
19
+ 'ca' => 'my_shiny_selfsigned_ca',
20
+ 'subject' => '/C=ZZ/O=Trocla Inc./CN=test/emailAddress=example@example.com',
21
+ }
22
+ end
23
+
24
+ def verify(ca,cert)
25
+ store = OpenSSL::X509::Store.new
26
+ store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
27
+ Array(ca).each do |c|
28
+ store.add_cert(c)
29
+ end
30
+ store.verify(cert)
31
+ end
32
+
33
+ describe "x509 selfsigned" do
34
+ it "is able to create self signed cert without being a ca by default" do
35
+ cert_str = @trocla.password('my_shiny_selfsigned_ca', 'x509', {
36
+ 'CN' => 'This is my self-signed certificate',
37
+ 'become_ca' => false,
38
+ })
39
+ cert = OpenSSL::X509::Certificate.new(cert_str)
40
+ # selfsigned?
41
+ expect(cert.issuer.to_s).to eq(cert.subject.to_s)
42
+ # default size
43
+ # https://stackoverflow.com/questions/13747212/determine-key-size-from-public-key-pem-format
44
+ expect(cert.public_key.n.num_bytes * 8).to eq(4096)
45
+ expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
46
+ # it's a self signed cert and NOT a CA
47
+ expect(verify(cert,cert)).to be false
48
+
49
+ v = cert.extensions.find{|e| e.oid == 'basicConstraints' }.value
50
+ expect(v).to eq('CA:FALSE')
51
+ # we want to include only CNs that look like a DNS name
52
+ expect(cert.extensions.find{|e| e.oid == 'subjectAltName' }).to be_nil
53
+ ku = cert.extensions.find{|e| e.oid == 'keyUsage' }.value
54
+ expect(ku).not_to match(/Certificate Sign/)
55
+ expect(ku).not_to match(/CRL Sign/)
56
+ end
57
+
58
+ it "is able to create a self signed cert that is a CA" do
59
+ ca_str = @trocla.password('my_shiny_selfsigned_ca', 'x509', ca_options)
60
+ ca = OpenSSL::X509::Certificate.new(ca_str)
61
+ # selfsigned?
62
+ expect(ca.issuer.to_s).to eq(ca.subject.to_s)
63
+ expect((Date.parse(ca.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
64
+ expect(verify(ca,ca)).to be true
65
+
66
+ v = ca.extensions.find{|e| e.oid == 'basicConstraints' }.value
67
+ expect(v).to eq('CA:TRUE')
68
+ ku = ca.extensions.find{|e| e.oid == 'keyUsage' }.value
69
+ expect(ku).to match(/Certificate Sign/)
70
+ expect(ku).to match(/CRL Sign/)
71
+ end
72
+ it "is able to create a self signed cert without any keyUsage restrictions" do
73
+ cert_str = @trocla.password('my_shiny_selfsigned_without restrictions', 'x509', {
74
+ 'CN' => 'This is my self-signed certificate',
75
+ 'key_usages' => [],
76
+ })
77
+ cert = OpenSSL::X509::Certificate.new(cert_str)
78
+ # selfsigned?
79
+ expect(cert.issuer.to_s).to eq(cert.subject.to_s)
80
+ # default size
81
+ # https://stackoverflow.com/questions/13747212/determine-key-size-from-public-key-pem-format
82
+ expect(cert.public_key.n.num_bytes * 8).to eq(4096)
83
+ expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
84
+ # it's a self signed cert and NOT a CA, but has no keyUsage limitation
85
+ expect(verify(cert,cert)).to be true
86
+
87
+ v = cert.extensions.find{|e| e.oid == 'basicConstraints' }.value
88
+ expect(v).to_not eq('CA:TRUE')
89
+ expect(cert.extensions.find{|e| e.oid == 'keyUsage' }).to be_nil
90
+ end
91
+
92
+ it "is able to create a self signed cert with custom keyUsage restrictions" do
93
+ cert_str = @trocla.password('my_shiny_selfsigned_without restrictions', 'x509', {
94
+ 'CN' => 'This is my self-signed certificate',
95
+ 'key_usages' => [ 'cRLSign', ],
96
+ })
97
+ cert = OpenSSL::X509::Certificate.new(cert_str)
98
+ # selfsigned?
99
+ expect(cert.issuer.to_s).to eq(cert.subject.to_s)
100
+ # default size
101
+ # https://stackoverflow.com/questions/13747212/determine-key-size-from-public-key-pem-format
102
+ expect(cert.public_key.n.num_bytes * 8).to eq(4096)
103
+ expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
104
+ # it's a self signed cert and NOT a CA, as it's key is restricted to only CRL Sign
105
+ expect(verify(cert,cert)).to be false
106
+
107
+ v = cert.extensions.find{|e| e.oid == 'basicConstraints' }.value
108
+ expect(v).to_not eq('CA:TRUE')
109
+ ku = cert.extensions.find{|e| e.oid == 'keyUsage' }.value
110
+ expect(ku).to match(/CRL Sign/)
111
+ expect(ku).not_to match(/Certificate Sign/)
112
+ end
113
+
114
+ end
115
+ describe "x509 signed by a ca" do
116
+ before(:each) do
117
+ ca_str = @trocla.password('my_shiny_selfsigned_ca', 'x509', ca_options)
118
+ @ca = OpenSSL::X509::Certificate.new(ca_str)
119
+ end
120
+ it 'is able to get a cert signed by the ca' do
121
+ cert_str = @trocla.password('mycert', 'x509', cert_options)
122
+ cert = OpenSSL::X509::Certificate.new(cert_str)
123
+ expect(cert.issuer.to_s).to eq(@ca.subject.to_s)
124
+ expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
125
+ expect(verify(@ca,cert)).to be true
126
+
127
+ v = cert.extensions.find{|e| e.oid == 'basicConstraints' }.value
128
+ expect(v).to eq('CA:FALSE')
129
+ ku = cert.extensions.find{|e| e.oid == 'keyUsage' }.value
130
+ expect(ku).not_to match(/Certificate Sign/)
131
+ expect(ku).not_to match(/CRL Sign/)
132
+ end
133
+
134
+ it 'supports fetching only the key' do
135
+ cert_str = @trocla.password('mycert', 'x509', cert_options.merge('render' => {'keyonly' => true }))
136
+ expect(cert_str).not_to match(/-----BEGIN CERTIFICATE-----/)
137
+ expect(cert_str).to match(/-----BEGIN RSA PRIVATE KEY-----/)
138
+ end
139
+ it 'supports fetching only the cert' do
140
+ cert_str = @trocla.password('mycert', 'x509', cert_options.merge('render' => {'certonly' => true }))
141
+ expect(cert_str).to match(/-----BEGIN CERTIFICATE-----/)
142
+ expect(cert_str).not_to match(/-----BEGIN RSA PRIVATE KEY-----/)
143
+ end
144
+ it 'supports fetching only the cert even a second time' do
145
+ cert_str = @trocla.password('mycert', 'x509', cert_options.merge('render' => {'certonly' => true }))
146
+ expect(cert_str).to match(/-----BEGIN CERTIFICATE-----/)
147
+ expect(cert_str).not_to match(/-----BEGIN RSA PRIVATE KEY-----/)
148
+ cert_str = @trocla.password('mycert', 'x509', cert_options.merge('render' => {'certonly' => true }))
149
+ expect(cert_str).to match(/-----BEGIN CERTIFICATE-----/)
150
+ expect(cert_str).not_to match(/-----BEGIN RSA PRIVATE KEY-----/)
151
+ end
152
+
153
+ it 'does not simply increment the serial' do
154
+ cert_str = @trocla.password('mycert', 'x509', cert_options)
155
+ cert1 = OpenSSL::X509::Certificate.new(cert_str)
156
+ cert_str = @trocla.password('mycert2', 'x509', cert_options)
157
+ cert2 = OpenSSL::X509::Certificate.new(cert_str)
158
+
159
+ expect(cert1.serial.to_i).not_to eq(1)
160
+ expect(cert2.serial.to_i).not_to eq(2)
161
+ expect((cert2.serial - cert1.serial).to_i).not_to eq(1)
162
+ end
163
+
164
+ it 'is able to get a cert signed by the ca that is again a ca' do
165
+ cert_str = @trocla.password('mycert', 'x509', cert_options.merge({
166
+ 'become_ca' => true,
167
+ }))
168
+ cert = OpenSSL::X509::Certificate.new(cert_str)
169
+ expect(cert.issuer.to_s).to eq(@ca.subject.to_s)
170
+ expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
171
+ expect(verify(@ca,cert)).to be true
172
+
173
+ expect(cert.extensions.find{|e| e.oid == 'basicConstraints' }.value).to eq('CA:TRUE')
174
+ ku = cert.extensions.find{|e| e.oid == 'keyUsage' }.value
175
+ expect(ku).to match(/Certificate Sign/)
176
+ expect(ku).to match(/CRL Sign/)
177
+ end
178
+
179
+ it 'supports simple name constraints for CAs' do
180
+ ca2_str = @trocla.password('mycert_with_nc', 'x509', cert_options.merge({
181
+ 'name_constraints' => ['example.com','bla.example.net'],
182
+ 'become_ca' => true,
183
+ }))
184
+ ca2 = OpenSSL::X509::Certificate.new(ca2_str)
185
+ expect(ca2.issuer.to_s).to eq(@ca.subject.to_s)
186
+ expect((Date.parse(ca2.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
187
+ pending_for(:engine => 'jruby',:reason => 'NameConstraints verification seem to be broken in jRuby: https://github.com/jruby/jruby/issues/3502') do
188
+ expect(verify(@ca,ca2)).to be true
189
+ end
190
+
191
+ expect(ca2.extensions.find{|e| e.oid == 'basicConstraints' }.value).to eq('CA:TRUE')
192
+ ku = ca2.extensions.find{|e| e.oid == 'keyUsage' }.value
193
+ expect(ku).to match(/Certificate Sign/)
194
+ expect(ku).to match(/CRL Sign/)
195
+ nc = ca2.extensions.find{|e| e.oid == 'nameConstraints' }.value
196
+ pending_for(:engine => 'jruby',:reason => 'NameConstraints verification seem to be broken in jRuby: https://github.com/jruby/jruby/issues/3502') do
197
+ expect(nc).to match(/Permitted:\n DNS:example.com\n DNS:bla.example.net/)
198
+ end
199
+ valid_cert_str = @trocla.password('myvalidexamplecert','x509', {
200
+ 'subject' => '/C=ZZ/O=Trocla Inc./CN=foo.example.com/emailAddress=example@example.com',
201
+ 'ca' => 'mycert_with_nc'
202
+ })
203
+ valid_cert = OpenSSL::X509::Certificate.new(valid_cert_str)
204
+ expect(valid_cert.issuer.to_s).to eq(ca2.subject.to_s)
205
+ expect(verify([@ca,ca2],valid_cert)).to be true
206
+ expect((Date.parse(valid_cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
207
+
208
+ false_cert_str = @trocla.password('myfalseexamplecert','x509', {
209
+ 'subject' => '/C=ZZ/O=Trocla Inc./CN=foo.example.net/emailAddress=example@example.com',
210
+ 'ca' => 'mycert_with_nc'
211
+ })
212
+
213
+ false_cert = OpenSSL::X509::Certificate.new(false_cert_str)
214
+ expect(false_cert.issuer.to_s).to eq(ca2.subject.to_s)
215
+ expect(verify([@ca,ca2],false_cert)).to be false
216
+ expect((Date.parse(false_cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
217
+ end
218
+
219
+ it 'supports simple name constraints for CAs with leading dots' do
220
+ ca2_str = @trocla.password('mycert_with_nc', 'x509', cert_options.merge({
221
+ 'name_constraints' => ['.example.com','.bla.example.net'],
222
+ 'become_ca' => true,
223
+ }))
224
+ ca2 = OpenSSL::X509::Certificate.new(ca2_str)
225
+ expect(ca2.issuer.to_s).to eq(@ca.subject.to_s)
226
+ expect((Date.parse(ca2.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
227
+ pending_for(:engine => 'jruby',:reason => 'NameConstraints verification seem to be broken in jRuby: https://github.com/jruby/jruby/issues/3502') do
228
+ expect(verify(@ca,ca2)).to be true
229
+ end
230
+
231
+ expect(ca2.extensions.find{|e| e.oid == 'basicConstraints' }.value).to eq('CA:TRUE')
232
+ ku = ca2.extensions.find{|e| e.oid == 'keyUsage' }.value
233
+ expect(ku).to match(/Certificate Sign/)
234
+ expect(ku).to match(/CRL Sign/)
235
+ nc = ca2.extensions.find{|e| e.oid == 'nameConstraints' }.value
236
+ expect(nc).to match(/Permitted:\n DNS:.example.com\n DNS:.bla.example.net/)
237
+ valid_cert_str = @trocla.password('myvalidexamplecert','x509', {
238
+ 'subject' => '/C=ZZ/O=Trocla Inc./CN=foo.example.com/emailAddress=example@example.com',
239
+ 'ca' => 'mycert_with_nc'
240
+ })
241
+ valid_cert = OpenSSL::X509::Certificate.new(valid_cert_str)
242
+ expect(valid_cert.issuer.to_s).to eq(ca2.subject.to_s)
243
+ expect((Date.parse(valid_cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
244
+ # workaround broken openssl
245
+ if Gem::Version.new(%x{openssl version}.split(' ')[1]) < Gem::Version.new('1.0.2')
246
+ skip_for(:engine => 'ruby',:reason => 'NameConstraints verification is broken on older openssl versions https://rt.openssl.org/Ticket/Display.html?id=3562') do
247
+ expect(verify([@ca,ca2],valid_cert)).to be true
248
+ end
249
+ else
250
+ expect(verify([@ca,ca2],valid_cert)).to be true
251
+ end
252
+
253
+ false_cert_str = @trocla.password('myfalseexamplecert','x509', {
254
+ 'subject' => '/C=ZZ/O=Trocla Inc./CN=foo.example.net/emailAddress=example@example.com',
255
+ 'ca' => 'mycert_with_nc'
256
+ })
257
+ false_cert = OpenSSL::X509::Certificate.new(false_cert_str)
258
+ expect(false_cert.issuer.to_s).to eq(ca2.subject.to_s)
259
+ expect((Date.parse(false_cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
260
+ expect(verify([@ca,ca2],false_cert)).to be false
261
+ end
262
+
263
+ it 'is able to get a cert signed by the ca that is again a ca that is able to sign certs' do
264
+ ca2_str = @trocla.password('mycert_and_ca', 'x509', cert_options.merge({
265
+ 'become_ca' => true,
266
+ }))
267
+ ca2 = OpenSSL::X509::Certificate.new(ca2_str)
268
+ expect(ca2.issuer.to_s).to eq(@ca.subject.to_s)
269
+ expect((Date.parse(ca2.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
270
+ expect(verify(@ca,ca2)).to be true
271
+
272
+ cert2_str = @trocla.password('mycert', 'x509', {
273
+ 'ca' => 'mycert_and_ca',
274
+ 'subject' => '/C=ZZ/O=Trocla Inc./CN=test2/emailAddress=example@example.com',
275
+ 'become_ca' => true,
276
+ })
277
+ cert2 = OpenSSL::X509::Certificate.new(cert2_str)
278
+ expect(cert2.issuer.to_s).to eq(ca2.subject.to_s)
279
+ expect((Date.parse(cert2.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
280
+ skip_for(:engine => 'jruby',:reason => 'Chained CA validation seems to be broken on jruby atm.') do
281
+ expect(verify([@ca,ca2],cert2)).to be true
282
+ end
283
+ end
284
+
285
+ it 'respects all options' do
286
+ co = cert_options.merge({
287
+ 'hash' => 'sha1',
288
+ 'keysize' => 2048,
289
+ 'days' => 3650,
290
+ 'subject' => nil,
291
+ 'C' => 'AA',
292
+ 'ST' => 'Earth',
293
+ 'L' => 'Here',
294
+ 'O' => 'SSLTrocla',
295
+ 'OU' => 'root',
296
+ 'CN' => 'www.test',
297
+ 'emailAddress' => 'test@example.com',
298
+ 'altnames' => [ 'test', 'test1', 'test2', 'test3' ],
299
+ })
300
+ cert_str = @trocla.password('mycert', 'x509', co)
301
+ cert = OpenSSL::X509::Certificate.new(cert_str)
302
+ expect(cert.issuer.to_s).to eq(@ca.subject.to_s)
303
+ ['C','ST','L','O','OU','CN'].each do |field|
304
+ expect(cert.subject.to_s).to match(/#{field}=#{co[field]}/)
305
+ end
306
+ expect(cert.subject.to_s).to match(/(Email|emailAddress)=#{co['emailAddress']}/)
307
+ hash_match = (defined?(RUBY_ENGINE) &&RUBY_ENGINE == 'jruby') ? 'RSA-SHA1' : 'sha1WithRSAEncryption'
308
+ expect(cert.signature_algorithm).to eq(hash_match)
309
+ expect(cert.not_before).to be < Time.now
310
+ expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(3650)
311
+ # https://stackoverflow.com/questions/13747212/determine-key-size-from-public-key-pem-format
312
+ expect(cert.public_key.n.num_bytes * 8).to eq(2048)
313
+ expect(verify(@ca,cert)).to be true
314
+ skip_for(:engine => 'jruby',:reason => 'subjectAltName represenation is broken in jruby-openssl -> https://github.com/jruby/jruby-openssl/pull/123') do
315
+ expect(cert.extensions.find{|e| e.oid == 'subjectAltName' }.value).to eq('DNS:www.test, DNS:test, DNS:test1, DNS:test2, DNS:test3')
316
+ end
317
+
318
+ expect(cert.extensions.find{|e| e.oid == 'basicConstraints' }.value).to eq('CA:FALSE')
319
+ ku = cert.extensions.find{|e| e.oid == 'keyUsage' }.value
320
+ expect(ku).not_to match(/Certificate Sign/)
321
+ expect(ku).not_to match(/CRL Sign/)
322
+ end
323
+
324
+ it 'shold not add subject alt name on empty array' do
325
+ co = cert_options.merge({
326
+ 'CN' => 'www.test',
327
+ 'altnames' => []
328
+ })
329
+ cert_str = @trocla.password('mycert', 'x509', co)
330
+ cert = OpenSSL::X509::Certificate.new(cert_str)
331
+ expect(cert.issuer.to_s).to eq(@ca.subject.to_s)
332
+ expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
333
+ expect(verify(@ca,cert)).to be true
334
+ expect(cert.extensions.find{|e| e.oid == 'subjectAltName' }).to be_nil
335
+ end
336
+
337
+ it 'prefers full subject of single subject parts' do
338
+ co = cert_options.merge({
339
+ 'C' => 'AA',
340
+ 'ST' => 'Earth',
341
+ 'L' => 'Here',
342
+ 'O' => 'SSLTrocla',
343
+ 'OU' => 'root',
344
+ 'CN' => 'www.test',
345
+ 'emailAddress' => 'test@example.net',
346
+ })
347
+ cert_str = @trocla.password('mycert', 'x509', co)
348
+ cert = OpenSSL::X509::Certificate.new(cert_str)
349
+ ['C','ST','L','O','OU','CN'].each do |field|
350
+ expect(cert.subject.to_s).not_to match(/#{field}=#{co[field]}/)
351
+ end
352
+ expect(cert.subject.to_s).not_to match(/(Email|emailAddress)=#{co['emailAddress']}/)
353
+ expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
354
+ expect(verify(@ca,cert)).to be true
355
+ end
356
+ it "is able to create a signed cert with custom keyUsage restrictions" do
357
+ cert_str = @trocla.password('mycert_without_restrictions', 'x509', cert_options.merge({
358
+ 'CN' => 'sign only test',
359
+ 'key_usages' => [ ],
360
+ }))
361
+ cert = OpenSSL::X509::Certificate.new(cert_str)
362
+ # default size
363
+ # https://stackoverflow.com/questions/13747212/determine-key-size-from-public-key-pem-format
364
+ expect(cert.public_key.n.num_bytes * 8).to eq(4096)
365
+ expect((Date.parse(cert.not_after.localtime.to_s) - Date.today).to_i).to eq(365)
366
+ expect(cert.issuer.to_s).to eq(@ca.subject.to_s)
367
+ expect(verify(@ca,cert)).to be true
368
+
369
+ v = cert.extensions.find{|e| e.oid == 'basicConstraints' }.value
370
+ expect(v).to_not eq('CA:TRUE')
371
+ expect(cert.extensions.find{|e| e.oid == 'keyUsage' }).to be_nil
372
+ end
373
+
374
+ end
375
+ end
@@ -0,0 +1,6 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'trocla/stores/memory'
4
+ describe Trocla::Stores::Memory do
5
+ include_examples 'store_validation', Trocla::Stores::Memory.new({},nil)
6
+ end
@@ -0,0 +1,6 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'trocla/stores/moneta'
4
+ describe Trocla::Stores::Moneta do
5
+ include_examples 'store_validation', Trocla::Stores::Moneta.new({'adapter' => :Memory},{:expires => true})
6
+ end
@@ -0,0 +1,54 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Trocla::Util" do
4
+
5
+ { :random_str => 12, :salt => 8 }.each do |m,length|
6
+ describe m do
7
+ it "is random" do
8
+ expect(Trocla::Util.send(m)).not_to eq(Trocla::Util.send(m))
9
+ end
10
+
11
+ it "defaults to length #{length}" do
12
+ expect(Trocla::Util.send(m).length).to eq(length)
13
+ end
14
+
15
+ it "is possible to change length" do
16
+ expect(Trocla::Util.send(m,8).length).to eq(8)
17
+ expect(Trocla::Util.send(m,32).length).to eq(32)
18
+ expect(Trocla::Util.send(m,1).length).to eq(1)
19
+ end
20
+ end
21
+ end
22
+
23
+ describe :numeric_generator do
24
+ 10.times.each do |i|
25
+ it "creates random numeric password #{i}" do
26
+ expect(Trocla::Util.random_str(12, 'numeric')).to match(/^[0-9]{12}$/)
27
+ end
28
+ end
29
+ end
30
+
31
+ describe :hexadecimal_generator do
32
+ 10.times.each do |i|
33
+ it "creates random hexadecimal password #{i}" do
34
+ expect(Trocla::Util.random_str(12, 'hexadecimal')).to match(/^[0-9a-f]{12}$/)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe :typesafe_generator do
40
+ 10.times.each do |i|
41
+ it "creates random typesafe password #{i}" do
42
+ expect(Trocla::Util.random_str(12, 'typesafe')).to match(/^[1-9a-hj-km-xA-HJ-KM-X]{12}$/)
43
+ end
44
+ end
45
+ end
46
+
47
+ describe :salt do
48
+ 10.times.each do |i|
49
+ it "contains only characters and numbers #{i}" do
50
+ expect(Trocla::Util.salt).to match(/^[a-z0-9]+$/i)
51
+ end
52
+ end
53
+ end
54
+ end