puppetlabs-stdlib/lib/puppet/parser/functions/validate_x509_rsa_key_pair.rb
Matt Bostock 97320ab421 Add a function to validate an x509 RSA key pair
Add a function to validate an x509 RSA certificate and key pair, as
commonly used for TLS certificates.

The rationale behind this is that we store our TLS certificates and
private keys in Hiera YAML files, and poor indentation or formatting in
the YAML file could cause a valid certificate to be considered invalid.

Will cause the Puppet run to fail if:

- an invalid certificate is detected
- an invalid RSA key is detected
- the certificate does not match the key, i.e. the certificate
  has not been signed by the supplied key

The test certificates I've used in the spec tests were generated using
the Go standard library:

    $ go run $GOROOT/src/crypto/tls/generate_cert.go -host localhost

Example output:

    ==> cache-1.router: Error: Not a valid RSA key: Neither PUB key nor PRIV key:: nested asn1 error at /var/govuk/puppet/modules/nginx/manifests/config/ssl.pp:30 on node cache-1.router.dev.gov.uk
2016-01-08 11:09:45 +00:00

47 lines
1.2 KiB
Ruby

module Puppet::Parser::Functions
newfunction(:validate_x509_rsa_key_pair, :doc => <<-ENDHEREDOC
Validates a PEM-formatted X.509 certificate and RSA private key using
OpenSSL. Verifies that the certficate's signature was created from the
supplied key.
Fail compilation if any value fails this check.
validate_x509_rsa_key_pair($cert, $key)
ENDHEREDOC
) do |args|
require 'openssl'
NUM_ARGS = 2 unless defined? NUM_ARGS
unless args.length == NUM_ARGS then
raise Puppet::ParseError,
("validate_x509_rsa_key_pair(): wrong number of arguments (#{args.length}; must be #{NUM_ARGS})")
end
args.each do |arg|
unless arg.is_a?(String)
raise Puppet::ParseError, "#{arg.inspect} is not a string."
end
end
begin
cert = OpenSSL::X509::Certificate.new(args[0])
rescue OpenSSL::X509::CertificateError => e
raise Puppet::ParseError, "Not a valid x509 certificate: #{e}"
end
begin
key = OpenSSL::PKey::RSA.new(args[1])
rescue OpenSSL::PKey::RSAError => e
raise Puppet::ParseError, "Not a valid RSA key: #{e}"
end
unless cert.verify(key)
raise Puppet::ParseError, "Certificate signature does not match supplied key"
end
end
end