1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
|
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
|