class Chef::Resource::WindowsCertificate

Public Instance Methods

acl_script(hash) click to toggle source
# 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
add_cert(cert_obj) click to toggle source
# 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
add_pfx_cert() click to toggle source
# 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
binary_cert?() click to toggle source

@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
cert_exists_script(hash) click to toggle source
# 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
cert_location() click to toggle source
# File lib/chef/resource/windows_certificate.rb, line 198
def cert_location
  @location ||= new_resource.user_store ? "CurrentUser" : "LocalMachine"
end
cert_script(persist) click to toggle source
# 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
delete_cert() click to toggle source
# 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
export_cert(cert_obj, cert_path) click to toggle source
# 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
fetch_cert() click to toggle source
# 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
fetch_cert_object(ext) click to toggle source

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
import_certificates(cert_objs, is_pfx) click to toggle source

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
show_or_store_cert(cert_obj) click to toggle source
# 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
verify_cert(thumbprint = new_resource.source) click to toggle source

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
within_store_script() { |"$store"| ... } click to toggle source
# 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