diff options
author | Tim Smith <tsmith@chef.io> | 2019-02-16 14:53:43 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-16 14:53:43 -0800 |
commit | f4cea91fe6aa201f6d02bb321665dec77e0641b7 (patch) | |
tree | 29662b458397c599081018e907988c57aed68238 | |
parent | ab964df45ad41621a2133a30de113a4cddacaca2 (diff) | |
parent | ccd9b7c5ca3487880b4bd2aee8581e6fda53d192 (diff) | |
download | chef-f4cea91fe6aa201f6d02bb321665dec77e0641b7.tar.gz |
Merge pull request #8229 from MsysTechnologiesllc/nimesh/MSYS-937_win_certificate_add_base64
windows_certificate: Add support to import Base 64 encoded CER certificates
-rw-r--r-- | lib/chef/resource/windows_certificate.rb | 61 | ||||
-rw-r--r-- | spec/data/windows_certificates/base64_test.cer | 22 | ||||
-rw-r--r-- | spec/functional/resource/windows_certificate_spec.rb | 18 |
3 files changed, 73 insertions, 28 deletions
diff --git a/lib/chef/resource/windows_certificate.rb b/lib/chef/resource/windows_certificate.rb index a4225583e8..ebc846644b 100644 --- a/lib/chef/resource/windows_certificate.rb +++ b/lib/chef/resource/windows_certificate.rb @@ -52,7 +52,7 @@ class Chef description: "" # lazy used to set default value of sensitive to true if password is set - property :sensitive, [ TrueClass, FalseClass ], + property :sensitive, [TrueClass, FalseClass], description: "Ensure that sensitive resource data is not logged by the chef-client.", default: lazy { |r| r.pfx_password ? true : false }, skip_docs: true @@ -61,9 +61,7 @@ class Chef # Extension of the certificate ext = ::File.extname(new_resource.source) - raw_source = convert_pem(ext) - - cert_obj = OpenSSL::X509::Certificate.new(raw_source) # A certificate object in memory + cert_obj = fetch_cert_object(ext) # Fetch OpenSSL::X509::Certificate object thumbprint = OpenSSL::Digest::SHA1.new(cert_obj.to_der).to_s # Fetch its thumbprint # Need to check if return value is Boolean:true @@ -247,6 +245,7 @@ class Chef def acl_script(hash) return "" if new_resource.private_key_acl.nil? || new_resource.private_key_acl.empty? + # this PS came from http://blogs.technet.com/b/operationsguy/archive/2010/11/29/provide-access-to-private-keys-commandline-vs-powershell.aspx # and from https://msdn.microsoft.com/en-us/library/windows/desktop/bb204778(v=vs.85).aspx set_acl_script = <<-EOH @@ -272,35 +271,43 @@ class Chef set_acl_script end - # Uses powershell command to convert crt/der/cer/pfx & p7b certificates - # In PEM format and returns its certificate content - def convert_pem(ext) - out = case ext - when ".crt", ".cer", ".der" - powershell_out("openssl x509 -text -inform DER -in #{new_resource.source} -outform PEM") - when ".pfx" - powershell_out("openssl pkcs12 -in #{new_resource.source} -nodes -passin pass:'#{new_resource.pfx_password}'") - when ".p7b" - powershell_out("openssl pkcs7 -print_certs -in #{new_resource.source} -outform PEM") - else - powershell_out("openssl x509 -text -inform #{ext.delete(".")} -in #{new_resource.source} -outform PEM") - end - - if out.exitstatus == 0 - format_raw_out(out.stdout) + # Method returns an OpenSSL::X509::Certificate object + # + # Based on its extension, the certificate contents are used to initialize + # PKCS12 (PFX), PKCS7 (P7B) objects which contains OpenSSL::X509::Certificate. + # + # @note Other then PEM, all the certificates are usually in binary format, and hence + # their contents are loaded by using File.binread + # + # @param ext [String] Extension of the certificate + # + # @return [OpenSSL::X509::Certificate] Object containing certificate's attributes + # + # @raise [OpenSSL::PKCS12::PKCS12Error] When incorrect password is provided for PFX certificate + # + def fetch_cert_object(ext) + contents = if binary_cert? + ::File.binread(new_resource.source) + else + ::File.read(new_resource.source) + end + + case ext + when ".pfx" + OpenSSL::PKCS12.new(contents, new_resource.pfx_password).certificate + when ".p7b" + OpenSSL::PKCS7.new(contents).certificates.first else - raise out.stderr + OpenSSL::X509::Certificate.new(contents) end end - # Returns the certificate content - def format_raw_out(out) - begin_cert = "-----BEGIN CERTIFICATE-----" - end_cert = "-----END CERTIFICATE-----" - begin_cert + out[/#{begin_cert}(.*?)#{end_cert}/m, 1] + end_cert + # @return [Boolean] Whether the certificate file is binary encoded or not + # + def binary_cert? + powershell_out!("file -b --mime-encoding #{new_resource.source}").stdout.strip == "binary" end end - end end end diff --git a/spec/data/windows_certificates/base64_test.cer b/spec/data/windows_certificates/base64_test.cer new file mode 100644 index 0000000000..0d90bf81e3 --- /dev/null +++ b/spec/data/windows_certificates/base64_test.cer @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQNH6iXZnEKbFOEQ7D9f9iCTANBgkqhkiG9w0BAQsFADBK +MSMwIQYDVQQDDBpBIEJhc2U2NCBEdW1teSBDZXJ0aWZpY2F0ZTEjMCEGCSqGSIb3 +DQEJARYUdGVzdGJ5cnNwZWNAY2hlZi5jb20wHhcNMTkwMjEyMDk1ODM2WhcNMjAw +MjEyMTAxODM2WjBKMSMwIQYDVQQDDBpBIEJhc2U2NCBEdW1teSBDZXJ0aWZpY2F0 +ZTEjMCEGCSqGSIb3DQEJARYUdGVzdGJ5cnNwZWNAY2hlZi5jb20wggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDSy2Qlf2k1X3y/YgEjnvD0K8NeKgXKKi62 +RHRMTJ2+6KSg+I1MqHZC+BVrfzehuJVby5kM7tGLF8FvM3q7X/5oSPg8pvLZzIV0 +pBrpVPCTYw8fnlmFKBt/+m2XOqsWyL59yP+p66SHAKmoLYTGu8dkGvgJn3dwKNen +VFmwadteVfKs2wFW/ZwUxH4aLloCa8KSyqstIXrYQmdqqFOSuEgkynalD19dozSv +QtkQ9FZPuFGDwNpdO7OrcjE1lTUlzuth7CqV/pj4GYJhK/PPtO8Ing/BtwZm5XB8 +2yvvLVnL7Y/hikg2ENKA9fOYk52zR/kkd7d8qoJva7WlYEXTZvpdAgMBAAGjcDBu +MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEw +HgYDVR0RBBcwFYITd3d3LnRlc3RieXJzcGVjLmNvbTAdBgNVHQ4EFgQUuL1l247K +h+cVH9LehmQgXuV8F6MwDQYJKoZIhvcNAQELBQADggEBAMTJW5tSZ/g2AP45EUwj +PLDnDLY4YnsJDQ7Jo58EAY6givUc+ZnKRWxYAYNBOKcqDM5E4pXi3Fa1lKYR1vMu +5AThPaDXhv18ljGAs21MYt9hl7PqdzbfX4ejF+jCD4UrE8bGtxuDc1WQ2HbeJtdj +0j7BPPNXfcvPAIyX3BEOQFUPgvVAqzWMQLpdUKg+sNUJZijqKQv11xVALGHtxqGB +1MFrdl6D/idODfhcdo2n1tBMyOGhHwEOBLqB1PTH72g5J4BVx4iwH/gh8PRmMy0P +eJkNspgOBGPOhNpe7bhmK45MBuJpmjyl/CYCqtQvaEdpbuRQIgc2e+YRMfR71qYp +Em8= +-----END CERTIFICATE----- diff --git a/spec/functional/resource/windows_certificate_spec.rb b/spec/functional/resource/windows_certificate_spec.rb index f60b63ade9..eac7ee31b2 100644 --- a/spec/functional/resource/windows_certificate_spec.rb +++ b/spec/functional/resource/windows_certificate_spec.rb @@ -60,6 +60,7 @@ describe Chef::Resource::WindowsCertificate, :windows_only, :appveyor_only do let(:store) { "Chef-Functional-Test" } let(:certificate_path) { File.expand_path(File.join(CHEF_SPEC_DATA, "windows_certificates")) } let(:cer_path) { File.join(certificate_path, "test.cer") } + let(:base64_path) { File.join(certificate_path, "base64_test.cer") } let(:pem_path) { File.join(certificate_path, "test.pem") } let(:pfx_path) { File.join(certificate_path, "test.pfx") } let(:out_path) { File.join(certificate_path, "testout.pem") } @@ -174,6 +175,21 @@ describe Chef::Resource::WindowsCertificate, :windows_only, :appveyor_only do end end + context "Adds Base64 Encoded CER" do + before do + win_certificate.source = base64_path + win_certificate.run_action(:create) + end + it "Imports certificate into store" do + expect(no_of_certificates).to eq(1) + end + it "Idempotent: Does not converge while adding again" do + win_certificate.run_action(:create) + expect(no_of_certificates).to eq(1) + expect(win_certificate).not_to be_updated_by_last_action + end + end + context "Adds PEM" do before do win_certificate.source = pem_path @@ -212,7 +228,7 @@ describe Chef::Resource::WindowsCertificate, :windows_only, :appveyor_only do win_certificate.pfx_password = "Invalid password" end it "Raises an error" do - expect { win_certificate.run_action(:create) }.to raise_error(RuntimeError) + expect { win_certificate.run_action(:create) }.to raise_error(OpenSSL::PKCS12::PKCS12Error) end end end |