Coverage Report

Created: 2026-08-28 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/cipher/internal.h
Line
Count
Source
1
// Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
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
#ifndef OPENSSL_HEADER_CRYPTO_FIPSMODULE_CIPHER_INTERNAL_H
16
#define OPENSSL_HEADER_CRYPTO_FIPSMODULE_CIPHER_INTERNAL_H
17
18
#include <openssl/base.h>
19
20
#include <openssl/aead.h>
21
#include <openssl/aes.h>
22
#include <openssl/span.h>
23
24
#include "../../internal.h"
25
#include "../../mem_internal.h"
26
#include "../aes/internal.h"
27
28
#include <algorithm>
29
#include <functional>
30
#include <optional>
31
#include <type_traits>
32
33
extern "C" {
34
35
36
// EVP_CIPH_MODE_MASK contains the bits of `flags` that represent the mode.
37
169k
#define EVP_CIPH_MODE_MASK 0x3f
38
39
// EVP_AEAD represents a specific AEAD algorithm.
40
struct evp_aead_st {
41
  uint8_t key_len;
42
  uint8_t nonce_len;
43
  uint8_t overhead;
44
  uint8_t max_tag_len;
45
46
  // init initialises an `EVP_AEAD_CTX`. If this call returns zero then
47
  // `cleanup` will not be called for that context.
48
  int (*init)(EVP_AEAD_CTX *, const uint8_t *key, size_t key_len,
49
              size_t tag_len);
50
  int (*init_with_direction)(EVP_AEAD_CTX *, const uint8_t *key, size_t key_len,
51
                             size_t tag_len, enum evp_aead_direction_t dir);
52
  void (*cleanup)(EVP_AEAD_CTX *);
53
54
  // AEADs need to provide one of the following sets of methods:
55
  //
56
  // - openv + sealv: variable tag length AEAD.
57
  // - openv_detached + sealv: fixed tag length AEAD.
58
59
  int (*openv)(const EVP_AEAD_CTX *ctx, bssl::Span<const CRYPTO_IOVEC> iovecs,
60
               size_t *out_total_bytes, bssl::Span<const uint8_t> nonce,
61
               bssl::Span<const CRYPTO_IVEC> aadvecs);
62
63
  int (*sealv)(const EVP_AEAD_CTX *ctx, bssl::Span<const CRYPTO_IOVEC> iovecs,
64
               bssl::Span<uint8_t> out_tag, size_t *out_tag_len,
65
               bssl::Span<const uint8_t> nonce,
66
               bssl::Span<const CRYPTO_IVEC> aadvecs);
67
68
  int (*openv_detached)(const EVP_AEAD_CTX *ctx,
69
                        bssl::Span<const CRYPTO_IOVEC> iovecs,
70
                        bssl::Span<const uint8_t> nonce,
71
                        bssl::Span<const uint8_t> in_tag,
72
                        bssl::Span<const CRYPTO_IVEC> aadvecs);
73
74
  int (*get_iv)(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
75
                size_t *out_len);
76
77
  size_t (*tag_len)(const EVP_AEAD_CTX *ctx, size_t in_len);
78
};
79
80
struct evp_cipher_st {
81
  // type contains a NID identifying the cipher. (e.g. NID_aes_128_gcm.)
82
  int nid;
83
84
  // block_size contains the block size, in bytes, of the cipher, or 1 for a
85
  // stream cipher.
86
  unsigned block_size;
87
88
  // key_len contains the key size, in bytes, for the cipher. If the cipher
89
  // takes a variable key size then this contains the default size.
90
  unsigned key_len;
91
92
  // iv_len contains the IV size, in bytes, or zero if inapplicable.
93
  unsigned iv_len;
94
95
  // ctx_size contains the size, in bytes, of the per-key context for this
96
  // cipher.
97
  unsigned ctx_size;
98
99
  // flags contains the OR of a number of flags. See `EVP_CIPH_*`.
100
  uint32_t flags;
101
102
  int (*init)(EVP_CIPHER_CTX *ctx, const uint8_t *key, const uint8_t *iv,
103
              int enc);
104
105
  // cipher encrypts/decrypts `in`, write output to `out`. Writes exactly `len`
106
  // bytes, which must be a multiple of the `block_size`.
107
  //
108
  // For ciphers where encryption and decryption operations differ, `init`
109
  // shall set an internal state for this.
110
  //
111
  // Returns 1 on success, or 0 on error.
112
  int (*cipher_update)(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
113
                       size_t len);
114
115
  // cipher_final finalizes the cipher, performing possible final
116
  // authentication checks.
117
  //
118
  // Only used for `EVP_CIPH_FLAG_CUSTOM_CIPHER` ciphers.
119
  //
120
  // Returns 1 on success, or 0 on error. When decrypting, if an error is
121
  // returned, the decrypted data must not be used.
122
  int (*cipher_final)(EVP_CIPHER_CTX *ctx);
123
124
  // update_aad adds `in` (of length `inl`) to the authenticated data for the
125
  // encryption operation.
126
  //
127
  // Only used for `EVP_CIPH_FLAG_CUSTOM_CIPHER` ciphers.
128
  //
129
  // Returns 1 on success, or 0 on error.
130
  int (*update_aad)(EVP_CIPHER_CTX *ctx, const uint8_t *in, size_t inl);
131
132
  // cleanup, if non-NULL, releases memory associated with the context. It is
133
  // called if `EVP_CTRL_INIT` succeeds. Note that `init` may not have been
134
  // called at this point.
135
  void (*cleanup)(EVP_CIPHER_CTX *);
136
137
  int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr);
138
};
139
140
}  // extern C
141
142
BSSL_NAMESPACE_BEGIN
143
144
// CopySpan copies an entire span of bytes from `from` to `to`.
145
//
146
// The spans need to have the same length.
147
12.3k
inline void CopySpan(Span<const uint8_t> from, Span<uint8_t> to) {
148
12.3k
  BSSL_CHECK(from.size() == to.size());
149
12.3k
  std::copy(from.begin(), from.end(), to.begin());
150
12.3k
}
151
152
// CopyToPrefix copies a span of bytes from `from` into `to`. It aborts
153
// if there is not enough space.
154
//
155
// TODO(crbug.com/404286922): Can we simplify this in a C++20 world (e.g.
156
// std::ranges::copy)? Must preserve range checking on the destination span.
157
11.0k
inline void CopyToPrefix(Span<const uint8_t> from, Span<uint8_t> to) {
158
11.0k
  CopySpan(from, to.first(from.size()));
159
11.0k
}
160
161
// Generic CRYPTO_IOVEC/CRYPTO_IVEC helpers.
162
namespace iovec {
163
164
// IsValid returns whether the given `CRYPTO_IVEC` or `CRYPTO_IOVEC` is
165
// valid for use with public APIs, i.e. does not contain more than `SIZE_MAX`
166
// bytes. Note that the `EVP_AEAD` methods need to accept an arbitrary number
167
// of chunks.
168
template <typename IVec>
169
18.9k
inline bool IsValid(Span<IVec> ivecs) {
170
18.9k
  size_t allowed = SIZE_MAX;
171
19.6k
  for (const IVec &ivec : ivecs) {
172
19.6k
    size_t len = ivec.len;
173
19.6k
    if (len > allowed) {
174
0
      return false;
175
0
    }
176
19.6k
    allowed -= len;
177
19.6k
  }
178
18.9k
  return true;
179
18.9k
}
bool bssl::iovec::IsValid<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>)
Line
Count
Source
169
9.49k
inline bool IsValid(Span<IVec> ivecs) {
170
9.49k
  size_t allowed = SIZE_MAX;
171
10.1k
  for (const IVec &ivec : ivecs) {
172
10.1k
    size_t len = ivec.len;
173
10.1k
    if (len > allowed) {
174
0
      return false;
175
0
    }
176
10.1k
    allowed -= len;
177
10.1k
  }
178
9.49k
  return true;
179
9.49k
}
bool bssl::iovec::IsValid<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>)
Line
Count
Source
169
9.49k
inline bool IsValid(Span<IVec> ivecs) {
170
9.49k
  size_t allowed = SIZE_MAX;
171
9.49k
  for (const IVec &ivec : ivecs) {
172
9.49k
    size_t len = ivec.len;
173
9.49k
    if (len > allowed) {
174
0
      return false;
175
0
    }
176
9.49k
    allowed -= len;
177
9.49k
  }
178
9.49k
  return true;
179
9.49k
}
180
181
// Length returns the total length in bytes of a given `CRYPTO_IVEC` or
182
// `CRYPTO_IOVEC`.
183
template <typename IVec>
184
11.5k
inline size_t TotalLength(Span<IVec> ivecs) {
185
11.5k
  size_t total = 0;
186
11.8k
  for (const IVec &ivec : ivecs) {
187
11.8k
    total += ivec.len;
188
11.8k
  }
189
11.5k
  return total;
190
11.5k
}
unsigned long bssl::iovec::TotalLength<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>)
Line
Count
Source
184
6.45k
inline size_t TotalLength(Span<IVec> ivecs) {
185
6.45k
  size_t total = 0;
186
6.80k
  for (const IVec &ivec : ivecs) {
187
6.80k
    total += ivec.len;
188
6.80k
  }
189
6.45k
  return total;
190
6.45k
}
unsigned long bssl::iovec::TotalLength<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>)
Line
Count
Source
184
5.04k
inline size_t TotalLength(Span<IVec> ivecs) {
185
5.04k
  size_t total = 0;
186
5.04k
  for (const IVec &ivec : ivecs) {
187
5.04k
    total += ivec.len;
188
5.04k
  }
189
5.04k
  return total;
190
5.04k
}
Unexecuted instantiation: unsigned long bssl::iovec::TotalLength<crypto_iovec_st>(bssl::Span<crypto_iovec_st, 18446744073709551615ul>)
191
192
// GetAndRemoveSuffix takes `suffix_buf.size()` final bytes from the given
193
// `CRYPTO_IVEC` or `CRYPTO_IOVEC` (mutating said iovec to no longer contain
194
// those bytes) and returns them.
195
//
196
// If the byte range is contained in a single chunk of `ivecs`, it will just
197
// return that span pointing into `ivecs`; otherwise, it will copy the bytes
198
// into `out` and return that.
199
//
200
// If `ivecs` is too short, returns `nullopt`.
201
template <typename IVec, typename ReadFromT = const uint8_t *,
202
          ReadFromT IVec::*ReadFrom = &IVec::in>
