Update mcollective.init according to OSCI-855
[packages/precise/mcollective.git] / spec / unit / ssl_spec.rb
1 #!/usr/bin/env rspec
2
3 require 'spec_helper'
4
5 module MCollective
6   describe SSL do
7     before do
8       @rootdir = File.dirname(__FILE__)
9       @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem")
10     end
11
12     it "should be able to decode base64 text it encoded" do
13       @ssl.base64_decode(@ssl.base64_encode("foo")).should == "foo"
14     end
15
16     it "should decrypt what it encrypted with RSA" do
17       crypted = @ssl.aes_encrypt("foo")
18       decrypted = @ssl.aes_decrypt(crypted[:key], crypted[:data])
19
20       decrypted.should == "foo"
21     end
22
23     it "should be able to decrypt using RSA private key what it encrypted with RSA public key" do
24       crypted = @ssl.rsa_encrypt_with_public("foo")
25       decrypted = @ssl.rsa_decrypt_with_private(crypted)
26
27       decrypted.should == "foo"
28     end
29
30     it "should be able to decrypt using RSA public key what it encrypted with RSA private key" do
31       crypted = @ssl.rsa_encrypt_with_private("foo")
32       decrypted = @ssl.rsa_decrypt_with_public(crypted)
33
34       decrypted.should == "foo"
35     end
36
37     it "using a helper it should be able to decrypt with private key what it encrypted using the public key" do
38       @ssl.decrypt_with_private(@ssl.encrypt_with_public("foo")).should == "foo"
39       @ssl.decrypt_with_private(@ssl.encrypt_with_public("foo", false), false).should == "foo"
40     end
41
42     it "using a helper it should be able to decrypt with public key what it encrypted using the private key" do
43       @ssl.decrypt_with_public(@ssl.encrypt_with_private("foo")).should == "foo"
44       @ssl.decrypt_with_public(@ssl.encrypt_with_private("foo", false), false).should == "foo"
45     end
46
47     describe "#initialize" do
48       it "should default to aes-256-cbc" do
49         @ssl.ssl_cipher.should == "aes-256-cbc"
50       end
51
52       it "should take the configured value when present" do
53         Config.instance.stubs("ssl_cipher").returns("aes-128-cbc")
54         @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem")
55
56         @ssl.ssl_cipher.should == "aes-128-cbc"
57       end
58
59       it "should set the supplied ssl cipher" do
60         @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem", nil, "aes-128-cbc")
61         @ssl.ssl_cipher.should == "aes-128-cbc"
62       end
63
64       it "should prefer the supplied cipher over configured cipher" do
65         Config.instance.stubs("aes_key_size").returns("foo-foo-foo")
66         @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem", nil, "aes-128-cbc")
67
68         @ssl.ssl_cipher.should == "aes-128-cbc"
69       end
70
71       it "should fail on invalid ciphers" do
72         expect {
73           @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem", nil, "foo-foo-foo")
74         }.to raise_error("The supplied cipher 'foo-foo-foo' is not supported")
75       end
76     end
77
78     describe "#read_key" do
79       it "should fail on non exiting files" do
80         expect {
81           @ssl.read_key(:public, "/nonexisting")
82         }.to raise_error("Could not find key /nonexisting")
83       end
84
85       it "should fail on existing, empty files" do
86         File.expects(:exist?).with('key').returns(true)
87         File.expects(:zero?).with('key').returns(true)
88         expect{
89           @ssl.read_key(:public, 'key')
90         }.to raise_error("public key file 'key' is empty")
91       end
92
93       it "should fail on unknown key types" do
94         expect {
95           @ssl.read_key(:unknown, @ssl.public_key_file)
96         }.to raise_error("Can only load :public or :private keys")
97       end
98
99       it "should read a public key" do
100         @ssl.read_key(:public, "#{@rootdir}/../fixtures/test-public.pem")
101       end
102
103       it "should read the public key from a certificate" do
104         @ssl.read_key(:public, "#{@rootdir}/../fixtures/test-cert.pem").to_s.should match(/.+BEGIN.+PUBLIC KEY.+END.+PUBLIC KEY.+/m)
105       end
106
107       it "should return nil if no key was given" do
108         @ssl.read_key(:public).should == nil
109       end
110
111       it "should return nil if nil key was given" do
112         @ssl.read_key(:public, nil).should == nil
113       end
114
115       it "should clear the OpenSSL error queue on ruby 1.8" do
116         Util.expects(:ruby_version).returns("1.8.7")
117         OpenSSL.expects(:errors)
118         @ssl.read_key(:public, "#{@rootdir}/../fixtures/test-public.pem")
119         @ssl.read_key(:private, "#{@rootdir}/../fixtures/test-private.pem")
120       end
121
122       it "should not clear the OpenSSL error queue on ruby > 1.8" do
123         Util.expects(:ruby_version).returns("1.9.3")
124         OpenSSL.expects(:errors).never
125         @ssl.read_key(:public, "#{@rootdir}/../fixtures/test-public.pem")
126         @ssl.read_key(:private, "#{@rootdir}/../fixtures/test-private.pem")
127       end
128     end
129
130     describe "#base64_encode" do
131       it "should correctly encode" do
132         @ssl.base64_encode("foo").should == "Zm9v\n"
133         SSL.base64_encode("foo").should == "Zm9v\n"
134       end
135     end
136
137     describe "#base64_decode" do
138       it "should correctly decode" do
139         @ssl.base64_decode("Zm9v").should == "foo"
140         SSL.base64_decode("Zm9v").should == "foo"
141       end
142     end
143
144     describe "#aes_encrypt" do
145       it "should create a key and data" do
146         crypted = @ssl.aes_encrypt("foo")
147
148         crypted.include?(:key).should == true
149         crypted.include?(:data).should == true
150       end
151     end
152
153     describe "#aes_decrypt" do
154       it "should decrypt correctly given key and data" do
155         key = @ssl.base64_decode("rAaCyW6qB0XqZNa9hji0qHwrI3P47t8diLNXoemW9ss=")
156         data = @ssl.base64_decode("mSthvO/wSl0ArNOcgysTVw==")
157
158         @ssl.aes_decrypt(key, data).should == "foo"
159       end
160
161       it "should decrypt correctly given key, data and cipher" do
162         key = @ssl.base64_decode("VEma3a/R7fjw2M4d0NIctA==")
163         data = @ssl.base64_decode("FkH6qLvKTn7a+uNPe8ciHA==")
164
165         # the default aes-256-cbc should fail here, the key above is 128 bit
166         # the exception classes changed mid-1.9.2 :(
167         if OpenSSL.constants.include?("CipherError")
168           expect { @ssl.aes_decrypt(key, data) }.to raise_error(OpenSSL::CipherError)
169         else
170           expect { @ssl.aes_decrypt(key, data) }.to raise_error(OpenSSL::Cipher::CipherError)
171         end
172
173         # new ssl instance configured for aes-128-cbc, should work
174         @ssl = SSL.new("#{@rootdir}/../fixtures/test-public.pem", "#{@rootdir}/../fixtures/test-private.pem", nil, "aes-128-cbc")
175         @ssl.aes_decrypt(key, data).should == "foo"
176       end
177     end
178
179     describe "#md5" do
180       it "should produce correct md5 sums" do
181         # echo -n 'hello world'|md5sum
182         @ssl.md5("hello world").should == "5eb63bbbe01eeed093cb22bb8f5acdc3"
183       end
184     end
185     describe "#sign" do
186       it "should sign the message without base64 by default" do
187         SSL.md5(@ssl.sign("hello world")).should == "8269b23f55945aaa82efbff857c845a6"
188       end
189
190       it "should support base64 encoding messages" do
191         SSL.md5(@ssl.sign("hello world", true)).should == "8a4eb3c3d44d22c46dc36a7e441d8db0"
192       end
193     end
194
195     describe "#verify_signature" do
196       it "should correctly verify a message signed using the same keypair" do
197         @ssl.verify_signature(@ssl.sign("hello world"), "hello world").should == true
198         @ssl.verify_signature(@ssl.sign("hello world", true), "hello world", true).should == true
199       end
200
201       it "should fail to verify messages not signed by the key" do
202         @ssl.verify_signature("evil fake signature", "hello world").should == false
203       end
204     end
205
206     describe "#decrypt_with_public" do
207       it "should decrypt correctly given key and data in base64 format" do
208         crypted = {:key=> "YaRcSDdcKgnRZ4Eu2eirl/+lzDgVkPZ41kXAQQNOi+6AfjdbbOW7Zblibx9r\n3TzZAi0ulA94gqNAXPvPC8LaO8W9TtJwlto/RHwDM7ZdfqEImSYoVACFNq28\n+0MLr3K3hIBsB1pyxgFTQul+MrCq+3Fik7Nj7ZKkJUT2veyqbg8=",
209           :data=>"TLVw1EYeOaGDmEC/R2I/cA=="}
210
211         @ssl.decrypt_with_public(crypted).should == "foo"
212       end
213     end
214
215     describe "#decrypt_with_private" do
216       it "should decrypt correctly given key and data in base64 format" do
217         crypted = {:key=> "kO1kUgJBiEBdoajN4OHp9BOie6dCznf1YKbBnp3LOyBxcDDQtjxEBlPmjQve\npXrQJ5xpLX6oNBxzU18Pf2SKYUZSbzIkDUb97GQY0WoBQsdM2OwPXH+HtF2A\no5N8iIx9srPAEAFa6hZAdqvcmRT/SzhP1kH+Gyy8fyvW8HGBjNY=",
218           :data=>"gDTaHCmes/Yua4jtjmgukQ=="}
219
220         @ssl.decrypt_with_private(crypted).should == "foo"
221       end
222     end
223
224     describe "#decrypt_with_private" do
225       it "should fail if not given a key" do
226         expect {
227           @ssl.decrypt_with_private({:iv => "x", :data => "x"})
228         }.to raise_error("Crypted data should include a key")
229       end
230
231       it "should fail if not given data" do
232         expect {
233           @ssl.decrypt_with_private({:iv => "x", :key => "x"})
234         }.to raise_error("Crypted data should include data")
235       end
236     end
237
238     describe "#decrypt_with_public" do
239       it "should fail if not given a key" do
240         expect {
241           @ssl.decrypt_with_public({:iv => "x", :data => "x"})
242         }.to raise_error("Crypted data should include a key")
243       end
244
245       it "should fail if not given data" do
246         expect {
247           @ssl.decrypt_with_public({:iv => "x", :key => "x"})
248         }.to raise_error("Crypted data should include data")
249       end
250     end
251
252     describe "#uuid" do
253       it "should produce repeatable uuids" do
254         SSL.uuid("hello world").should == SSL.uuid("hello world")
255       end
256
257       it "should not always produce the same uuid" do
258         SSL.uuid.should_not == SSL.uuid
259       end
260     end
261   end
262 end