summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2018-01-22 07:44:28 -0800
committerGitHub <noreply@github.com>2018-01-22 07:44:28 -0800
commit9ef5c2d239b2501cad5fc01bdfc9d617ddef5430 (patch)
tree899d755703c7e861bdc9f0e0e7eba066842db7b2
parent84fb46aeb7e6c457665dc4bf5ac5719b4f5eefd5 (diff)
parent1a88d51c49b23365c8af5c6a6f5a9306eccae225 (diff)
downloadchef-9ef5c2d239b2501cad5fc01bdfc9d617ddef5430.tar.gz
Merge pull request #6736 from chef/openssl_resources
Add dhparam, rsa_private_key and rsa_public_key resources
-rw-r--r--kitchen-tests/cookbooks/base/recipes/default.rb20
-rw-r--r--lib/chef/mixin/openssl.rb118
-rw-r--r--lib/chef/resource/openssl_dhparam.rb59
-rw-r--r--lib/chef/resource/openssl_rsa_private_key.rb69
-rw-r--r--lib/chef/resource/openssl_rsa_public_key.rb56
-rw-r--r--lib/chef/resources.rb3
-rw-r--r--spec/unit/mixin/openssl_spec.rb252
-rw-r--r--spec/unit/resource/openssl_dhparam.rb51
-rw-r--r--spec/unit/resource/openssl_rsa_private_key.rb59
-rw-r--r--spec/unit/resource/openssl_rsa_public_key.rb39
10 files changed, 726 insertions, 0 deletions
diff --git a/kitchen-tests/cookbooks/base/recipes/default.rb b/kitchen-tests/cookbooks/base/recipes/default.rb
index 8b0eac0e6e..1811245b13 100644
--- a/kitchen-tests/cookbooks/base/recipes/default.rb
+++ b/kitchen-tests/cookbooks/base/recipes/default.rb
@@ -60,4 +60,24 @@ include_recipe "cron"
include_recipe "git"
+directory "/etc/ssl"
+
+# Generate new key and certificate
+openssl_dhparam "/etc/ssl/dhparam.pem" do
+ key_length 1024
+ action :create
+end
+
+# Generate new key with aes-128-cbc cipher
+openssl_rsa_private_key "/etc/ssl/rsakey_aes128cbc.pem" do
+ key_length 1024
+ key_cipher "aes-128-cbc"
+ action :create
+end
+
+openssl_rsa_public_key "/etc/ssl/rsakey_aes128cbc.pub" do
+ private_key_path "/etc/ssl/rsakey_aes128cbc.pem"
+ action :create
+end
+
include_recipe "::tests"
diff --git a/lib/chef/mixin/openssl.rb b/lib/chef/mixin/openssl.rb
new file mode 100644
index 0000000000..e868da9ac4
--- /dev/null
+++ b/lib/chef/mixin/openssl.rb
@@ -0,0 +1,118 @@
+#
+# Copyright:: Copyright 2013-2018, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# 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.
+#
+
+class Chef
+ module Mixin
+ module OpenSSL
+ def self.included(_base)
+ require "openssl" unless defined?(::OpenSSL)
+ end
+
+ # determine the key filename from the cert filename
+ # @param [String] cert_filename the path to the certfile
+ # @return [String] the path to the keyfile
+ def get_key_filename(cert_filename)
+ cert_file_path, cert_filename = ::File.split(cert_filename)
+ cert_filename = ::File.basename(cert_filename, ::File.extname(cert_filename))
+ cert_file_path + ::File::SEPARATOR + cert_filename + ".key"
+ end
+
+ # is the key length a valid key length
+ # @param [Integer] number
+ # @return [Boolean] is length valid
+ def key_length_valid?(number)
+ number >= 1024 && ( number & (number - 1) == 0 )
+ end
+
+ # validate a dhparam file from path
+ # @param [String] dhparam_pem_path the path to the pem file
+ # @return [Boolean] is the key valid
+ def dhparam_pem_valid?(dhparam_pem_path)
+ # 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.params_ok?
+ end
+
+ # given either a key file path or key file content see if it's actually
+ # a private key
+ # @param [String] key_file the path to the keyfile or the key contents
+ # @param [String] key_password optional password to the keyfile
+ # @return [Boolean] is the key valid?
+ def priv_key_file_valid?(key_file, key_password = nil)
+ # 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?(key_file) ? File.read(key_file) : key_file
+
+ begin
+ key = ::OpenSSL::PKey::RSA.new key_content, key_password
+ rescue ::OpenSSL::PKey::RSAError
+ return false
+ end
+ key.private?
+ end
+
+ # generate a dhparam file
+ # @param [String] key_length the length of the key
+ # @param [Integer] generator the dhparam generator to use
+ # @return [OpenSSL::PKey::DH]
+ def gen_dhparam(key_length, generator)
+ 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)
+ end
+
+ # generate an RSA private key given key length
+ # @param [Integer] key_length the key length of the private key
+ # @return [OpenSSL::PKey::DH]
+ 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)
+ end
+
+ # generate pem format of the public key given a private key
+ # @param [String] priv_key either the contents of the private key or the path to the file
+ # @param [String] priv_key_password optional password for the private key
+ # @return [String] pem format of the public key
+ def gen_rsa_pub_key(priv_key, priv_key_password = nil)
+ # 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.public_key.to_pem
+ end
+
+ # generate a pem file given a cipher, key, an optional key_password
+ # @param [OpenSSL::PKey::RSA] rsa_key the private key object
+ # @param [String] key_password the password for the private key
+ # @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, "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)
+
+ cipher = ::OpenSSL::Cipher.new(key_cipher)
+ rsa_key.to_pem(cipher, key_password)
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/openssl_dhparam.rb b/lib/chef/resource/openssl_dhparam.rb
new file mode 100644
index 0000000000..cec27d21bd
--- /dev/null
+++ b/lib/chef/resource/openssl_dhparam.rb
@@ -0,0 +1,59 @@
+#
+# Copyright:: Copyright 2009-2018, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# 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 "chef/resource"
+
+class Chef
+ class Resource
+ # a resource for generating dhparam.pem files.
+ # If a valid dhparam.pem file is found at the specified location, no new
+ # file will be created. If a file is found at the specified location but it
+ # is not a valid dhparam file, it will be overwritten.
+ #
+ # @since 14.0
+ class OpensslDhparam < Chef::Resource
+ require "chef/mixin/openssl"
+ include Chef::Mixin::OpenSSL
+
+ resource_name :openssl_dhparam
+
+ property :path, String, name_property: true
+ property :key_length, equal_to: [1024, 2048, 4096, 8192], default: 2048
+ property :generator, equal_to: [2, 5], default: 2
+ property :owner, [String, nil]
+ property :group, [String, nil]
+ property :mode, [Integer, String], default: "0640"
+
+ action :create do
+ unless dhparam_pem_valid?(new_resource.path)
+ converge_by("Create a dhparam file #{new_resource.path}") do
+ dhparam_content = gen_dhparam(new_resource.key_length, new_resource.generator).to_pem
+
+ declare_resource(:file, new_resource.path) do
+ action :create
+ owner new_resource.owner unless new_resource.owner.nil?
+ group new_resource.group unless new_resource.group.nil?
+ mode new_resource.mode
+ sensitive true
+ content dhparam_content
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/openssl_rsa_private_key.rb b/lib/chef/resource/openssl_rsa_private_key.rb
new file mode 100644
index 0000000000..32c394846b
--- /dev/null
+++ b/lib/chef/resource/openssl_rsa_private_key.rb
@@ -0,0 +1,69 @@
+#
+# Copyright:: Copyright 2009-2018, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# 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 "chef/resource"
+
+class Chef
+ class Resource
+ # A resource for generating rsa private key files.
+ # If a valid rsa key file can be opened at the specified location, no new file
+ # will be created. If the RSA key file cannot be opened, either because it
+ # does not exist or because the password to the RSA key file does not match
+ # the password in the recipe, it will be overwritten.
+ #
+ # @since 14.0
+ class OpensslRsaPrivateKey < Chef::Resource
+ require "chef/mixin/openssl"
+ include Chef::Mixin::OpenSSL
+
+ resource_name :openssl_rsa_private_key
+ provides :openssl_rsa_private_key
+ provides :openssl_rsa_key # legacy cookbook resource name
+
+ property :path, String, name_property: true
+ property :key_length, equal_to: [1024, 2048, 4096, 8192], default: 2048
+ property :key_pass, String
+ property :key_cipher, String, default: "des3", equal_to: OpenSSL::Cipher.ciphers
+ property :owner, [String, nil]
+ property :group, [String, nil]
+ property :mode, [Integer, String], default: "0600"
+ property :force, [true, false], default: false
+
+ action :create do
+ return if new_resource.force || priv_key_file_valid?(new_resource.path, new_resource.key_pass)
+
+ converge_by("create #{new_resource.key_length} bit RSA key #{new_resource.path}") do
+ if new_resource.key_pass
+ unencrypted_rsa_key = gen_rsa_priv_key(new_resource.key_length)
+ rsa_key_content = encrypt_rsa_key(unencrypted_rsa_key, new_resource.key_pass, new_resource.key_cipher)
+ else
+ rsa_key_content = gen_rsa_priv_key(new_resource.key_length).to_pem
+ end
+
+ declare_resource(:file, new_resource.path) do
+ action :create
+ owner new_resource.owner unless new_resource.owner.nil?
+ group new_resource.group unless new_resource.group.nil?
+ mode new_resource.mode
+ sensitive true
+ content rsa_key_content
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/openssl_rsa_public_key.rb b/lib/chef/resource/openssl_rsa_public_key.rb
new file mode 100644
index 0000000000..602b48065e
--- /dev/null
+++ b/lib/chef/resource/openssl_rsa_public_key.rb
@@ -0,0 +1,56 @@
+#
+# Copyright:: Copyright 2009-2018, Chef Software Inc.
+# License:: Apache License, Version 2.0
+#
+# 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 "chef/resource"
+
+class Chef
+ class Resource
+ # A resource for generating rsa public key files given a rsa private key.
+ #
+ # @since 14.0
+ class OpensslRsaPublicKey < Chef::Resource
+ require "chef/mixin/openssl"
+ include Chef::Mixin::OpenSSL
+
+ resource_name :openssl_rsa_public_key
+
+ property :path, String, name_property: true
+ property :private_key_path, String
+ property :private_key_content, String
+ property :private_key_pass, String
+ property :owner, [String, nil]
+ property :group, [String, nil]
+ property :mode, [Integer, String], default: "0640"
+
+ action :create do
+ raise ArgumentError, "You cannot specify both 'private_key_path' and 'private_key_content' properties at the same time." if new_resource.private_key_path && new_resource.private_key_content
+ raise ArgumentError, "You must specify the private key with either 'private_key_path' or 'private_key_content' properties." unless new_resource.private_key_path || new_resource.private_key_content
+ raise "#{new_resource.private_key_path} not a valid private RSA key or password is invalid" unless priv_key_file_valid?((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
+
+ rsa_key_content = gen_rsa_pub_key((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
+
+ declare_resource(:file, new_resource.path) do
+ action :create
+ owner new_resource.owner unless new_resource.owner.nil?
+ group new_resource.group unless new_resource.group.nil?
+ mode new_resource.mode
+ content rsa_key_content
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 0723f1b45a..9fee978432 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -53,6 +53,9 @@ require "chef/resource/mdadm"
require "chef/resource/mount"
require "chef/resource/ohai"
require "chef/resource/openbsd_package"
+require "chef/resource/openssl_dhparam"
+require "chef/resource/openssl_rsa_private_key"
+require "chef/resource/openssl_rsa_public_key"
require "chef/resource/package"
require "chef/resource/pacman_package"
require "chef/resource/paludis_package"
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
diff --git a/spec/unit/resource/openssl_dhparam.rb b/spec/unit/resource/openssl_dhparam.rb
new file mode 100644
index 0000000000..d1021d4f7e
--- /dev/null
+++ b/spec/unit/resource/openssl_dhparam.rb
@@ -0,0 +1,51 @@
+#
+# Copyright:: Copyright 2018, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# 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"
+
+describe Chef::Resource::OpensslDhparam do
+
+ let(:resource) { Chef::Resource::OpensslDhparam.new("dhparam") }
+
+ it "has a resource name of :openssl_dhparam" do
+ expect(resource.resource_name).to eql(:openssl_dhparam)
+ end
+
+ it "has a default action of create" do
+ expect(resource.action).to eql([:create])
+ end
+
+ it "has a default mode of '0640'" do
+ expect(resource.mode).to eql("0640")
+ end
+
+ it "has a default generator of 2" do
+ expect(resource.generator).to eql(2)
+ end
+
+ it "has a default key_length of 2048" do
+ expect(resource.key_length).to eql(2048)
+ end
+
+ it "only accepts valid key length" do
+ expect { resource.key_length 1234 }.to raise_error(ArgumentError)
+ end
+
+ it "the path property is the name property" do
+ expect(resource.path).to eql("dhparam")
+ end
+end
diff --git a/spec/unit/resource/openssl_rsa_private_key.rb b/spec/unit/resource/openssl_rsa_private_key.rb
new file mode 100644
index 0000000000..67bebf17fe
--- /dev/null
+++ b/spec/unit/resource/openssl_rsa_private_key.rb
@@ -0,0 +1,59 @@
+#
+# Copyright:: Copyright 2018, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# 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"
+
+describe Chef::Resource::OpensslRsaPrivateKey do
+
+ let(:resource) { Chef::Resource::OpensslRsaPrivateKey.new("key") }
+
+ it "has a resource name of :openssl_rsa_private_key" do
+ expect(resource.resource_name).to eql(:openssl_rsa_private_key)
+ end
+
+ it "has a default action of create" do
+ expect(resource.action).to eql([:create])
+ end
+
+ it "has a default mode of '0600'" do
+ expect(resource.mode).to eql("0600")
+ end
+
+ it "has a default key_cipher of 'des3'" do
+ expect(resource.key_cipher).to eql("des3")
+ end
+
+ it "only accepts valid key_cipher values" do
+ expect { resource.key_cipher "fako" }.to raise_error(ArgumentError)
+ end
+
+ it "has a default key_length of 2048" do
+ expect(resource.key_length).to eql(2048)
+ end
+
+ it "only accepts valid key length" do
+ expect { resource.key_length 1234 }.to raise_error(ArgumentError)
+ end
+
+ it "has a default force value of of false" do
+ expect(resource.force).to eql(false)
+ end
+
+ it "the path property is the name property" do
+ expect(resource.path).to eql("key")
+ end
+end
diff --git a/spec/unit/resource/openssl_rsa_public_key.rb b/spec/unit/resource/openssl_rsa_public_key.rb
new file mode 100644
index 0000000000..d624e10338
--- /dev/null
+++ b/spec/unit/resource/openssl_rsa_public_key.rb
@@ -0,0 +1,39 @@
+#
+# Copyright:: Copyright 2018, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# 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"
+
+describe Chef::Resource::OpensslRsaPublicKey do
+
+ let(:resource) { Chef::Resource::OpensslRsaPublicKey.new("key") }
+
+ it "has a resource name of :openssl_rsa_public_key" do
+ expect(resource.resource_name).to eql(:openssl_rsa_public_key)
+ end
+
+ it "has a default action of create" do
+ expect(resource.action).to eql([:create])
+ end
+
+ it "has a default mode of '0640'" do
+ expect(resource.mode).to eql("0640")
+ end
+
+ it "the path property is the name property" do
+ expect(resource.path).to eql("key")
+ end
+end