203
inline std::optional<Span<const uint8_t>> GetAndRemoveSuffix(
204
3.55k
    Span<uint8_t> suffix_buf, Span<IVec> ivecs) {
205
  // Get the trivial case out.
206
3.55k
  if (suffix_buf.empty()) {
207
0
    return suffix_buf;
208
0
  }
209
  // Strip trailing zero length chunks.
210
3.55k
  while (!ivecs.empty() && ivecs.back().len == 0) {
211
0
    ivecs = ivecs.first(ivecs.size() - 1);
212
0
  }
213
3.55k
  if (ivecs.empty()) {
214
0
    return std::nullopt;
215
0
  }
216
  // Is the requested chunk entirely contained? If so, just return it.
217
3.55k
  if (ivecs.back().len >= suffix_buf.size()) {
218
3.55k
    ivecs.back().len -= suffix_buf.size();
219
3.55k
    return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size());
220
3.55k
  }
221
  // Otherwise, collect it into the buffer while trimming `ivecs`.
222
0
  Span<uint8_t> remaining = suffix_buf;
223
0
  while (!ivecs.empty()) {
224
0
    Span<const uint8_t> src(ivecs.back().*ReadFrom, ivecs.back().len);
225
0
    if (src.size() >= remaining.size()) {
226
0
      CopySpan(src.last(remaining.size()), remaining);
227
0
      ivecs.back().len -= remaining.size();
228
0
      return suffix_buf;
229
0
    }
230
0
    CopySpan(src, remaining.last(src.size()));
231
0
    remaining = remaining.first(remaining.size() - src.size());
232
0
    ivecs.back().len = 0;
233
0
    ivecs = ivecs.first(ivecs.size() - 1);
234
0
  }
235
0
  return std::nullopt;
