summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2018-01-05 15:26:21 -0800
committerTim Smith <tsmith@chef.io>2018-01-05 16:05:54 -0800
commit25123712d7db2be05b13c21b40eb8eacaa7f55dc (patch)
tree52818c0a6dfc60ebb11c698e843ae7da7eaa24bf
parent98223f0b0fdca5ae8d460738c8c01ca0e80ec2c8 (diff)
downloadchef-25123712d7db2be05b13c21b40eb8eacaa7f55dc.tar.gz
Add tests for the mixin
Signed-off-by: Tim Smith <tsmith@chef.io>
-rw-r--r--kitchen-tests/cookbooks/base/recipes/default.rb2
-rw-r--r--lib/chef/mixin/openssl.rb20
-rw-r--r--spec/unit/mixin/openssl_spec.rb252
3 files changed, 263 insertions, 11 deletions
diff --git a/kitchen-tests/cookbooks/base/recipes/default.rb b/kitchen-tests/cookbooks/base/recipes/default.rb
index ad1bba8903..1811245b13 100644
--- a/kitchen-tests/cookbooks/base/recipes/default.rb
+++ b/kitchen-tests/cookbooks/base/recipes/default.rb
@@ -63,7 +63,7 @@ include_recipe "git"
directory "/etc/ssl"
# Generate new key and certificate
-openssl_dhparam "/etc/ssl_test/dhparam.pem" do
+openssl_dhparam "/etc/ssl/dhparam.pem" do
key_length 1024
action :create
end
diff --git a/lib/chef/mixin/openssl.rb b/lib/chef/mixin/openssl.rb
index 923ca75377..848f5a6088 100644
--- a/lib/chef/mixin/openssl.rb
+++ b/lib/chef/mixin/openssl.rb
@@ -19,7 +19,7 @@ class Chef
module Mixin
module OpenSSL
def self.included(_base)
- require "openssl" unless defined?(OpenSSL)
+ require "openssl" unless defined?(::OpenSSL)
end
# determine the key filename from the cert filename
@@ -45,7 +45,7 @@ class Chef
# Check if the dhparam.pem file exists
# Verify the dhparam.pem file contains a key
return false unless ::File.exist?(dhparam_pem_path)
- dhparam = OpenSSL::PKey::DH.new File.read(dhparam_pem_path)
+ dhparam = ::OpenSSL::PKey::DH.new File.read(dhparam_pem_path)
dhparam.params_ok?
end
@@ -60,8 +60,8 @@ class Chef
key_content = ::File.exist?(key_file) ? File.read(key_file) : key_file
begin
- key = OpenSSL::PKey::RSA.new key_content, key_password
- rescue OpenSSL::PKey::RSAError
+ key = ::OpenSSL::PKey::RSA.new key_content, key_password
+ rescue ::OpenSSL::PKey::RSAError
return false
end
key.private?
@@ -75,7 +75,7 @@ class Chef
raise ArgumentError, "Key length must be a power of 2 greater than or equal to 1024" unless key_length_valid?(key_length)
raise TypeError, "Generator must be an integer" unless generator.is_a?(Integer)
- OpenSSL::PKey::DH.new(key_length, generator)
+ ::OpenSSL::PKey::DH.new(key_length, generator)
end
# generate an RSA private key given key length
@@ -84,7 +84,7 @@ class Chef
def gen_rsa_priv_key(key_length)
raise ArgumentError, "Key length must be a power of 2 greater than or equal to 1024" unless key_length_valid?(key_length)
- OpenSSL::PKey::RSA.new(key_length)
+ ::OpenSSL::PKey::RSA.new(key_length)
end
# generate pem format of the public key given a private key
@@ -95,7 +95,7 @@ class Chef
# if the file exists try to read the content
# if not assume we were passed the key and set the string to the content
key_content = ::File.exist?(priv_key) ? File.read(priv_key) : priv_key
- key = OpenSSL::PKey::RSA.new key_content, priv_key_password
+ key = ::OpenSSL::PKey::RSA.new key_content, priv_key_password
key.public_key.to_pem
end
@@ -105,12 +105,12 @@ class Chef
# @param [String] key_cipher the cipher to use
# @return [String] pem contents
def encrypt_rsa_key(rsa_key, key_password, key_cipher)
- raise TypeError, "rsa_key must be a Ruby OpenSSL::PKey::RSA object" unless rsa_key.is_a?(OpenSSL::PKey::RSA)
+ raise TypeError, "rsa_key must be a Ruby OpenSSL::PKey::RSA object" unless rsa_key.is_a?(::OpenSSL::PKey::RSA)
raise TypeError, "key_password must be a string" unless key_password.is_a?(String)
raise TypeError, "key_cipher must be a string" unless key_cipher.is_a?(String)
- raise ArgumentError, "Specified key_cipher is not available on this system" unless OpenSSL::Cipher.ciphers.include?(key_cipher)
+ raise ArgumentError, "Specified key_cipher is not available on this system" unless ::OpenSSL::Cipher.ciphers.include?(key_cipher)
- cipher = OpenSSL::Cipher.new(key_cipher)
+ cipher = ::OpenSSL::Cipher.new(key_cipher)
rsa_key.to_pem(cipher, key_password)
end
end
diff --git a/spec/unit/mixin/openssl_spec.rb b/spec/unit/mixin/openssl_spec.rb
new file mode 100644
index 0000000000..8a0206116c
--- /dev/null
+++ b/spec/unit/mixin/openssl_spec.rb
@@ -0,0 +1,252 @@
+#
+# Copyright 2009-2018, Chef Software, Inc <legal@chef.io>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require "spec_helper"
+require "chef/mixin/openssl"
+
+describe Chef::Mixin::OpenSSL do
+ let(:instance) do
+ Class.new { include Chef::Mixin::OpenSSL }.new
+ end
+
+ describe ".included" do
+ it "requires openssl" do
+ instance
+ expect(defined?(OpenSSL)).to_not be(false)
+ end
+ end
+
+ # Path helpers
+ describe "#get_key_filename" do
+ context "When the input is not a string" do
+ it "Throws a TypeError" do
+ expect do
+ instance.get_key_filename(33)
+ end.to raise_error(TypeError)
+ end
+ end
+
+ context "when the input is a string" do
+ it "Generates valid keyfile names" do
+ expect(instance.get_key_filename("/etc/temp.crt")).to match("/etc/temp.key")
+ end
+ end
+ end
+
+ # Validation helpers
+ describe "#key_length_valid?" do
+ context "When the number is less than 1024" do
+ it "returns false" do
+ expect(instance.key_length_valid?(1023)).to be_falsey
+ expect(instance.key_length_valid?(2)).to be_falsey
+ expect(instance.key_length_valid?(64)).to be_falsey
+ expect(instance.key_length_valid?(512)).to be_falsey
+ end
+ end
+
+ context "When the number is greater than 1024 but is not a power of 2" do
+ it "returns false" do
+ expect(instance.key_length_valid?(1025)).to be_falsey
+ expect(instance.key_length_valid?(6666)).to be_falsey
+ expect(instance.key_length_valid?(8191)).to be_falsey
+ end
+ end
+
+ context "When the number is a power of 2, equal to or greater than 1024" do
+ it "returns true" do
+ expect(instance.key_length_valid?(1024)).to be_truthy
+ expect(instance.key_length_valid?(2048)).to be_truthy
+ expect(instance.key_length_valid?(4096)).to be_truthy
+ expect(instance.key_length_valid?(8192)).to be_truthy
+ end
+ end
+ end
+
+ describe "#dhparam_pem_valid?" do
+ require "tempfile"
+
+ before(:each) do
+ @dhparam_file = Tempfile.new("dhparam")
+ end
+
+ context "When the dhparam.pem file does not exist" do
+ it "returns false" do
+ expect(instance.dhparam_pem_valid?("/tmp/bad_filename")).to be_falsey
+ end
+ end
+
+ context "When the dhparam.pem file does exist, but does not contain a valid dhparam key" do
+ it "Throws an OpenSSL::PKey::DHError exception" do
+ expect do
+ @dhparam_file.puts("I_am_not_a_key_I_am_a_free_man")
+ @dhparam_file.close
+ instance.dhparam_pem_valid?(@dhparam_file.path)
+ end.to raise_error(::OpenSSL::PKey::DHError)
+ end
+ end
+
+ context "When the dhparam.pem file does exist, and does contain a vaild dhparam key" do
+ it "returns true" do
+ @dhparam_file.puts(::OpenSSL::PKey::DH.new(1024).to_pem)
+ @dhparam_file.close
+ expect(instance.dhparam_pem_valid?(@dhparam_file.path)).to be_truthy
+ end
+ end
+
+ after(:each) do
+ @dhparam_file.unlink
+ end
+ end
+
+ describe "#priv_key_file_valid?" do
+ require "tempfile"
+ require "openssl" unless defined?(OpenSSL)
+
+ cipher = ::OpenSSL::Cipher.new("des3")
+
+ before(:each) do
+ @keyfile = Tempfile.new("keyfile")
+ end
+
+ context "When the key file does not exist" do
+ it "returns false" do
+ expect(instance.priv_key_file_valid?("/tmp/bad_filename")).to be_falsey
+ end
+ end
+
+ context "When the key file does exist, but does not contain a valid rsa private key" do
+ it "Throws an OpenSSL::PKey::RSAError exception" do
+ @keyfile.write("I_am_not_a_key_I_am_a_free_man")
+ @keyfile.close
+ expect(instance.priv_key_file_valid?(@keyfile.path)).to be_falsey
+ end
+ end
+
+ context "When the key file does exist, and does contain a vaild rsa private key" do
+ it "returns true" do
+ @keyfile.write(::OpenSSL::PKey::RSA.new(1024).to_pem)
+ @keyfile.close
+ expect(instance.priv_key_file_valid?(@keyfile.path)).to be_truthy
+ end
+ end
+
+ context "When a valid keyfile requires a passphrase, and an invalid passphrase is supplied" do
+ it "returns false" do
+ @keyfile.write(::OpenSSL::PKey::RSA.new(1024).to_pem(cipher, "oink"))
+ @keyfile.close
+ expect(instance.priv_key_file_valid?(@keyfile.path, "poml")).to be_falsey
+ end
+ end
+
+ context "When a valid keyfile requires a passphrase, and a valid passphrase is supplied" do
+ it "returns true" do
+ @keyfile.write(::OpenSSL::PKey::RSA.new(1024).to_pem(cipher, "oink"))
+ @keyfile.close
+ expect(instance.priv_key_file_valid?(@keyfile.path, "oink")).to be_truthy
+ end
+ end
+
+ after(:each) do
+ @keyfile.unlink
+ end
+ end
+
+ # Generators
+ describe "#gen_dhparam" do
+ context "When given an invalid key length" do
+ it "Throws an ArgumentError" do
+ expect do
+ instance.gen_dhparam(2046, 2)
+ end.to raise_error(ArgumentError)
+ end
+ end
+
+ context "When given an invalid generator id" do
+ it "Throws a TypeError" do
+ expect do
+ instance.gen_dhparam(2048, "bob")
+ end.to raise_error(TypeError)
+ end
+ end
+
+ context "When a proper key length and generator id are given" do
+ it "Generates a dhparam object" do
+ expect(instance.gen_dhparam(1024, 2)).to be_kind_of(::OpenSSL::PKey::DH)
+ end
+ end
+ end
+
+ describe "#gen_rsa_priv_key" do
+ context "When given an invalid key length" do
+ it "Throws an ArgumentError" do
+ expect do
+ instance.gen_rsa_priv_key(4093)
+ end.to raise_error(ArgumentError)
+ end
+ end
+
+ context "When a proper key length is given" do
+ it "Generates an RSA key object" do
+ expect(instance.gen_rsa_priv_key(1024)).to be_kind_of(::OpenSSL::PKey::RSA)
+ end
+ end
+ end
+
+ describe "#encrypt_rsa_key" do
+ before(:all) do
+ @rsa_key = ::OpenSSL::PKey::RSA.new(1024)
+ end
+
+ context "When given anything other than an RSA key object to encrypt" do
+ it "Raises a TypeError" do
+ expect do
+ instance.encrypt_rsa_key("abcd", "efgh", "des3")
+ end.to raise_error(TypeError)
+ end
+ end
+
+ context "When given anything other than a string as the passphrase" do
+ it "Raises a TypeError" do
+ expect do
+ instance.encrypt_rsa_key(@rsa_key, 1234, "des3")
+ end.to raise_error(TypeError)
+ end
+ end
+
+ context "When given anything other than a string as the cipher" do
+ it "Raises a TypeError" do
+ expect do
+ instance.encrypt_rsa_key(@rsa_key, "1234", 1234)
+ end.to raise_error(TypeError)
+ end
+ end
+
+ context "When given an invalid cipher string" do
+ it "Raises an ArgumentError" do
+ expect do
+ instance.encrypt_rsa_key(@rsa_key, "1234", "des3_bogus")
+ end.to raise_error(ArgumentError)
+ end
+ end
+
+ context "When given a valid RSA key and a valid passphrase string" do
+ it "Generates a valid encrypted PEM" do
+ @encrypted_key = instance.encrypt_rsa_key(@rsa_key, "oink", "des3")
+ expect(@encrypted_key).to be_kind_of(String)
+ expect(::OpenSSL::PKey::RSA.new(@encrypted_key, "oink").private?).to be_truthy
+ end
+ end
+ end
+end