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.
- checksums.yaml +7 -0
- data/.document +4 -0
- data/.rspec +1 -0
- data/.travis.yml +10 -0
- data/CHANGELOG.md +71 -0
- data/Gemfile +51 -0
- data/LICENSE.txt +15 -0
- data/README.md +351 -0
- data/Rakefile +53 -0
- data/bin/trocla +148 -0
- data/ext/redhat/rubygem-trocla.spec +120 -0
- data/lib/VERSION +4 -0
- data/lib/trocla.rb +162 -0
- data/lib/trocla/default_config.yaml +47 -0
- data/lib/trocla/encryptions.rb +54 -0
- data/lib/trocla/encryptions/none.rb +10 -0
- data/lib/trocla/encryptions/ssl.rb +51 -0
- data/lib/trocla/formats.rb +54 -0
- data/lib/trocla/formats/bcrypt.rb +7 -0
- data/lib/trocla/formats/md5crypt.rb +6 -0
- data/lib/trocla/formats/mysql.rb +6 -0
- data/lib/trocla/formats/pgsql.rb +7 -0
- data/lib/trocla/formats/plain.rb +7 -0
- data/lib/trocla/formats/sha1.rb +7 -0
- data/lib/trocla/formats/sha256crypt.rb +6 -0
- data/lib/trocla/formats/sha512crypt.rb +6 -0
- data/lib/trocla/formats/ssha.rb +9 -0
- data/lib/trocla/formats/sshkey.rb +46 -0
- data/lib/trocla/formats/x509.rb +197 -0
- data/lib/trocla/store.rb +80 -0
- data/lib/trocla/stores.rb +39 -0
- data/lib/trocla/stores/memory.rb +56 -0
- data/lib/trocla/stores/moneta.rb +58 -0
- data/lib/trocla/util.rb +71 -0
- data/lib/trocla/version.rb +22 -0
- data/spec/data/.keep +0 -0
- data/spec/spec_helper.rb +290 -0
- data/spec/trocla/encryptions/none_spec.rb +22 -0
- data/spec/trocla/encryptions/ssl_spec.rb +26 -0
- data/spec/trocla/formats/x509_spec.rb +375 -0
- data/spec/trocla/store/memory_spec.rb +6 -0
- data/spec/trocla/store/moneta_spec.rb +6 -0
- data/spec/trocla/util_spec.rb +54 -0
- data/spec/trocla_spec.rb +248 -0
- data/trocla-ruby2.gemspec +104 -0
- 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,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
|