236
0
}
Unexecuted instantiation: _ZN4bssl5iovec18GetAndRemoveSuffixI15crypto_iovec_stPKhTnMT_T0_XadL_ZNS2_2inEEEEENSt3__18optionalINS_4SpanIS3_Lm18446744073709551615EEEEENSA_IhLm18446744073709551615EEENSA_IS5_Lm18446744073709551615EEE
_ZN4bssl5iovec18GetAndRemoveSuffixI15crypto_iovec_stPhTnMT_T0_XadL_ZNS2_3outEEEEENSt3__18optionalINS_4SpanIKhLm18446744073709551615EEEEENS9_IhLm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEE
Line
Count
Source
204
3.55k
    Span<uint8_t> suffix_buf, Span<IVec> ivecs) {
205
  // Get the trivial case out.
206
3.55k
  if (suffix_buf.empty()) {
207
0
    return suffix_buf;
208
0
  }
209
  // Strip trailing zero length chunks.
210
3.55k
  while (!ivecs.empty() && ivecs.back().len == 0) {
211
0
    ivecs = ivecs.first(ivecs.size() - 1);
212
0
  }
213
3.55k
  if (ivecs.empty()) {
214
0
    return std::nullopt;
215
0
  }
216
  // Is the requested chunk entirely contained? If so, just return it.
217
3.55k
  if (ivecs.back().len >= suffix_buf.size()) {
218
3.55k
    ivecs.back().len -= suffix_buf.size();
219
3.55k
    return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size());
220
3.55k
  }
221
  // Otherwise, collect it into the buffer while trimming `ivecs`.
222
0
  Span<uint8_t> remaining = suffix_buf;
223
0
  while (!ivecs.empty()) {
224
0
    Span<const uint8_t> src(ivecs.back().*ReadFrom, ivecs.back().len);
225
0
    if (src.size() >= remaining.size()) {
226
0
      CopySpan(src.last(remaining.size()), remaining);
227
0
      ivecs.back().len -= remaining.size();
228
0
      return suffix_buf;
229
0
    }
230
0
    CopySpan(src, remaining.last(src.size()));
231
0
    remaining = remaining.first(remaining.size() - src.size());
232
0
    ivecs.back().len = 0;
233
0
    ivecs = ivecs.first(ivecs.size() - 1);
234
0
  }
235
0
  return std::nullopt;
236
0
}
237
238
// GetAndRemoveOutSuffix is like `GetAndRemoveSuffix` but takes from a
239
// `CRYPTO_IOVEC`'s `out` member instead.
240
inline std::optional<Span<const uint8_t>> GetAndRemoveOutSuffix(
241
3.55k
    Span<uint8_t> out, Span<CRYPTO_IOVEC> iovecs) {
242
3.55k
  return GetAndRemoveSuffix<CRYPTO_IOVEC, /*ReadFromT=*/uint8_t *,
243
3.55k
                            /*ReadFrom=*/&CRYPTO_IOVEC::out>(out, iovecs);
244
3.55k
}
245
246
namespace internal {
247
inline void CopySpanToIOVec(Span<const uint8_t> out, CRYPTO_IOVEC head,
248
0
                            Span<const CRYPTO_IOVEC> rest) {
249
0
  for (;;) {
250
0
    size_t to_copy = std::min(head.len, out.size());
251
0
    CopySpan(out.first(to_copy), Span(head.out, to_copy));
252
0
    out = out.subspan(to_copy);
253
0
    if (out.empty()) {
254
0
      break;
255
0
    }
256
0
    head = rest.front();  // Checkfails if insufficient space in CRYPTO_IOVEC.
257
0
    rest = rest.subspan(1);
258
0
  }
259
0
}
260
}  // namespace internal
261
262
// ForEachBlockRange iterates over the `ivecs` as follows:
263
//
264
// - `f_whole` gets called on whole blocks crossing `ivecs` chunk boundaries, or
265
//   ranges of whole blocks that are entirely in chunks.
266
// - `f` gets called exactly once, on the last block range which may
267
//   end up with a partial block.
268
// - Both functions receive an `in` pointer that either points into `ivecs` or
269
//   into a chunk assembly buffer and a `len` which indicates the number of
270
//   bytes from `in` that can be accessed. If the function returns 0,
271
//   iteration stops.
272
// - If `WriteOut` is set, `f_whole` and `f` receive an extra `out`
273
//   argument to which they can write output. This output will be placed into
274
//   the `ivecs`'s `out` members either during or after the call. If iteration
275
//   was stopped, the contents of `out` are indeterminate.
276
// - The return value is true if iteration was not stopped by the callbacks.
277
template <
278
    size_t BlockSize, bool WriteOut = false, typename IVec,
279
    typename ReadFromT = const uint8_t *, ReadFromT IVec::*ReadFrom = &IVec::in,
280
    typename /* bool(const uint8_t *in, [uint8_t *out,] size_t len) */ FWhole,
281
    typename /* bool(const uint8_t *in, [uint8_t *out,] size_t len) */
282
    FFinal>
283
inline bool ForEachBlockRange(Span<IVec> ivecs, const FWhole &f_whole,
284
5.04k
                              const FFinal &f_final) {
285
5.04k
  using MutableIVec = std::remove_const_t<IVec>;
286
  // Helper to make the function calls simpler.
287
5.04k
  auto call_func = [&](const auto &f, const IVec &ivec) {
288
5.04k
    if constexpr (WriteOut) {
289
5.04k
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
290
5.04k
    } else {
291
0
      return f(ivec.*ReadFrom, ivec.len);
292
0
    }
293
5.04k
  };
Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSH_IS3_Lm18446744073709551615EEEbE3$_0SK_EEbNSH_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISK_EEDaSU_SV_
Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPhTnMT1_T2_XadL_ZNS2_3outEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSG_IS3_Lm18446744073709551615EEEbE3$_0SJ_EEbNSG_IS5_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISJ_EEDaST_SU_
Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISI_EEDaSS_ST_
Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISH_EEDaSS_ST_
Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISG_EEDaSQ_SR_
Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISF_EEDaSQ_SR_
e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISJ_EEDaST_SU_
Line
Count
Source
287
163
  auto call_func = [&](const auto &f, const IVec &ivec) {
288
163
    if constexpr (WriteOut) {
289
163
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
290
    } else {
291
      return f(ivec.*ReadFrom, ivec.len);
292
    }
293
163
  };
e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISJ_EEDaST_SU_
Line
Count
Source
287
3.46k
  auto call_func = [&](const auto &f, const IVec &ivec) {
288
3.46k
    if constexpr (WriteOut) {
289
3.46k
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
290
    } else {
291
      return f(ivec.*ReadFrom, ivec.len);
292
    }
293
3.46k
  };
e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISL_EEDaSV_SW_
Line
Count
Source
287
654
  auto call_func = [&](const auto &f, const IVec &ivec) {
288
654
    if constexpr (WriteOut) {
289
654
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
290
    } else {
291
      return f(ivec.*ReadFrom, ivec.len);
292
    }
293
654
  };
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISK_EEDaSV_SW_
e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISL_EEDaSV_SW_
Line
Count
Source
287
770
  auto call_func = [&](const auto &f, const IVec &ivec) {
288
770
    if constexpr (WriteOut) {
289
770
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
290
    } else {
291
      return f(ivec.*ReadFrom, ivec.len);
292
    }
293
770
  };
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRKT_RS3_E_clISK_EEDaSV_SW_
294
  // Helper to cut from the start of an IVec.
295
5.04k
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
296
0
    ivec.*ReadFrom += by;
297
0
    if constexpr (WriteOut) {
298
0
      ivec.out += by;
299
0
    }
300
0
    ivec.len -= by;
301
0
  };
Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSH_IS3_Lm18446744073709551615EEEbE3$_0SK_EEbNSH_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESS_m
Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPhTnMT1_T2_XadL_ZNS2_3outEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSG_IS3_Lm18446744073709551615EEEbE3$_0SJ_EEbNSG_IS5_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESR_m
Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESQ_m
Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESO_m
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESR_m
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clESR_m
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clEST_m
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlRS2_mE_clEST_m
302
  // Helper to copy a range to an iovec list.
