Coverage Report

Created: 2026-05-11 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/ssl/ssl_buffer.cc
Line
Count
Source
1
// Copyright 2015 The BoringSSL Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <openssl/ssl.h>
16
17
#include <assert.h>
18
#include <limits.h>
19
#include <stdlib.h>
20
#include <string.h>
21
22
#include <openssl/bio.h>
23
#include <openssl/err.h>
24
#include <openssl/mem.h>
25
26
#include "../crypto/internal.h"
27
#include "internal.h"
28
29
30
BSSL_NAMESPACE_BEGIN
31
32
// BIO uses int instead of size_t. No lengths will exceed uint16_t, so this will
33
// not overflow.
34
static_assert(0xffff <= INT_MAX, "uint16_t does not fit in int");
35
36
static_assert((SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) == 0,
37
              "SSL3_ALIGN_PAYLOAD must be a power of 2");
38
39
2.50M
void SSLBuffer::Clear() {
40
2.50M
  if (buf_ != inline_buf_) {
41
2.47M
    free(buf_);  // Allocated with malloc().
42
2.47M
  }
43
2.50M
  buf_ = nullptr;
44
2.50M
  offset_ = 0;
45
2.50M
  size_ = 0;
46
2.50M
  cap_ = 0;
47
2.50M
}
48
49
1.30M
bool SSLBuffer::EnsureCap(size_t header_len, size_t new_cap) {
50
1.30M
  if (new_cap > 0xffff) {
51
0
    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
52
0
    return false;
53
0
  }
54
55
1.30M
  if (cap_ >= new_cap) {
56
0
    return true;
57
0
  }
58
59
1.30M
  uint8_t *new_buf;
60
1.30M
  size_t new_offset;
61
1.30M
  if (new_cap <= sizeof(inline_buf_)) {
62
    // This function is called twice per TLS record, first for the five-byte
63
    // header. To avoid allocating twice, use an inline buffer for short inputs.
64
575k
    new_buf = inline_buf_;
65
575k
    new_offset = 0;
66
734k
  } else {
67
    // Add up to |SSL3_ALIGN_PAYLOAD| - 1 bytes of slack for alignment.
68
    //
69
    // Since this buffer gets allocated quite frequently and doesn't contain any
70
    // sensitive data, we allocate with malloc rather than |OPENSSL_malloc| and
71
    // avoid zeroing on free.
72
734k
    new_buf = (uint8_t *)malloc(new_cap + SSL3_ALIGN_PAYLOAD - 1);
73
734k
    if (new_buf == nullptr) {
74
0
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
75
0
      return false;
76
0
    }
77
78
    // Offset the buffer such that the record body is aligned.
79
734k
    new_offset =
80
734k
        (0 - header_len - (uintptr_t)new_buf) & (SSL3_ALIGN_PAYLOAD - 1);
81
734k
  }
82
83
  // Note if the both old and new buffer are inline, the source and destination
84
  // may alias.
85
1.30M
  OPENSSL_memmove(new_buf + new_offset, buf_ + offset_, size_);
86
87
1.30M
  if (buf_ != inline_buf_) {
88
761k
    free(buf_);  // Allocated with malloc().
89
761k
  }
90
91
1.30M
  buf_ = new_buf;
92
1.30M
  offset_ = new_offset;
93
1.30M
  cap_ = new_cap;
94
1.30M
  return true;
95
1.30M
}
96
97
1.29M
void SSLBuffer::DidWrite(size_t new_size) {
98
1.29M
  if (new_size > cap() - size()) {
99
0
    abort();
100
0
  }
101
1.29M
  size_ += new_size;
102
1.29M
}
103
104
758k
void SSLBuffer::Consume(size_t len) {
105
758k
  if (len > size_) {
106
0
    abort();
107
0
  }
108
758k
  offset_ += (uint16_t)len;
109
758k
  size_ -= (uint16_t)len;
110
758k
  cap_ -= (uint16_t)len;
111
758k
}
112
113
3.34M
void SSLBuffer::DiscardConsumed() {
114
3.34M
  if (size_ == 0) {
115
2.23M
    Clear();
116
2.23M
  }
117
3.34M
}
118
119
169k
static int dtls_read_buffer_next_packet(SSL *ssl) {
120
169k
  SSLBuffer *buf = &ssl->s3->read_buffer;
121
122
169k
  if (!buf->empty()) {
123
    // It is an error to call |dtls_read_buffer_extend| when the read buffer is
124
    // not empty.
125
0
    OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
126
0
    return -1;
127
0
  }
128
129
  // Read a single packet from |ssl->rbio|. |buf->cap()| must fit in an int.
130
169k
  int ret =
131
169k
      BIO_read(ssl->rbio.get(), buf->data(), static_cast<int>(buf->cap()));
132
169k
  if (ret <= 0) {
133
7.28k
    ssl->s3->rwstate = SSL_ERROR_WANT_READ;
134
7.28k
    return ret;
135
7.28k
  }
136
162k
  buf->DidWrite(static_cast<size_t>(ret));
137
162k
  return 1;
138
169k
}
139
140
1.12M
static int tls_read_buffer_extend_to(SSL *ssl, size_t len) {
141
1.12M
  SSLBuffer *buf = &ssl->s3->read_buffer;
142
143
1.12M
  if (len > buf->cap()) {
144
0
    OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
145
0
    return -1;
146
0
  }
147
148
  // Read until the target length is reached.
149
2.24M
  while (buf->size() < len) {
150
    // The amount of data to read is bounded by |buf->cap|, which must fit in an
151
    // int.
152
1.12M
    int ret = BIO_read(ssl->rbio.get(), buf->data() + buf->size(),
153
1.12M
                       static_cast<int>(len - buf->size()));
154
1.12M
    if (ret <= 0) {
155
7.32k
      ssl->s3->rwstate = SSL_ERROR_WANT_READ;
156
7.32k
      return ret;
157
7.32k
    }
158
1.11M
    buf->DidWrite(static_cast<size_t>(ret));
159
1.11M
  }
160
161
1.11M
  return 1;
162
1.12M
}
163
164
1.29M
int ssl_read_buffer_extend_to(SSL *ssl, size_t len) {
165
  // |ssl_read_buffer_extend_to| implicitly discards any consumed data.
166
1.29M
  ssl->s3->read_buffer.DiscardConsumed();
167
168
1.29M
  if (SSL_is_dtls(ssl)) {
169
169k
    static_assert(
170
169k
        DTLS1_RT_MAX_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH <= 0xffff,
171
169k
        "DTLS read buffer is too large");
172
173
    // The |len| parameter is ignored in DTLS.
174
169k
    len = DTLS1_RT_MAX_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH;
175
169k
  }
176
177
  // The DTLS record header can have a variable length, so the |header_len|
178
  // value provided for buffer alignment only works if the header is the maximum
179
  // length.
180
1.29M
  if (!ssl->s3->read_buffer.EnsureCap(DTLS1_RT_MAX_HEADER_LENGTH, len)) {
181
0
    return -1;
182
0
  }
183
184
1.29M
  if (ssl->rbio == nullptr) {
185
0
    OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
186
0
    return -1;
187
0
  }
188
189
1.29M
  int ret;
190
1.29M
  if (SSL_is_dtls(ssl)) {
191
    // |len| is ignored for a datagram transport.
192
169k
    ret = dtls_read_buffer_next_packet(ssl);
193
1.12M
  } else {
194
1.12M
    ret = tls_read_buffer_extend_to(ssl, len);
195
1.12M
  }
196
197
1.29M
  if (ret <= 0) {
198
    // If the buffer was empty originally and remained empty after attempting to
199
    // extend it, release the buffer until the next attempt.
200
14.6k
    ssl->s3->read_buffer.DiscardConsumed();
201
14.6k
  }
202
1.29M
  return ret;
203
1.29M
}
204
205
int ssl_handle_open_record(SSL *ssl, bool *out_retry, ssl_open_record_t ret,
206
2.04M
                           size_t consumed, uint8_t alert) {
207
2.04M
  *out_retry = false;
208
2.04M
  if (ret != ssl_open_record_partial) {
209
746k
    ssl->s3->read_buffer.Consume(consumed);
210
746k
  }
211
2.04M
  if (ret != ssl_open_record_success) {
212
    // Nothing was returned to the caller, so discard anything marked consumed.
213
1.43M
    ssl->s3->read_buffer.DiscardConsumed();
214
1.43M
  }
215
2.04M
  switch (ret) {
216
602k
    case ssl_open_record_success:
217
602k
      return 1;
218
219
1.29M
    case ssl_open_record_partial: {
220
1.29M
      int read_ret = ssl_read_buffer_extend_to(ssl, consumed);
221
1.29M
      if (read_ret <= 0) {
222
14.6k
        return read_ret;
223
14.6k
      }
224
1.27M
      *out_retry = true;
225
1.27M
      return 1;
226
1.29M
    }
227
228
139k
    case ssl_open_record_discard:
229
139k
      *out_retry = true;
230
139k
      return 1;
231
232
104
    case ssl_open_record_close_notify:
233
104
      ssl->s3->rwstate = SSL_ERROR_ZERO_RETURN;
234
104
      return 0;
235
236
4.61k
    case ssl_open_record_error:
237
4.61k
      if (alert != 0) {
238
4.45k
        ssl_send_alert(ssl, SSL3_AL_FATAL, alert);
239
4.45k
      }
240
4.61k
      return -1;
241
2.04M
  }
242
2.04M
  assert(0);
243
0
  return -1;
244
0
}
245
246
247
static_assert(SSL3_RT_HEADER_LENGTH * 2 +
248
                      SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD * 2 +
249
                      SSL3_RT_MAX_PLAIN_LENGTH <=
250
                  0xffff,
251
              "maximum TLS write buffer is too large");
