trocla-ruby2 0.4.0

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 (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