303
5.04k
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
304
5.04k
                                 Span<IVec> rest) {
305
0
    if constexpr (WriteOut) {
306
0
      internal::CopySpanToIOVec(out, head, rest);
307
0
    }
308
0
  };
Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSH_IS3_Lm18446744073709551615EEEbE3$_0SK_EEbNSH_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlNSH_IS4_Lm18446744073709551615EEES2_SJ_E_clESS_S2_SJ_
Unexecuted instantiation: bcm.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPhTnMT1_T2_XadL_ZNS2_3outEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSG_IS3_Lm18446744073709551615EEEbE3$_0SJ_EEbNSG_IS5_Lm18446744073709551615EEERKT4_RKT5_ENKUlNSG_IKhLm18446744073709551615EEES2_SI_E_clESS_S2_SI_
Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSD_S2_SA_E_clESD_S2_SA_
Unexecuted instantiation: e_chacha20poly1305.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSB_S2_SA_E_clESB_S2_SA_
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSF_S2_SD_E_clESF_S2_SD_
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSF_S2_SD_E_clESF_S2_SD_
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSG_S2_SD_E_clESG_S2_SD_
Unexecuted instantiation: e_tls.cc:_ZZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_ENKUlSG_S2_SD_E_clESG_S2_SD_
309
310
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
311
  // detecting being at the end and calling `f_final` at the appropriate time.
312
5.04k
  Span<IVec> ivecs_trimmed = ivecs;
313
5.04k
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
314
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
315
0
  }
316
5.04k
  if (ivecs_trimmed.empty()) {
317
0
    return call_func(f_final, IVec{});
318
0
  }
319
320
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
321
  // last can be empty.
322
323
5.04k
  MutableIVec current_range_head = ivecs_trimmed.front();
324
5.04k
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
325
5.04k
  while (!current_range_rest.empty()) {
326
    // Process as many whole blocks as possible.
327
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
328
0
    if (whole_blocks_len != 0) {
329
0
      MutableIVec whole_part = current_range_head;
330
0
      whole_part.len = whole_blocks_len;
331
0
      if (!call_func(f_whole, whole_part)) {
332
0
        return false;
333
0
      }
334
0
      remove_prefix(current_range_head, whole_blocks_len);
335
0
    }
336
337
0
    if (current_range_head.len == 0) {
338
0
      current_range_head = current_range_rest.front();
339
0
      current_range_rest = current_range_rest.subspan(1);
340
0
      continue;
341
0
    }
342
343
    // Collect a whole block.
344
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
345
0
    alignas(BlockSize) uint8_t out[BlockSize];
346
0
    MutableIVec collect_from_head = current_range_head;
347
0
    Span<IVec> collect_from_rest = current_range_rest;
348
0
    while (in.size() <= BlockSize) {
349
0
      size_t remaining = BlockSize - in.size();
350
0
      if (remaining < collect_from_head.len) {
351
        // Got enough to complete the block _and more_.
352
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
353
0
        remove_prefix(collect_from_head, remaining);
354
0
        break;
355
0
      }
356
      // Consume all of `ivec` and advance.
357
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
358
0
      if (collect_from_rest.empty()) {
359
        // Nothing left - so this is the final block.
360
0
        auto finalout = Span(out).first(in.size());
361
0
        MutableIVec finalvec = {};
362
0
        finalvec.len = in.size();
363
0
        finalvec.*ReadFrom = in.data();
364
0
        if constexpr (WriteOut) {
365
0
          finalvec.out = finalout.data();
366
0
        }
367
0
        if (!call_func(f_final, finalvec)) {
368
0
          return false;
369
0
        }
370
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
371
0
        return true;
372
0
      }
373
0
      collect_from_head = collect_from_rest.front();
374
0
      collect_from_rest = collect_from_rest.subspan(1);
375
0
    }
376
0
    assert(in.size() == BlockSize);
377
378
    // The above loop ensures this condition by the `break` only happening if
379
    // `collect_from_head` has at least one byte remaining, and the loop
380
    // otherwise ensuring as an invariant that the final chunk - which is
381
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
382
    //
383
    // As such, at least one byte is remaining, and thus calling `f_whole` is
384
    // appropriate.
385
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
386
387
    // Process the block.
388
0
    MutableIVec wholevec = {};
389
0
    wholevec.len = in.size();
390
0
    wholevec.*ReadFrom = in.data();
391
0
    if constexpr (WriteOut) {
392
0
      wholevec.out = out;
393
0
    }
394
0
    if (!call_func(f_whole, wholevec)) {
395
0
      return false;
396
0
    }
397
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
398
0
                        current_range_rest);
399
400
    // Set the new position.
401
0
    current_range_head = collect_from_head;
402
0
    current_range_rest = collect_from_rest;
403
0
  }
404
405
  // If current_range_head.len is zero, then the last item of ivecs is empty.
406
  // That however was excluded at the start of the function to ensure `f_final`
407
  // is always used for the last call.
408
5.04k
  assert(current_range_head.len != 0);
409
410
5.04k
  return call_func(f_final, current_range_head);
