Method: Puppet::SSL::Verifier#call

Defined in:
lib/puppet/ssl/verifier.rb

#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.

OpenSSL will call this method with the verification result for each cert in the server’s chain, working from the root CA to the server’s cert. If preverify_ok is ‘true`, then that cert passed verification. If it’s ‘false` then the current verification error is contained in `store_context.error`. and the current cert is in `store_context.current_cert`.

If this method returns ‘false`, then verification stops and ruby will raise an `OpenSSL::SSL::Error` with “certificate verification failed”. If this method returns `true`, then verification continues.

If this method ignores a verification error, such as the cert’s CRL will be valid within the next 5 minutes, then this method may be called with a different verification error for the same cert.

WARNING: If ‘store_context.error` returns `OpenSSL::X509::V_OK`, don’t assume verification passed. Ruby 2.4+ implements certificate hostname checking by default, and if the cert doesn’t match the hostname, then the error will be V_OK. Always use ‘preverify_ok` to determine if verification succeeded or not.

Parameters:

  • preverify_ok (Boolean)

    if ‘true` the current certificate in `store_context` was verified. Otherwise, check for the current error in `store_context.error`

  • store_context (OpenSSL::X509::StoreContext)

    The context holding the verification result for one certificate

Returns:

  • (Boolean)

    If ‘true`, continue verifying the chain, even if that means ignoring the current verification error. If `false`, abort the connection.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/puppet/ssl/verifier.rb', line 104

def call(preverify_ok, store_context)
  return true if preverify_ok

  peer_cert = store_context.current_cert

  case store_context.error
  when OpenSSL::X509::V_OK
    # 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 peer_cert && chain_cert && peer_cert.to_der == chain_cert.to_der && !OpenSSL::SSL.verify_certificate_identity(peer_cert, @hostname)
      @last_error = Puppet::SSL::CertMismatchError.new(peer_cert, @hostname)
      return false
    end

  # ruby-openssl#74ef8c0cc56b840b772240f2ee2b0fc0aafa2743 now sets the
  # store_context error when the cert is mismatched
  when OpenSSL::X509::V_ERR_HOSTNAME_MISMATCH
    @last_error = Puppet::SSL::CertMismatchError.new(peer_cert, @hostname)
    return false

  when OpenSSL::X509::V_ERR_CRL_NOT_YET_VALID
    crl = store_context.current_crl
    if crl && 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}")
      return true
    end
  end

  # TRANSLATORS: `error` is an untranslated message from openssl describing why a certificate in the server's chain is invalid, and `subject` is the identity/name of the failed certificate
  @last_error = Puppet::SSL::CertVerifyError.new(
    _("certificate verify failed [%{error} for %{subject}]") %
    { error: store_context.error_string, subject: peer_cert.subject.to_utf8 },
    store_context.error, peer_cert
  )
  false
end