Class: Puppet::SSL::Validator::DefaultValidator Deprecated Private
- Defined in:
- lib/puppet/ssl/validator/default_validator.rb
Overview
This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.
Perform peer certificate verification against the known CA. If there is no CA information known, then no verification is performed
Constant Summary collapse
- FIVE_MINUTES_AS_SECONDS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
5 * 60
Instance Attribute Summary collapse
- #last_error ⇒ Object readonly private
-
#peer_certs ⇒ Object
readonly
private
< class Puppet::SSL::Validator.
- #verify_errors ⇒ Object readonly private
Instance Method Summary collapse
-
#call(preverify_ok, store_context) ⇒ Boolean
private
Performs verification of the SSL connection and collection of the certificates for use in constructing the error message if the verification failed.
-
#decode_cert_bundle(bundle_str) ⇒ Array<OpenSSL::X509::Certificate>
private
Decode a string of concatenated certificates.
-
#has_authz_peer_cert(peer_certs, authz_certs) ⇒ Boolean
private
Checks if the set of peer_certs contains at least one certificate issued by a certificate listed in authz_certs.
-
#initialize(ca_path = Puppet[:ssl_client_ca_auth] || Puppet[:localcacert]) ⇒ DefaultValidator
constructor
private
Creates a new DefaultValidator, optionally with an SSL Configuration and SSL Host.
-
#read_file(path) ⇒ Object
private
read_file makes testing easier.
-
#reset! ⇒ Object
private
Resets this validator to its initial validation state.
-
#setup_connection(connection, ssl_host = Puppet.lookup(:ssl_host)) ⇒ void
private
Registers the instance’s call method with the connection.
- #ssl_certificates_are_present? ⇒ Boolean private
-
#valid_peer? ⇒ Boolean
private
Validates the peer certificates against the authorized certificates.
Constructor Details
#initialize(ca_path = Puppet[:ssl_client_ca_auth] || Puppet[:localcacert]) ⇒ DefaultValidator
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Creates a new DefaultValidator, optionally with an SSL Configuration and SSL Host.
23 24 25 26 27 28 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 23 def initialize( ca_path = Puppet[:ssl_client_ca_auth] || Puppet[:localcacert]) reset! @ca_path = ca_path end |
Instance Attribute Details
#last_error ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
13 14 15 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 13 def last_error @last_error end |
#peer_certs ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
< class Puppet::SSL::Validator
11 12 13 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 11 def peer_certs @peer_certs end |
#verify_errors ⇒ Object (readonly)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
12 13 14 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 12 def verify_errors @verify_errors end |
Instance Method Details
#call(preverify_ok, store_context) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Performs verification of the SSL connection and collection of the certificates for use in constructing the error message if the verification failed. This callback will be executed once for each certificate in a chain being verified.
From the [OpenSSL documentation](www.openssl.org/docs/ssl/SSL_CTX_set_verify.html): The ‘verify_callback` function is used to control the behaviour when the SSL_VERIFY_PEER flag is set. It must be supplied by the application and receives two arguments: preverify_ok indicates, whether the verification of the certificate in question was passed (preverify_ok=1) or not (preverify_ok=0). x509_store_ctx is a pointer to the complete context used for the certificate chain verification.
See Network::HTTP::Connection for more information and where this class is intended to be used.
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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 68 def call(preverify_ok, store_context) current_cert = store_context.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 if @peer_certs.length == store_context.chain.length # (#20027) The peer cert must be issued by a specific authority preverify_ok = valid_peer? end else error = store_context.error || 0 error_string = store_context.error_string || "OpenSSL error #{error}" case error when OpenSSL::X509::V_OK if @hostname # chain is from leaf to root, opposite of the order that `call` is invoked chain_cert = store_context.chain.first # ruby 2.4 doesn't compare certs based on value, so force to DER byte array if current_cert && chain_cert && current_cert.to_der == chain_cert.to_der && !OpenSSL::SSL.verify_certificate_identity(current_cert, @hostname) @last_error = Puppet::SSL::CertMismatchError.new(current_cert, @hostname) return false else @verify_errors << "#{error_string} for #{current_cert.subject.to_utf8}" end else @verify_errors << "#{error_string} for #{current_cert.subject.to_utf8}" end when OpenSSL::X509::V_ERR_CRL_NOT_YET_VALID # current_crl can be nil # https://github.com/ruby/ruby/blob/ruby_1_9_3/ext/openssl/ossl_x509store.c#L501-L510 crl = store_context.current_crl if crl if crl.last_update && crl.last_update < Time.now + FIVE_MINUTES_AS_SECONDS Puppet.debug("Ignoring CRL not yet valid, current time #{Time.now.utc}, CRL last updated #{crl.last_update.utc}") preverify_ok = true else @verify_errors << "#{error_string} for #{crl.issuer.to_utf8}" end else @verify_errors << error_string end else @verify_errors << "#{error_string} for #{current_cert.subject.to_utf8}" end end preverify_ok rescue => ex @verify_errors << ex. false end |
#decode_cert_bundle(bundle_str) ⇒ Array<OpenSSL::X509::Certificate>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Decode a string of concatenated certificates
153 154 155 156 157 158 159 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 153 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 |
#has_authz_peer_cert(peer_certs, authz_certs) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Checks if the set of peer_certs contains at least one certificate issued by a certificate listed in authz_certs
196 197 198 199 200 201 202 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 196 def has_authz_peer_cert(peer_certs, authz_certs) peer_certs.any? do |peer_cert| authz_certs.any? do |authz_cert| peer_cert.verify(authz_cert.public_key) end end end |
#read_file(path) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
read_file makes testing easier.
162 163 164 165 166 167 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 162 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 |
#reset! ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Resets this validator to its initial validation state. The ssl configuration is not changed.
35 36 37 38 39 40 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 35 def reset! @peer_certs = [] @verify_errors = [] @hostname = nil @last_error = nil end |
#setup_connection(connection, ssl_host = Puppet.lookup(:ssl_host)) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Registers the instance’s call method with the connection.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 134 def setup_connection(connection, ssl_host = Puppet.lookup(:ssl_host)) @hostname = connection.address if ssl_certificates_are_present? 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 |
#ssl_certificates_are_present? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
206 207 208 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 206 def ssl_certificates_are_present? Puppet::FileSystem.exist?(Puppet[:hostcert]) && Puppet::FileSystem.exist?(@ca_path) end |
#valid_peer? ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Validates the peer certificates against the authorized certificates.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/puppet/ssl/validator/default_validator.rb', line 173 def valid_peer? 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.to_utf8}.join(', ')} " << "Peer Chain: #{descending_cert_chain.collect {|c| c.subject.to_utf8}.join(' => ')}" @verify_errors << msg false else true end end |