411
5.04k
}
Unexecuted instantiation: bcm.cc:_ZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSH_IS3_Lm18446744073709551615EEEbE3$_0SK_EEbNSH_IS6_Lm18446744073709551615EEERKT4_RKT5_
Unexecuted instantiation: bcm.cc:_ZN4bssl5iovec17ForEachBlockRangeILm16ELb0EK15crypto_iovec_stPhTnMT1_T2_XadL_ZNS2_3outEEEZL18ccm128_compute_macPK14ccm128_contextP12ccm128_statePK10aes_key_stNS_4SpanIhLm18446744073709551615EEENSG_IS3_Lm18446744073709551615EEEbE3$_0SJ_EEbNSG_IS5_Lm18446744073709551615EEERKT4_RKT5_
Unexecuted instantiation: e_chacha20poly1305.cc:_ZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL23chacha20_poly1305_sealvS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IhLm18446744073709551615EEEPmNS9_IS4_Lm18446744073709551615EEENS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL23chacha20_poly1305_sealvS5_SA_SB_SC_SD_SG_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_
Unexecuted instantiation: e_chacha20poly1305.cc:_ZN4bssl5iovec17ForEachBlockRangeILm64ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL32chacha20_poly1305_openv_detachedS5_NS_4SpanIS3_Lm18446744073709551615EEENS9_IS4_Lm18446744073709551615EEESB_NS9_IK14crypto_ivec_stLm18446744073709551615EEEmE3$_0ZL32chacha20_poly1305_openv_detachedS5_SA_SB_SB_SE_mE3$_1EEbNS9_IS6_Lm18446744073709551615EEERKT4_RKT5_
e_tls.cc:_ZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_
Line
Count
Source
284
163
                              const FFinal &f_final) {
285
163
  using MutableIVec = std::remove_const_t<IVec>;
286
  // Helper to make the function calls simpler.
287
163
  auto call_func = [&](const auto &f, const IVec &ivec) {
288
163
    if constexpr (WriteOut) {
289
163
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
290
163
    } else {
291
163
      return f(ivec.*ReadFrom, ivec.len);
292
163
    }
293
163
  };
294
  // Helper to cut from the start of an IVec.
295
163
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
296
163
    ivec.*ReadFrom += by;
297
163
    if constexpr (WriteOut) {
298
163
      ivec.out += by;
299
163
    }
300
163
    ivec.len -= by;
301
163
  };
302
  // Helper to copy a range to an iovec list.
303
163
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
304
163
                                 Span<IVec> rest) {
305
163
    if constexpr (WriteOut) {
306
163
      internal::CopySpanToIOVec(out, head, rest);
307
163
    }
308
163
  };
309
310
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
311
  // detecting being at the end and calling `f_final` at the appropriate time.
312
163
  Span<IVec> ivecs_trimmed = ivecs;
313
163
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
314
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
315
0
  }
316
163
  if (ivecs_trimmed.empty()) {
317
0
    return call_func(f_final, IVec{});
318
0
  }
319
320
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
321
  // last can be empty.
322
323
163
  MutableIVec current_range_head = ivecs_trimmed.front();
324
163
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
325
163
  while (!current_range_rest.empty()) {
326
    // Process as many whole blocks as possible.
327
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
328
0
    if (whole_blocks_len != 0) {
329
0
      MutableIVec whole_part = current_range_head;
330
0
      whole_part.len = whole_blocks_len;
331
0
      if (!call_func(f_whole, whole_part)) {
332
0
        return false;
333
0
      }
334
0
      remove_prefix(current_range_head, whole_blocks_len);
335
0
    }
336
337
0
    if (current_range_head.len == 0) {
338
0
      current_range_head = current_range_rest.front();
339
0
      current_range_rest = current_range_rest.subspan(1);
340
0
      continue;
341
0
    }
342
343
    // Collect a whole block.
344
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
345
0
    alignas(BlockSize) uint8_t out[BlockSize];
346
0
    MutableIVec collect_from_head = current_range_head;
347
0
    Span<IVec> collect_from_rest = current_range_rest;
348
0
    while (in.size() <= BlockSize) {
349
0
      size_t remaining = BlockSize - in.size();
350
0
      if (remaining < collect_from_head.len) {
351
        // Got enough to complete the block _and more_.
352
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
353
0
        remove_prefix(collect_from_head, remaining);
354
0
        break;
355
0
      }
356
      // Consume all of `ivec` and advance.
357
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
358
0
      if (collect_from_rest.empty()) {
359
        // Nothing left - so this is the final block.
360
0
        auto finalout = Span(out).first(in.size());
361
0
        MutableIVec finalvec = {};
362
0
        finalvec.len = in.size();
363
0
        finalvec.*ReadFrom = in.data();
364
0
        if constexpr (WriteOut) {
365
0
          finalvec.out = finalout.data();
366
0
        }
367
0
        if (!call_func(f_final, finalvec)) {
368
0
          return false;
369
0
        }
370
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
371
0
        return true;
372
0
      }
373
0
      collect_from_head = collect_from_rest.front();
374
0
      collect_from_rest = collect_from_rest.subspan(1);
375
0
    }
376
0
    assert(in.size() == BlockSize);
377
378
    // The above loop ensures this condition by the `break` only happening if
379
    // `collect_from_head` has at least one byte remaining, and the loop
380
    // otherwise ensuring as an invariant that the final chunk - which is
381
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
382
    //
383
    // As such, at least one byte is remaining, and thus calling `f_whole` is
384
    // appropriate.
385
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
386
387
    // Process the block.
388
0
    MutableIVec wholevec = {};
389
0
    wholevec.len = in.size();
390
0
    wholevec.*ReadFrom = in.data();
391
0
    if constexpr (WriteOut) {
392
0
      wholevec.out = out;
393
0
    }
394
0
    if (!call_func(f_whole, wholevec)) {
395
0
      return false;
396
0
    }
397
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
398
0
                        current_range_rest);
399
400
    // Set the new position.
401
0
    current_range_head = collect_from_head;
402
0
    current_range_rest = collect_from_rest;
403
0
  }
404
405
  // If current_range_head.len is zero, then the last item of ivecs is empty.
406
  // That however was excluded at the start of the function to ensure `f_final`
407
  // is always used for the last call.
408
163
  assert(current_range_head.len != 0);
409
410
163
  return call_func(f_final, current_range_head);