252
253
static_assert(DTLS1_RT_MAX_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD +
254
                      SSL3_RT_MAX_PLAIN_LENGTH <=
255
                  0xffff,
256
              "maximum DTLS write buffer is too large");
257
258
23.0k
static int tls_write_buffer_flush(SSL *ssl) {
259
23.0k
  SSLBuffer *buf = &ssl->s3->write_buffer;
260
261
34.6k
  while (!buf->empty()) {
262
11.5k
    int ret = BIO_write(ssl->wbio.get(), buf->data(), buf->size());
263
11.5k
    if (ret <= 0) {
264
0
      ssl->s3->rwstate = SSL_ERROR_WANT_WRITE;
265
0
      return ret;
266
0
    }
267
11.5k
    buf->Consume(static_cast<size_t>(ret));
268
11.5k
  }
269
23.0k
  buf->Clear();
270
23.0k
  return 1;
271
23.0k
}
272
273
4.67k
static int dtls_write_buffer_flush(SSL *ssl) {
274
4.67k
  SSLBuffer *buf = &ssl->s3->write_buffer;
275
4.67k
  if (buf->empty()) {
276
0
    return 1;
277
0
  }
278
279
4.67k
  int ret = BIO_write(ssl->wbio.get(), buf->data(), buf->size());
280
4.67k
  if (ret <= 0) {
281
0
    ssl->s3->rwstate = SSL_ERROR_WANT_WRITE;
282
    // If the write failed, drop the write buffer anyway. Datagram transports
283
    // can't write half a packet, so the caller is expected to retry from the
284
    // top.
285
0
    buf->Clear();
286
0
    return ret;
287
0
  }
288
4.67k
  buf->Clear();
289
4.67k
  return 1;
290
4.67k
}
291
292
27.7k
int ssl_write_buffer_flush(SSL *ssl) {
293
27.7k
  if (ssl->wbio == nullptr) {
294
0
    OPENSSL_PUT_ERROR(SSL, SSL_R_BIO_NOT_SET);
295
0
    return -1;
296
0
  }
297
298
27.7k
  if (SSL_is_dtls(ssl)) {
299
4.67k
    return dtls_write_buffer_flush(ssl);
300
23.0k
  } else {
301
23.0k
    return tls_write_buffer_flush(ssl);
302
23.0k
  }
303
27.7k
}
304
305
BSSL_NAMESPACE_END