vendored/puppet/lib/puppet/ssl/validator/default_validator.rb in bolt-0.20.3 vs vendored/puppet/lib/puppet/ssl/validator/default_validator.rb in bolt-0.20.5

- old
+ new

@@ -7,31 +7,24 @@ # @api private # class Puppet::SSL::Validator::DefaultValidator #< class Puppet::SSL::Validator attr_reader :peer_certs attr_reader :verify_errors - attr_reader :ssl_configuration FIVE_MINUTES_AS_SECONDS = 5 * 60 # Creates a new DefaultValidator, optionally with an SSL Configuration and SSL Host. # - # @param ssl_configuration [Puppet::SSL::Configuration] (a default configuration) ssl_configuration the SSL configuration to use - # @param ssl_host [Puppet::SSL::Host] The SSL host to use + # @param ca_path [String] Filepath for the cacert # # @api private # def initialize( - ssl_configuration = Puppet::SSL::Configuration.new( - Puppet[:localcacert], { - :ca_auth_file => Puppet[:ssl_client_ca_auth] - }), - ssl_host = Puppet.lookup(:ssl_host)) + ca_path = Puppet[:ssl_client_ca_auth] || Puppet[:localcacert]) reset! - @ssl_configuration = ssl_configuration - @ssl_host = ssl_host + @ca_path = ca_path end # Resets this validator to its initial validation state. The ssl configuration is not changed. # @@ -68,11 +61,11 @@ # # @api private # def call(preverify_ok, store_context) current_cert = store_context.current_cert - @peer_certs << Puppet::SSL::Certificate.from_instance(current_cert) + @peer_certs << current_cert # We must make a copy since the scope of the store_context will be lost # across invocations of this method. if preverify_ok # If we've copied all of the certs in the chain out of the SSL library @@ -111,34 +104,55 @@ # Registers the instance's call method with the connection. # # @param [Net::HTTP] connection The connection to validate # + # @param [Puppet::SSL::Host] host The host object containing SSL data # @return [void] # # @api private # - def setup_connection(connection) + def setup_connection(connection, ssl_host = Puppet.lookup(:ssl_host)) if ssl_certificates_are_present? - connection.cert_store = @ssl_host.ssl_store - connection.ca_file = @ssl_configuration.ca_auth_file - connection.cert = @ssl_host.certificate.content - connection.key = @ssl_host.key.content + connection.cert_store = ssl_host.ssl_store + connection.ca_file = @ca_path + connection.cert = ssl_host.certificate.content + connection.key = ssl_host.key.content connection.verify_mode = OpenSSL::SSL::VERIFY_PEER connection.verify_callback = self else connection.verify_mode = OpenSSL::SSL::VERIFY_NONE end end + ## + # Decode a string of concatenated certificates + # + # @return [Array<OpenSSL::X509::Certificate>] + def decode_cert_bundle(bundle_str) + re = /-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m + pem_ary = bundle_str.scan(re) + pem_ary.map do |pem_str| + OpenSSL::X509::Certificate.new(pem_str) + end + end + + # read_file makes testing easier. + def read_file(path) + # https://www.ietf.org/rfc/rfc2459.txt defines the x509 V3 certificate format + # CA bundles are concatenated X509 certificates, but may also include + # comments, which could have UTF-8 characters + Puppet::FileSystem.read(path, :encoding => Encoding::UTF_8) + end + # Validates the peer certificates against the authorized certificates. # # @api private # def valid_peer? - descending_cert_chain = @peer_certs.reverse.map {|c| c.content } - authz_ca_certs = ssl_configuration.ca_auth_certificates + descending_cert_chain = @peer_certs.reverse + authz_ca_certs = decode_cert_bundle(read_file(@ca_path)) if not has_authz_peer_cert(descending_cert_chain, authz_ca_certs) msg = "The server presented a SSL certificate chain which does not include a " << "CA listed in the ssl_client_ca_auth file. " msg << "Authorized Issuers: #{authz_ca_certs.collect {|c| c.subject}.join(', ')} " << @@ -166,8 +180,8 @@ end # @api private # def ssl_certificates_are_present? - Puppet::FileSystem.exist?(Puppet[:hostcert]) && Puppet::FileSystem.exist?(@ssl_configuration.ca_auth_file) + Puppet::FileSystem.exist?(Puppet[:hostcert]) && Puppet::FileSystem.exist?(@ca_path) end end