411
163
}
e_tls.cc:_ZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_
Line
Count
Source
284
3.46k
                              const FFinal &f_final) {
285
3.46k
  using MutableIVec = std::remove_const_t<IVec>;
286
  // Helper to make the function calls simpler.
287
3.46k
  auto call_func = [&](const auto &f, const IVec &ivec) {
288
3.46k
    if constexpr (WriteOut) {
289
3.46k
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
290
3.46k
    } else {
291
3.46k
      return f(ivec.*ReadFrom, ivec.len);
292
3.46k
    }
293
3.46k
  };
294
  // Helper to cut from the start of an IVec.
295
3.46k
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
296
3.46k
    ivec.*ReadFrom += by;
297
3.46k
    if constexpr (WriteOut) {
298
3.46k
      ivec.out += by;
299
3.46k
    }
300
3.46k
    ivec.len -= by;
301
3.46k
  };
302
  // Helper to copy a range to an iovec list.
303
3.46k
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
304
3.46k
                                 Span<IVec> rest) {
305
3.46k
    if constexpr (WriteOut) {
306
3.46k
      internal::CopySpanToIOVec(out, head, rest);
307
3.46k
    }
308
3.46k
  };
309
310
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
311
  // detecting being at the end and calling `f_final` at the appropriate time.
312
3.46k
  Span<IVec> ivecs_trimmed = ivecs;
313
3.46k
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
314
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
315
0
  }
316
3.46k
  if (ivecs_trimmed.empty()) {
317
0
    return call_func(f_final, IVec{});
318
0
  }
319
320
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
321
  // last can be empty.
322
323
3.46k
  MutableIVec current_range_head = ivecs_trimmed.front();
324
3.46k
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
325
3.46k
  while (!current_range_rest.empty()) {
326
    // Process as many whole blocks as possible.
327
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
328
0
    if (whole_blocks_len != 0) {
329
0
      MutableIVec whole_part = current_range_head;
330
0
      whole_part.len = whole_blocks_len;
331
0
      if (!call_func(f_whole, whole_part)) {
332
0
        return false;
333
0
      }
334
0
      remove_prefix(current_range_head, whole_blocks_len);
335
0
    }
336
337
0
    if (current_range_head.len == 0) {
338
0
      current_range_head = current_range_rest.front();
339
0
      current_range_rest = current_range_rest.subspan(1);
340
0
      continue;
341
0
    }
342
343
    // Collect a whole block.
344
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
345
0
    alignas(BlockSize) uint8_t out[BlockSize];
346
0
    MutableIVec collect_from_head = current_range_head;
347
0
    Span<IVec> collect_from_rest = current_range_rest;
348
0
    while (in.size() <= BlockSize) {
349
0
      size_t remaining = BlockSize - in.size();
350
0
      if (remaining < collect_from_head.len) {
351
        // Got enough to complete the block _and more_.
352
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
353
0
        remove_prefix(collect_from_head, remaining);
354
0
        break;
355
0
      }
356
      // Consume all of `ivec` and advance.
357
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
358
0
      if (collect_from_rest.empty()) {
359
        // Nothing left - so this is the final block.
360
0
        auto finalout = Span(out).first(in.size());
361
0
        MutableIVec finalvec = {};
362
0
        finalvec.len = in.size();
363
0
        finalvec.*ReadFrom = in.data();
364
0
        if constexpr (WriteOut) {
365
0
          finalvec.out = finalout.data();
366
0
        }
367
0
        if (!call_func(f_final, finalvec)) {
368
0
          return false;
369
0
        }
370
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
371
0
        return true;
372
0
      }
373
0
      collect_from_head = collect_from_rest.front();
374
0
      collect_from_rest = collect_from_rest.subspan(1);
375
0
    }
376
0
    assert(in.size() == BlockSize);
377
378
    // The above loop ensures this condition by the `break` only happening if
379
    // `collect_from_head` has at least one byte remaining, and the loop
380
    // otherwise ensuring as an invariant that the final chunk - which is
381
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
382
    //
383
    // As such, at least one byte is remaining, and thus calling `f_whole` is
384
    // appropriate.
385
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
386
387
    // Process the block.
388
0
    MutableIVec wholevec = {};
389
0
    wholevec.len = in.size();
390
0
    wholevec.*ReadFrom = in.data();
391
0
    if constexpr (WriteOut) {
392
0
      wholevec.out = out;
393
0
    }
394
0
    if (!call_func(f_whole, wholevec)) {
395
0
      return false;
396
0
    }
397
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
398
0
                        current_range_rest);
399
400
    // Set the new position.
401
0
    current_range_head = collect_from_head;
402
0
    current_range_rest = collect_from_rest;
403
0
  }
404
405
  // If current_range_head.len is zero, then the last item of ivecs is empty.
406
  // That however was excluded at the start of the function to ensure `f_final`
407
  // is always used for the last call.
408
3.46k
  assert(current_range_head.len != 0);
409
410
3.46k
  return call_func(f_final, current_range_head);
411
3.46k
}
e_tls.cc:_ZN4bssl5iovec17ForEachBlockRangeILm8ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_
Line
Count
Source
284
654
                              const FFinal &f_final) {
285
654
  using MutableIVec = std::remove_const_t<IVec>;
286
  // Helper to make the function calls simpler.
287
654
  auto call_func = [&](const auto &f, const IVec &ivec) {
288
654
    if constexpr (WriteOut) {
289
654
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
290
654
    } else {
291
654
      return f(ivec.*ReadFrom, ivec.len);
292
654
    }
293
654
  };
294
  // Helper to cut from the start of an IVec.
295
654
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
296
654
    ivec.*ReadFrom += by;
297
654
    if constexpr (WriteOut) {
298
654
      ivec.out += by;
299
654
    }
300
654
    ivec.len -= by;
301
654
  };
302
  // Helper to copy a range to an iovec list.
303
654
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
304
654
                                 Span<IVec> rest) {
305
654
    if constexpr (WriteOut) {
306
654
      internal::CopySpanToIOVec(out, head, rest);
307
654
    }
308
654
  };
309
310
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
311
  // detecting being at the end and calling `f_final` at the appropriate time.
312
654
  Span<IVec> ivecs_trimmed = ivecs;
313
654
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
314
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
315
0
  }
316
654
  if (ivecs_trimmed.empty()) {
317
0
    return call_func(f_final, IVec{});
318
0
  }
319
320
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
321
  // last can be empty.
