diff options
author | John McCrae <john.mccrae@progress.com> | 2022-03-23 13:17:44 -0700 |
---|---|---|
committer | John McCrae <john.mccrae@progress.com> | 2022-03-23 13:17:44 -0700 |
commit | 25545606b7990b713dd8072e8cf3403f9a14a62a (patch) | |
tree | d1ae9d5c8eb25f2a1cbc2b0cbac30fac518c84fb /lib/chef | |
parent | 7621812b7e829fd53ad65430c61cb01a572d623b (diff) | |
download | chef-25545606b7990b713dd8072e8cf3403f9a14a62a.tar.gz |
updating gemlock files and updating code from feedback
Signed-off-by: John McCrae <john.mccrae@progress.com>
Diffstat (limited to 'lib/chef')
-rw-r--r-- | lib/chef/client.rb | 110 | ||||
-rw-r--r-- | lib/chef/http/authenticator.rb | 10 |
2 files changed, 61 insertions, 59 deletions
diff --git a/lib/chef/client.rb b/lib/chef/client.rb index c3b62a60c3..d50b8c6704 100644 --- a/lib/chef/client.rb +++ b/lib/chef/client.rb @@ -65,15 +65,7 @@ class Chef # The main object in a Chef run. Preps a Chef::Node and Chef::RunContext, # syncs cookbooks if necessary, and triggers convergence. class Client - class KeyMigration - include Singleton - attr_accessor :key_migrated - attr_accessor :old_priv_key - def initialize - @key_migrated = false - @old_priv_key = nil - end - end + CRYPT_EXPORTABLE = 0x00000001 attr_reader :local_context @@ -661,8 +653,8 @@ class Chef if result.rassoc("#{cert_name}") logger.trace("Client key #{config[:client_key]} is present in Certificate Store - skipping registration") else - move_key_and_register(cert_name) - logger.trace("Client key #{config[:client_key]} moved to the Certificate Store - skipping registration") + create_new_key_and_register(cert_name) + logger.trace("New client keys created in the Certificate Store - skipping registration") end events.skipping_registration(client_name, config) elsif File.exists?(config[:client_key]) @@ -683,7 +675,6 @@ class Chef raise end - # # In the brave new world of No Certs On Disk, we want to put the pem file into Keychain or the Certstore # But is it already there? def check_certstore_for_key(cert_name) @@ -692,35 +683,47 @@ class Chef win32certstore.search("#{cert_name}") end - def generate_pfx_package(cert_name, date = nil) - require_relative "mixin/powershell_exec" - extend Chef::Mixin::PowershellExec - ::Chef::HTTP::Authenticator.get_cert_password - powershell_code = <<~EOH - - $date = "#{date}" - - $certSplat = @{ - Subject = "#{cert_name}" - KeyExportPolicy = 'Exportable' - KeyUsage = @('KeyEncipherment','DigitalSignature') - CertStoreLocation = 'Cert:\\LocalMachine\\My' - TextExtension = @("2.5.29.37={text}1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.1") - }; - if ([string]$date -as [DateTime]){ - $certSplat.add('NotAfter', $date) - } - - New-SelfSignedCertificate @certSplat; - EOH - powershell_exec!(powershell_code) + def generate_pfx_package(cert_name, date) + self.class.generate_pfx_package(cert_name, date) + end + + def self.generate_pfx_package(cert_name, date) + require "openssl" + + key = OpenSSL::PKey::RSA.new(2048) + public_key = key.public_key + + subject = "CN=#{cert_name}" + + cert = OpenSSL::X509::Certificate.new + cert.subject = cert.issuer = OpenSSL::X509::Name.parse(subject) + cert.not_before = Time.now + cert.not_after = Time.parse(date) + cert.public_key = public_key + cert.serial = 0x0 + cert.version = 2 + + ef = OpenSSL::X509::ExtensionFactory.new + ef.subject_certificate = cert + ef.issuer_certificate = cert + cert.extensions = [ + ef.create_extension("subjectKeyIdentifier", "hash"), + ef.create_extension("keyUsage", "digitalSignature,keyEncipherment", true), + ] + cert.add_extension(ef.create_ext_from_string("extendedKeyUsage=critical,serverAuth,clientAuth")) + + cert.sign key, OpenSSL::Digest::SHA256.new + password = ::Chef::HTTP::Authenticator.get_cert_password + pfx = OpenSSL::PKCS12.create(password, subject, key, cert) + pfx end - def move_key_and_register(cert_name) + def create_new_key_and_register(cert_name) + require "pry" require "time" unless defined?(Time) autoload :URI, "uri" - KeyMigration.instance.key_migrated = true + # KeyMigration.instance.key_migrated = true node = Chef::Config[:node_name] d = Time.now @@ -733,31 +736,29 @@ class Chef expiration_date: end_date, } - generate_pfx_package(cert_name, end_date) - payload[:public_key] = get_public_key(cert_name) + new_pfx = generate_pfx_package(cert_name, end_date) + payload[:public_key] = new_pfx.certificate.public_key.to_pem base_url = "#{Chef::Config[:chef_server_url]}" client = Chef::ServerAPI.new(base_url, client_name: Chef::Config[:validation_client_name], signing_key_filename: Chef::Config[:validation_key]) client.post(base_url + "/clients", payload) - KeyMigration.instance.key_migrated = false + # KeyMigration.instance.key_migrated = false Chef::Log.trace("Updated client data: #{client.inspect}") + import_pfx_to_store(new_pfx) + end + + def import_pfx_to_store(new_pfx) + self.class.import_pfx_to_store(new_pfx) end - def get_public_key(cert_name) + def self.import_pfx_to_store(new_pfx) password = ::Chef::HTTP::Authenticator.get_cert_password - require_relative "mixin/powershell_exec" - extend Chef::Mixin::PowershellExec - powershell_code = <<~EOH - $my_pwd = ConvertTo-SecureString -String "#{password}" -Force -AsPlainText; - $tempfile = $([System.IO.Path]::GetTempPath()) + $([System.IO.Path]::GetRandomFileName()); - $cert = Get-ChildItem -path cert:\\LocalMachine\\My -Recurse | Where-Object { $_.Subject -match "#{cert_name}$" } -ErrorAction Stop; - Export-PFXCertificate -Cert $cert -Password $my_pwd -FilePath $tempfile; - return $tempfile; - EOH - cert_file = powershell_exec!(powershell_code).result - path = cert_file[1] - p12 = OpenSSL::PKCS12.new(File.binread(path), password) - File.delete(path) - p12.key.public_to_pem + require "win32-certstore" + tempfile = Tempfile.new("#{Chef::Config[:node_name]}.pfx") + File.open(tempfile, "wb") { |f| f.print new_pfx.to_der } + + store = ::Win32::Certstore.open("MY") + store.add_pfx(tempfile, password, CRYPT_EXPORTABLE) + tempfile.unlink end # @@ -1024,3 +1025,4 @@ end require_relative "cookbook_loader" require_relative "cookbook_version" require_relative "cookbook/synchronizer" + diff --git a/lib/chef/http/authenticator.rb b/lib/chef/http/authenticator.rb index 641599972a..79e462c5fc 100644 --- a/lib/chef/http/authenticator.rb +++ b/lib/chef/http/authenticator.rb @@ -119,6 +119,7 @@ class Chef # def self.detect_certificate_key(client_name) if ChefUtils.windows? + require "pry" check_certstore_for_key(client_name) else # generic return for Mac and LInux clients false @@ -141,9 +142,7 @@ class Chef def load_signing_key(key_file, raw_key = nil) results = retrieve_certificate_key(Chef::Config[:node_name]) - if ::Chef::Config[:migrate_key_to_keystore] == true && ::Chef::Client::KeyMigration.instance.key_migrated == true - @raw_key = IO.read(Chef::Config[:validation_key]).strip - elsif !!results + if !!results @raw_key = results elsif key_file == nil? && raw_key == nil? puts "\nNo key detected\n" @@ -192,7 +191,8 @@ class Chef unless @win32registry.key_exists?(new_path) @win32registry.create_key(new_path, true) end - password = SOME_CHARS.sample(1 + rand(SOME_CHARS.count)).join[0...14] + size = 14 + password = SOME_CHARS.sample(size).join encrypted_pass = encrypt_pfx_pass(password) values = { name: "PfxPass", type: :string, data: encrypted_pass } @win32registry.set_value(new_path, values) @@ -247,7 +247,7 @@ class Chef powershell_code = <<~CODE Try { $my_pwd = ConvertTo-SecureString -String "#{password}" -Force -AsPlainText; - $cert = Get-ChildItem -path cert:\\LocalMachine\\My -Recurse | Where-Object { $_.Subject -match "#{client_name}$" } -ErrorAction Stop; + $cert = Get-ChildItem -path cert:\\LocalMachine\\My -Recurse | Where-Object { $_.Subject -match "chef-#{client_name}$" } -ErrorAction Stop; $tempfile = [System.IO.Path]::GetTempPath() + "export_pfx.pfx"; Export-PfxCertificate -Cert $cert -Password $my_pwd -FilePath $tempfile; } |