Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/common/tls/ssl_handshaker.cc
Line
Count
Source (jump to first uncovered line)
1
#include "source/common/tls/ssl_handshaker.h"
2
3
#include "envoy/stats/scope.h"
4
5
#include "source/common/common/assert.h"
6
#include "source/common/common/empty_string.h"
7
#include "source/common/http/headers.h"
8
#include "source/common/runtime/runtime_features.h"
9
#include "source/common/tls/context_impl.h"
10
#include "source/common/tls/utility.h"
11
12
using Envoy::Network::PostIoAction;
13
14
namespace Envoy {
15
namespace Extensions {
16
namespace TransportSockets {
17
namespace Tls {
18
19
0
void ValidateResultCallbackImpl::onSslHandshakeCancelled() { extended_socket_info_.reset(); }
20
21
void ValidateResultCallbackImpl::onCertValidationResult(bool succeeded,
22
                                                        Ssl::ClientValidationStatus detailed_status,
23
                                                        const std::string& /*error_details*/,
24
0
                                                        uint8_t tls_alert) {
25
0
  if (!extended_socket_info_.has_value()) {
26
0
    return;
27
0
  }
28
0
  extended_socket_info_->setCertificateValidationStatus(detailed_status);
29
0
  extended_socket_info_->setCertificateValidationAlert(tls_alert);
30
0
  extended_socket_info_->onCertificateValidationCompleted(succeeded, true);
31
0
}
32
33
0
void CertificateSelectionCallbackImpl::onSslHandshakeCancelled() { extended_socket_info_.reset(); }
34
35
void CertificateSelectionCallbackImpl::onCertificateSelectionResult(
36
0
    OptRef<const Ssl::TlsContext> selected_ctx, bool staple) {
37
0
  if (!extended_socket_info_.has_value()) {
38
0
    return;
39
0
  }
40
0
  extended_socket_info_->onCertificateSelectionCompleted(selected_ctx, staple, true);
41
0
}
42
43
0
SslExtendedSocketInfoImpl::~SslExtendedSocketInfoImpl() {
44
0
  if (cert_validate_result_callback_.has_value()) {
45
0
    cert_validate_result_callback_->onSslHandshakeCancelled();
46
0
  }
47
0
  if (cert_selection_callback_.has_value()) {
48
0
    cert_selection_callback_->onSslHandshakeCancelled();
49
0
  }
50
0
}
51
52
void SslExtendedSocketInfoImpl::setCertificateValidationStatus(
53
0
    Envoy::Ssl::ClientValidationStatus validated) {
54
0
  certificate_validation_status_ = validated;
55
0
}
56
57
0
Envoy::Ssl::ClientValidationStatus SslExtendedSocketInfoImpl::certificateValidationStatus() const {
58
0
  return certificate_validation_status_;
59
0
}
60
61
0
void SslExtendedSocketInfoImpl::onCertificateValidationCompleted(bool succeeded, bool async) {
62
0
  cert_validation_result_ =
63
0
      succeeded ? Ssl::ValidateStatus::Successful : Ssl::ValidateStatus::Failed;
64
0
  if (cert_validate_result_callback_.has_value()) {
65
0
    cert_validate_result_callback_.reset();
66
    // Resume handshake.
67
0
    if (async) {
68
0
      ssl_handshaker_.handshakeCallbacks()->onAsynchronousCertValidationComplete();
69
0
    }
70
0
  }
71
0
}
72
73
0
Ssl::ValidateResultCallbackPtr SslExtendedSocketInfoImpl::createValidateResultCallback() {
74
0
  auto callback = std::make_unique<ValidateResultCallbackImpl>(
75
0
      ssl_handshaker_.handshakeCallbacks()->connection().dispatcher(), *this);
76
0
  cert_validate_result_callback_ = *callback;
77
0
  cert_validation_result_ = Ssl::ValidateStatus::Pending;
78
0
  return callback;
79
0
}
80
81
void SslExtendedSocketInfoImpl::onCertificateSelectionCompleted(
82
0
    OptRef<const Ssl::TlsContext> selected_ctx, bool staple, bool async) {
83
0
  RELEASE_ASSERT(cert_selection_result_ == Ssl::CertificateSelectionStatus::Pending,
84
0
                 "onCertificateSelectionCompleted twice");
85
0
  if (!selected_ctx.has_value()) {
86
0
    cert_selection_result_ = Ssl::CertificateSelectionStatus::Failed;
87
0
  } else {
88
0
    cert_selection_result_ = Ssl::CertificateSelectionStatus::Successful;
89
    // Apply the selected context. This must be done before OCSP stapling below
90
    // since applying the context can remove the previously-set OCSP response.
91
    // This will only return NULL if memory allocation fails.
92
0
    RELEASE_ASSERT(SSL_set_SSL_CTX(ssl_handshaker_.ssl(), selected_ctx->ssl_ctx_.get()) != nullptr,
93
0
                   "");
94
95
0
    if (staple) {
96
      // We avoid setting the OCSP response if the client didn't request it, but doing so is safe.
97
0
      RELEASE_ASSERT(selected_ctx->ocsp_response_,
98
0
                     "OCSP response must be present under OcspStapleAction::Staple");
99
0
      const std::vector<uint8_t>& resp_bytes = selected_ctx->ocsp_response_->rawBytes();
100
0
      const int rc =
101
0
          SSL_set_ocsp_response(ssl_handshaker_.ssl(), resp_bytes.data(), resp_bytes.size());
102
0
      RELEASE_ASSERT(rc != 0, "");
103
0
    }
104
0
  }
105
0
  if (cert_selection_callback_.has_value()) {
106
0
    cert_selection_callback_.reset();
107
    // Resume handshake.
108
0
    if (async) {
109
0
      ssl_handshaker_.handshakeCallbacks()->onAsynchronousCertificateSelectionComplete();
110
0
    }
111
0
  }
112
0
}
113
114
Ssl::CertificateSelectionCallbackPtr
115
0
SslExtendedSocketInfoImpl::createCertificateSelectionCallback() {
116
0
  auto callback = std::make_unique<CertificateSelectionCallbackImpl>(
117
0
      ssl_handshaker_.handshakeCallbacks()->connection().dispatcher(), *this);
118
0
  cert_selection_callback_ = *callback;
119
0
  cert_selection_result_ = Ssl::CertificateSelectionStatus::Pending;
120
0
  return callback;
121
0
}
122
123
SslHandshakerImpl::SslHandshakerImpl(bssl::UniquePtr<SSL> ssl, int ssl_extended_socket_info_index,
124
                                     Ssl::HandshakeCallbacks* handshake_callbacks)
125
    : ssl_(std::move(ssl)), handshake_callbacks_(handshake_callbacks),
126
0
      extended_socket_info_(*this) {
127
0
  SSL_set_ex_data(ssl_.get(), ssl_extended_socket_info_index, &(this->extended_socket_info_));
128
0
}
129
130
0
bool SslHandshakerImpl::peerCertificateValidated() const {
131
0
  return extended_socket_info_.certificateValidationStatus() ==
132
0
         Envoy::Ssl::ClientValidationStatus::Validated;
133
0
}
134
135
0
Network::PostIoAction SslHandshakerImpl::doHandshake() {
136
0
  ASSERT(state_ != Ssl::SocketState::HandshakeComplete && state_ != Ssl::SocketState::ShutdownSent);
137
0
  int rc = SSL_do_handshake(ssl());
138
0
  if (rc == 1) {
139
0
    state_ = Ssl::SocketState::HandshakeComplete;
140
0
    handshake_callbacks_->onSuccess(ssl());
141
142
    // It's possible that we closed during the handshake callback.
143
0
    return handshake_callbacks_->connection().state() == Network::Connection::State::Open
144
0
               ? PostIoAction::KeepOpen
145
0
               : PostIoAction::Close;
146
0
  } else {
147
0
    int err = SSL_get_error(ssl(), rc);
148
0
    ENVOY_CONN_LOG(trace, "ssl error occurred while read: {}", handshake_callbacks_->connection(),
149
0
                   Utility::getErrorDescription(err));
150
0
    switch (err) {
151
0
    case SSL_ERROR_WANT_READ:
152
0
    case SSL_ERROR_WANT_WRITE:
153
0
      return PostIoAction::KeepOpen;
154
0
    case SSL_ERROR_PENDING_CERTIFICATE:
155
0
    case SSL_ERROR_WANT_PRIVATE_KEY_OPERATION:
156
0
    case SSL_ERROR_WANT_CERTIFICATE_VERIFY:
157
0
      state_ = Ssl::SocketState::HandshakeInProgress;
158
0
      return PostIoAction::KeepOpen;
159
0
    default:
160
0
      handshake_callbacks_->onFailure();
161
0
      return PostIoAction::Close;
162
0
    }
163
0
  }
164
0
}
165
166
} // namespace Tls
167
} // namespace TransportSockets
168
} // namespace Extensions
169
} // namespace Envoy