322
323
654
  MutableIVec current_range_head = ivecs_trimmed.front();
324
654
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
325
654
  while (!current_range_rest.empty()) {
326
    // Process as many whole blocks as possible.
327
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
328
0
    if (whole_blocks_len != 0) {
329
0
      MutableIVec whole_part = current_range_head;
330
0
      whole_part.len = whole_blocks_len;
331
0
      if (!call_func(f_whole, whole_part)) {
332
0
        return false;
333
0
      }
334
0
      remove_prefix(current_range_head, whole_blocks_len);
335
0
    }
336
337
0
    if (current_range_head.len == 0) {
338
0
      current_range_head = current_range_rest.front();
339
0
      current_range_rest = current_range_rest.subspan(1);
340
0
      continue;
341
0
    }
342
343
    // Collect a whole block.
344
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
345
0
    alignas(BlockSize) uint8_t out[BlockSize];
346
0
    MutableIVec collect_from_head = current_range_head;
347
0
    Span<IVec> collect_from_rest = current_range_rest;
348
0
    while (in.size() <= BlockSize) {
349
0
      size_t remaining = BlockSize - in.size();
350
0
      if (remaining < collect_from_head.len) {
351
        // Got enough to complete the block _and more_.
352
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
353
0
        remove_prefix(collect_from_head, remaining);
354
0
        break;
355
0
      }
356
      // Consume all of `ivec` and advance.
357
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
358
0
      if (collect_from_rest.empty()) {
359
        // Nothing left - so this is the final block.
360
0
        auto finalout = Span(out).first(in.size());
361
0
        MutableIVec finalvec = {};
362
0
        finalvec.len = in.size();
363
0
        finalvec.*ReadFrom = in.data();
364
0
        if constexpr (WriteOut) {
365
0
          finalvec.out = finalout.data();
366
0
        }
367
0
        if (!call_func(f_final, finalvec)) {
368
0
          return false;
369
0
        }
370
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
371
0
        return true;
372
0
      }
373
0
      collect_from_head = collect_from_rest.front();
374
0
      collect_from_rest = collect_from_rest.subspan(1);
375
0
    }
376
0
    assert(in.size() == BlockSize);
377
378
    // The above loop ensures this condition by the `break` only happening if
379
    // `collect_from_head` has at least one byte remaining, and the loop
380
    // otherwise ensuring as an invariant that the final chunk - which is
381
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
382
    //
383
    // As such, at least one byte is remaining, and thus calling `f_whole` is
384
    // appropriate.
385
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
386
387
    // Process the block.
388
0
    MutableIVec wholevec = {};
389
0
    wholevec.len = in.size();
390
0
    wholevec.*ReadFrom = in.data();
391
0
    if constexpr (WriteOut) {
392
0
      wholevec.out = out;
393
0
    }
394
0
    if (!call_func(f_whole, wholevec)) {
395
0
      return false;
396
0
    }
397
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
398
0
                        current_range_rest);
399
400
    // Set the new position.
401
0
    current_range_head = collect_from_head;
402
0
    current_range_rest = collect_from_rest;
403
0
  }
404
405
  // If current_range_head.len is zero, then the last item of ivecs is empty.
406
  // That however was excluded at the start of the function to ensure `f_final`
407
  // is always used for the last call.
408
654
  assert(current_range_head.len != 0);
409
410
654
  return call_func(f_final, current_range_head);
411
654
}
e_tls.cc:_ZN4bssl5iovec17ForEachBlockRangeILm16ELb1EK15crypto_iovec_stPKhTnMT1_T2_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEbNSC_IS6_Lm18446744073709551615EEERKT4_RKT5_
Line
Count
Source
284
770
                              const FFinal &f_final) {
285
770
  using MutableIVec = std::remove_const_t<IVec>;
286
  // Helper to make the function calls simpler.
287
770
  auto call_func = [&](const auto &f, const IVec &ivec) {
288
770
    if constexpr (WriteOut) {
289
770
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
290
770
    } else {
291
770
      return f(ivec.*ReadFrom, ivec.len);
292
770
    }
293
770
  };
294
  // Helper to cut from the start of an IVec.
295
770
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
296
770
    ivec.*ReadFrom += by;
297
770
    if constexpr (WriteOut) {
298
770
      ivec.out += by;
299
770
    }
300
770
    ivec.len -= by;
301
770
  };
302
  // Helper to copy a range to an iovec list.
303
770
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
304
770
                                 Span<IVec> rest) {
305
770
    if constexpr (WriteOut) {
306
770
      internal::CopySpanToIOVec(out, head, rest);
307
770
    }
308
770
  };
309
310
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
311
  // detecting being at the end and calling `f_final` at the appropriate time.
312
770
  Span<IVec> ivecs_trimmed = ivecs;
313
770
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
314
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
315
0
  }
316
770
  if (ivecs_trimmed.empty()) {
317
0
    return call_func(f_final, IVec{});
318
0
  }
319
320
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
321
  // last can be empty.
322
323
770
  MutableIVec current_range_head = ivecs_trimmed.front();
