require 'spec_helper' require 'puppet/ssl/key' describe Puppet::SSL::Key do include PuppetSpec::Files # different UTF-8 widths # 1-byte A # 2-byte ۿ - http://www.fileformat.info/info/unicode/char/06ff/index.htm - 0xDB 0xBF / 219 191 # 3-byte ᚠ - http://www.fileformat.info/info/unicode/char/16A0/index.htm - 0xE1 0x9A 0xA0 / 225 154 160 # 4-byte ܎ - http://www.fileformat.info/info/unicode/char/2070E/index.htm - 0xF0 0xA0 0x9C 0x8E / 240 160 156 142 let (:mixed_utf8) { "A\u06FF\u16A0\u{2070E}" } # Aۿᚠ܎ before do # Get a safe temporary file dir = tmpdir('key_integration_testing') Puppet.settings[:confdir] = dir Puppet.settings[:vardir] = dir # This is necessary so the terminus instances don't lie around. # and so that Puppet::SSL::Key.indirection.save may be used Puppet::SSL::Key.indirection.termini.clear end describe 'with a custom user-specified passfile' do before do # write custom password file to where Puppet expects password_file = tmpfile('passfile') Puppet[:passfile] = password_file Puppet::FileSystem.open(password_file, nil, 'w:UTF-8') { |f| f.print(mixed_utf8) } end it 'should use the configured password file if it is not the CA key' do key = Puppet::SSL::Key.new('test') expect(key.password_file).to eq(Puppet[:passfile]) expect(key.password).to eq(mixed_utf8.force_encoding(Encoding::BINARY)) end it "should be able to read an existing private key given the correct password" do key_name = 'test' # use OpenSSL APIs to generate a private key private_key = OpenSSL::PKey::RSA.generate(512) # stash it in Puppets private key directory FileUtils.mkdir_p(Puppet[:privatekeydir]) pem_path = File.join(Puppet[:privatekeydir], "#{key_name}.pem") Puppet::FileSystem.open(pem_path, nil, 'w:UTF-8') do |f| # with password protection enabled pem = private_key.to_pem(OpenSSL::Cipher::DES.new(:EDE3, :CBC), mixed_utf8) f.print(pem) end # indirector loads existing .pem off disk instead of replacing it host = Puppet::SSL::Host.new(key_name) host.generate # newly loaded host private key matches the manually created key # Private-Key: (512 bit) style data expect(host.key.content.to_text).to eq(private_key.to_text) # -----BEGIN RSA PRIVATE KEY----- expect(host.key.content.to_s).to eq(private_key.to_s) expect(host.key.password).to eq(mixed_utf8.force_encoding(Encoding::BINARY)) end it 'should export the private key to PEM using the password' do key_name = 'test' # uses specified :passfile when writing the private key key = Puppet::SSL::Key.new(key_name) key.generate Puppet::SSL::Key.indirection.save(key) # indirector writes file here pem_path = File.join(Puppet[:privatekeydir], "#{key_name}.pem") # note incorrect password is an error expect do Puppet::FileSystem.open(pem_path, nil, 'r:ASCII') do |f| OpenSSL::PKey::RSA.new(f.read, 'invalid_password') end end.to raise_error(OpenSSL::PKey::RSAError) # but when specifying the correct password reloaded_key = nil Puppet::FileSystem.open(pem_path, nil, 'r:ASCII') do |f| reloaded_key = OpenSSL::PKey::RSA.new(f.read, mixed_utf8) end # the original key matches the manually reloaded key # Private-Key: (512 bit) style data expect(key.content.to_text).to eq(reloaded_key.to_text) # -----BEGIN RSA PRIVATE KEY----- expect(key.content.to_s).to eq(reloaded_key.to_s) end end end