class Chef::Resource::WindowsCertificate
Public Instance Methods
# File lib/chef/resource/windows_certificate.rb, line 234 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 $hash = #{hash} $storeCert = Get-ChildItem "cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash" if ($storeCert -eq $null) { throw 'no key exists.' } $keyname = $storeCert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName if ($keyname -eq $null) { throw 'no private key exists.' } if ($storeCert.PrivateKey.CspKeyContainerInfo.MachineKeyStore) { $fullpath = "$Env:ProgramData\\Microsoft\\Crypto\\RSA\\MachineKeys\\$keyname" } else { $currentUser = New-Object System.Security.Principal.NTAccount($Env:UserDomain, $Env:UserName) $userSID = $currentUser.Translate([System.Security.Principal.SecurityIdentifier]).Value $fullpath = "$Env:ProgramData\\Microsoft\\Crypto\\RSA\\$userSID\\$keyname" } EOH new_resource.private_key_acl.each do |name| set_acl_script << "$uname='#{name}'; icacls $fullpath /grant $uname`:RX\n" end set_acl_script end
# File lib/chef/resource/windows_certificate.rb, line 130 def add_cert(cert_obj) store = ::Win32::Certstore.open(new_resource.store_name) store.add(cert_obj) end
# File lib/chef/resource/windows_certificate.rb, line 135 def add_pfx_cert store = ::Win32::Certstore.open(new_resource.store_name) store.add_pfx(new_resource.source, new_resource.pfx_password) end
@return [Boolean] Whether the certificate file is binary encoded or not
# File lib/chef/resource/windows_certificate.rb, line 300 def binary_cert? powershell_out!("file -b --mime-encoding #{new_resource.source}").stdout.strip == "binary" end
# File lib/chef/resource/windows_certificate.rb, line 217 def cert_exists_script(hash) <<-EOH $hash = #{hash} Test-Path "Cert:\\#{cert_location}\\#{new_resource.store_name}\\$hash" EOH end
# File lib/chef/resource/windows_certificate.rb, line 198 def cert_location @location ||= new_resource.user_store ? "CurrentUser" : "LocalMachine" end
# File lib/chef/resource/windows_certificate.rb, line 202 def cert_script(persist) cert_script = "$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2" file = Chef::Util::PathHelper.cleanpath(new_resource.source) cert_script << " \"#{file}\"" if ::File.extname(file.downcase) == ".pfx" cert_script << ", \"#{new_resource.pfx_password}\"" if persist && new_resource.user_store cert_script << ", ([System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet)" elsif persist cert_script << ", ([System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::PersistKeySet -bor [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::MachineKeyset)" end end cert_script << "\n" end
# File lib/chef/resource/windows_certificate.rb, line 140 def delete_cert store = ::Win32::Certstore.open(new_resource.store_name) store.delete(new_resource.source) end
# File lib/chef/resource/windows_certificate.rb, line 173 def export_cert(cert_obj, cert_path) out_file = ::File.new(cert_path, "w+") case ::File.extname(cert_path) when ".pem" out_file.puts(cert_obj.to_pem) when ".der" out_file.puts(cert_obj.to_der) when ".cer" cert_out = powershell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CER").stdout out_file.puts(cert_out) when ".crt" cert_out = powershell_out("openssl x509 -text -inform DER -in #{cert_obj.to_pem} -outform CRT").stdout out_file.puts(cert_out) when ".pfx" cert_out = powershell_out("openssl pkcs12 -export -nokeys -in #{cert_obj.to_pem} -outform PFX").stdout out_file.puts(cert_out) when ".p7b" cert_out = powershell_out("openssl pkcs7 -export -nokeys -in #{cert_obj.to_pem} -outform P7B").stdout out_file.puts(cert_out) else Chef::Log.info("Supported certificate format .pem, .der, .cer, .crt, .pfx and .p7b") end out_file.close end
# File lib/chef/resource/windows_certificate.rb, line 145 def fetch_cert store = ::Win32::Certstore.open(new_resource.store_name) store.get(new_resource.source) end
Method returns an OpenSSL::X509::Certificate object. Might also return multiple certificates if present in certificate path
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
# File lib/chef/resource/windows_certificate.rb, line 276 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" pfx = OpenSSL::PKCS12.new(contents, new_resource.pfx_password) if pfx.ca_certs.nil? pfx.certificate else [pfx.certificate] + pfx.ca_certs end when ".p7b" OpenSSL::PKCS7.new(contents).certificates else OpenSSL::X509::Certificate.new(contents) end end
Imports the certificate object into cert store
@param cert_objs [OpenSSL::X509::Certificate] Object
containing certificate's attributes
@param is_pfx [Boolean] true if we want to import a PFX certificate
# File lib/chef/resource/windows_certificate.rb, line 310 def import_certificates(cert_objs, is_pfx) [cert_objs].flatten.each do |cert_obj| thumbprint = OpenSSL::Digest::SHA1.new(cert_obj.to_der).to_s # Fetch its thumbprint # Need to check if return value is Boolean:true # If not then the given certificate should be added in certstore if verify_cert(thumbprint) == true Chef::Log.debug("Certificate is already present") else converge_by("Adding certificate #{new_resource.source} into Store #{new_resource.store_name}") do if is_pfx add_pfx_cert else add_cert(cert_obj) end end end end end
# File lib/chef/resource/windows_certificate.rb, line 160 def show_or_store_cert(cert_obj) if new_resource.cert_path export_cert(cert_obj, new_resource.cert_path) if ::File.size(new_resource.cert_path) > 0 Chef::Log.info("Certificate export in #{new_resource.cert_path}") else ::File.delete(new_resource.cert_path) end else Chef::Log.info(cert_obj.display) end end
Checks whether a certificate with the given thumbprint is already present and valid in certificate store If the certificate is not present, verify_cert
returns a String: “Certificate not found” But if it is present but expired, it returns a Boolean: false Otherwise, it returns a Boolean: true
# File lib/chef/resource/windows_certificate.rb, line 155 def verify_cert(thumbprint = new_resource.source) store = ::Win32::Certstore.open(new_resource.store_name) store.valid?(thumbprint) end
# File lib/chef/resource/windows_certificate.rb, line 224 def within_store_script inner_script = yield "$store" <<-EOH $store = New-Object System.Security.Cryptography.X509Certificates.X509Store "#{new_resource.store_name}", ([System.Security.Cryptography.X509Certificates.StoreLocation]::#{cert_location}) $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite) #{inner_script} $store.Close() EOH end