324
770
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
325
770
  while (!current_range_rest.empty()) {
326
    // Process as many whole blocks as possible.
327
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
328
0
    if (whole_blocks_len != 0) {
329
0
      MutableIVec whole_part = current_range_head;
330
0
      whole_part.len = whole_blocks_len;
331
0
      if (!call_func(f_whole, whole_part)) {
332
0
        return false;
333
0
      }
334
0
      remove_prefix(current_range_head, whole_blocks_len);
335
0
    }
336
337
0
    if (current_range_head.len == 0) {
338
0
      current_range_head = current_range_rest.front();
339
0
      current_range_rest = current_range_rest.subspan(1);
340
0
      continue;
341
0
    }
342
343
    // Collect a whole block.
344
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
345
0
    alignas(BlockSize) uint8_t out[BlockSize];
346
0
    MutableIVec collect_from_head = current_range_head;
347
0
    Span<IVec> collect_from_rest = current_range_rest;
348
0
    while (in.size() <= BlockSize) {
349
0
      size_t remaining = BlockSize - in.size();
350
0
      if (remaining < collect_from_head.len) {
351
        // Got enough to complete the block _and more_.
352
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
353
0
        remove_prefix(collect_from_head, remaining);
354
0
        break;
355
0
      }
356
      // Consume all of `ivec` and advance.
357
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
358
0
      if (collect_from_rest.empty()) {
359
        // Nothing left - so this is the final block.
360
0
        auto finalout = Span(out).first(in.size());
361
0
        MutableIVec finalvec = {};
362
0
        finalvec.len = in.size();
363
0
        finalvec.*ReadFrom = in.data();
364
0
        if constexpr (WriteOut) {
365
0
          finalvec.out = finalout.data();
366
0
        }
367
0
        if (!call_func(f_final, finalvec)) {
368
0
          return false;
369
0
        }
370
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
371
0
        return true;
372
0
      }
373
0
      collect_from_head = collect_from_rest.front();
374
0
      collect_from_rest = collect_from_rest.subspan(1);
375
0
    }
376
0
    assert(in.size() == BlockSize);
377
378
    // The above loop ensures this condition by the `break` only happening if
379
    // `collect_from_head` has at least one byte remaining, and the loop
380
    // otherwise ensuring as an invariant that the final chunk - which is
381
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
382
    //
383
    // As such, at least one byte is remaining, and thus calling `f_whole` is
384
    // appropriate.
385
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
386
387
    // Process the block.
388
0
    MutableIVec wholevec = {};
389
0
    wholevec.len = in.size();
390
0
    wholevec.*ReadFrom = in.data();
391
0
    if constexpr (WriteOut) {
392
0
      wholevec.out = out;
393
0
    }
394
0
    if (!call_func(f_whole, wholevec)) {
395
0
      return false;
396
0
    }
397
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
398
0
                        current_range_rest);
399
400
    // Set the new position.
401
0
    current_range_head = collect_from_head;
402
0
    current_range_rest = collect_from_rest;
403
0
  }
404
405
  // If current_range_head.len is zero, then the last item of ivecs is empty.
406
  // That however was excluded at the start of the function to ensure `f_final`
407
  // is always used for the last call.
408
770
  assert(current_range_head.len != 0);
409
410
770
  return call_func(f_final, current_range_head);
411
770
}
412
413
// MaybeInplaceArray can hold a copy of a CRYPTO_IOVEC. If it is a low
414
// amount of entries, it will be stored on the stack, otherwise on the heap.
415
using MaybeInplaceArray = bssl::MaybeInplaceArray<CRYPTO_IOVEC, 16>;
416
417
// ForEachOutBlockRange is like `ForEachBlockRange` but reads from a
418
// `CRYPTO_IOVEC`'s `out` member instead.
419
template <
420
    size_t BlockSize,
421
    typename /* int(const uint8_t *in, [uint8_t *out,] size_t len) */ FWhole,
422
    typename /* int(const uint8_t *in, [uint8_t *out,] size_t len) */
423
    FFinal>
424
inline int ForEachOutBlockRange(Span<const CRYPTO_IOVEC> iovecs,
425
0
                                const FWhole &f_whole, const FFinal &f_final) {
426
0
  return ForEachBlockRange<BlockSize, /*WriteOut=*/false, const CRYPTO_IOVEC,
427
0
                           /*ReadFromT=*/uint8_t *,
428
0
                           /*ReadFrom=*/&CRYPTO_IOVEC::out>(iovecs, f_whole,
429
0
                                                            f_final);
430
0
}
431
432
// ForEachBlockRange_Dynamic is simply `ForEachBlockRange` with a
433
// runtime dispatch on the block size.
434
template <
435
    bool WriteOut = false, typename IVec, typename ReadFromT = const uint8_t *,
436
    ReadFromT IVec::*ReadFrom = &IVec::in,
437
    typename /* int(const uint8_t *in, uint8_t *out, size_t len) */ FWhole,
438
    typename /* int(const uint8_t *in, uint8_t *out, size_t len) */
439
    FFinal>
440
inline int ForEachBlockRange_Dynamic(size_t block_size, Span<IVec> ivecs,
441
                                     const FWhole &f_whole,
442
5.04k
                                     const FFinal &f_final) {
443
5.04k
  switch (block_size) {
444
817
    case 8:
445
817
      return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>(
446
817
          ivecs, f_whole, f_final);
447
0
      break;
448
4.23k
    case 16:
449
4.23k
      return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>(
450
4.23k
          ivecs, f_whole, f_final);
451
0
      break;
452
0
    default:
453
0
      return 0;
454
5.04k
  }
455
5.04k
}
e_tls.cc:_ZN4bssl5iovec25ForEachBlockRange_DynamicILb1EK15crypto_iovec_stPKhTnMT0_T1_XadL_ZNS2_2inEEEZL14aead_tls_openvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0SJ_EEimNSC_IS6_Lm18446744073709551615EEERKT3_RKT4_
Line
Count
Source
442
3.62k
                                     const FFinal &f_final) {
443
3.62k
  switch (block_size) {
444
163
    case 8:
445
163
      return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>(
446
163
          ivecs, f_whole, f_final);
447
0
      break;
448
3.46k
    case 16:
449
3.46k
      return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>(
450
3.46k
          ivecs, f_whole, f_final);
451
0
      break;
452
0
    default:
453
0
      return 0;
454
3.62k
  }
455
3.62k
}
e_tls.cc:_ZN4bssl5iovec25ForEachBlockRange_DynamicILb1EK15crypto_iovec_stPKhTnMT0_T1_XadL_ZNS2_2inEEEZL14aead_tls_sealvPK15evp_aead_ctx_stNS_4SpanIS3_Lm18446744073709551615EEENSC_IhLm18446744073709551615EEEPmNSC_IS4_Lm18446744073709551615EEENSC_IK14crypto_ivec_stLm18446744073709551615EEEE3$_0ZL14aead_tls_sealvSB_SD_SE_SF_SG_SJ_E3$_1EEimNSC_IS6_Lm18446744073709551615EEERKT3_RKT4_
Line
Count
Source
442
1.42k
                                     const FFinal &f_final) {
443
1.42k
  switch (block_size) {
444
654
    case 8:
445
654
      return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>(
446
654
          ivecs, f_whole, f_final);
447
0
      break;
448
770
    case 16:
449
770
      return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>(
450
770
          ivecs, f_whole, f_final);
451
0
      break;
452
0
    default:
453
0
      return 0;
454
1.42k
  }
455
1.42k
}
456
457
}  // namespace iovec
458
459
BSSL_NAMESPACE_END
460
461
#endif  // OPENSSL_HEADER_CRYPTO_FIPSMODULE_CIPHER_INTERNAL_H