Coverage Report

Created: 2026-08-14 07:01

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
11.5k
inline void CopySpan(Span<const uint8_t> from, Span<uint8_t> to) {
148
11.5k
  BSSL_CHECK(from.size() == to.size());
149
11.5k
  std::copy(from.begin(), from.end(), to.begin());
150
11.5k
}
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
10.3k
inline void CopyToPrefix(Span<const uint8_t> from, Span<uint8_t> to) {
158
10.3k
  CopySpan(from, to.first(from.size()));
159
10.3k
}
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 and not more than `CRYPTO_IOVEC_MAX` chunks. Note that the `EVP_AEAD`
167
// methods need to accept an arbitrary number of chunks.
168
template <typename IVec>
169
18.4k
inline bool IsValid(Span<IVec> ivecs) {
170
18.4k
  if (ivecs.size() > CRYPTO_IOVEC_MAX) {
171
0
    return false;
172
0
  }
173
18.4k
  size_t allowed = SIZE_MAX;
174
19.0k
  for (const IVec &ivec : ivecs) {
175
19.0k
    size_t len = ivec.len;
176
19.0k
    if (len > allowed) {
177
0
      return false;
178
0
    }
179
19.0k
    allowed -= len;
180
19.0k
  }
181
18.4k
  return true;
182
18.4k
}
bool bssl::iovec::IsValid<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>)
Line
Count
Source
169
9.20k
inline bool IsValid(Span<IVec> ivecs) {
170
9.20k
  if (ivecs.size() > CRYPTO_IOVEC_MAX) {
171
0
    return false;
172
0
  }
173
9.20k
  size_t allowed = SIZE_MAX;
174
9.83k
  for (const IVec &ivec : ivecs) {
175
9.83k
    size_t len = ivec.len;
176
9.83k
    if (len > allowed) {
177
0
      return false;
178
0
    }
179
9.83k
    allowed -= len;
180
9.83k
  }
181
9.20k
  return true;
182
9.20k
}
bool bssl::iovec::IsValid<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>)
Line
Count
Source
169
9.20k
inline bool IsValid(Span<IVec> ivecs) {
170
9.20k
  if (ivecs.size() > CRYPTO_IOVEC_MAX) {
171
0
    return false;
172
0
  }
173
9.20k
  size_t allowed = SIZE_MAX;
174
9.20k
  for (const IVec &ivec : ivecs) {
175
9.20k
    size_t len = ivec.len;
176
9.20k
    if (len > allowed) {
177
0
      return false;
178
0
    }
179
9.20k
    allowed -= len;
180
9.20k
  }
181
9.20k
  return true;
182
9.20k
}
183
184
// Length returns the total length in bytes of a given `CRYPTO_IVEC` or
185
// `CRYPTO_IOVEC`.
186
template <typename IVec>
187
11.3k
inline size_t TotalLength(Span<IVec> ivecs) {
188
11.3k
  size_t total = 0;
189
11.6k
  for (const IVec &ivec : ivecs) {
190
11.6k
    total += ivec.len;
191
11.6k
  }
192
11.3k
  return total;
193
11.3k
}
unsigned long bssl::iovec::TotalLength<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>)
Line
Count
Source
187
6.30k
inline size_t TotalLength(Span<IVec> ivecs) {
188
6.30k
  size_t total = 0;
189
6.61k
  for (const IVec &ivec : ivecs) {
190
6.61k
    total += ivec.len;
191
6.61k
  }
192
6.30k
  return total;
193
6.30k
}
unsigned long bssl::iovec::TotalLength<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>)
Line
Count
Source
187
5.01k
inline size_t TotalLength(Span<IVec> ivecs) {
188
5.01k
  size_t total = 0;
189
5.01k
  for (const IVec &ivec : ivecs) {
190
5.01k
    total += ivec.len;
191
5.01k
  }
192
5.01k
  return total;
193
5.01k
}
Unexecuted instantiation: unsigned long bssl::iovec::TotalLength<crypto_iovec_st>(bssl::Span<crypto_iovec_st, 18446744073709551615ul>)
194
195
// GetAndRemoveSuffix takes `suffix_buf.size()` final bytes from the given
196
// `CRYPTO_IVEC` or `CRYPTO_IOVEC` (mutating said iovec to no longer contain
197
// those bytes) and returns them.
198
//
199
// If the byte range is contained in a single chunk of `ivecs`, it will just
200
// return that span pointing into `ivecs`; otherwise, it will copy the bytes
201
// into `out` and return that.
202
//
203
// If `ivecs` is too short, returns `nullopt`.
204
template <typename IVec, typename ReadFromT = const uint8_t *,
205
          ReadFromT IVec::*ReadFrom = &IVec::in>
206
inline std::optional<Span<const uint8_t>> GetAndRemoveSuffix(
207
3.69k
    Span<uint8_t> suffix_buf, Span<IVec> ivecs) {
208
  // Get the trivial case out.
209
3.69k
  if (suffix_buf.empty()) {
210
0
    return suffix_buf;
211
0
  }
212
  // Strip trailing zero length chunks.
213
3.69k
  while (!ivecs.empty() && ivecs.back().len == 0) {
214
0
    ivecs = ivecs.first(ivecs.size() - 1);
215
0
  }
216
3.69k
  if (ivecs.empty()) {
217
0
    return std::nullopt;
218
0
  }
219
  // Is the requested chunk entirely contained? If so, just return it.
220
3.69k
  if (ivecs.back().len >= suffix_buf.size()) {
221
3.69k
    ivecs.back().len -= suffix_buf.size();
222
3.69k
    return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size());
223
3.69k
  }
224
  // Otherwise, collect it into the buffer while trimming `ivecs`.
225
0
  Span<uint8_t> remaining = suffix_buf;
226
0
  while (!ivecs.empty()) {
227
0
    Span<const uint8_t> src(ivecs.back().*ReadFrom, ivecs.back().len);
228
0
    if (src.size() >= remaining.size()) {
229
0
      CopySpan(src.last(remaining.size()), remaining);
230
0
      ivecs.back().len -= remaining.size();
231
0
      return suffix_buf;
232
0
    }
233
0
    CopySpan(src, remaining.last(src.size()));
234
0
    remaining = remaining.first(remaining.size() - src.size());
235
0
    ivecs.back().len = 0;
236
0
    ivecs = ivecs.first(ivecs.size() - 1);
237
0
  }
238
0
  return std::nullopt;
239
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
207
3.69k
    Span<uint8_t> suffix_buf, Span<IVec> ivecs) {
208
  // Get the trivial case out.
209
3.69k
  if (suffix_buf.empty()) {
210
0
    return suffix_buf;
211
0
  }
212
  // Strip trailing zero length chunks.
213
3.69k
  while (!ivecs.empty() && ivecs.back().len == 0) {
214
0
    ivecs = ivecs.first(ivecs.size() - 1);
215
0
  }
216
3.69k
  if (ivecs.empty()) {
217
0
    return std::nullopt;
218
0
  }
219
  // Is the requested chunk entirely contained? If so, just return it.
220
3.69k
  if (ivecs.back().len >= suffix_buf.size()) {
221
3.69k
    ivecs.back().len -= suffix_buf.size();
222
3.69k
    return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size());
223
3.69k
  }
224
  // Otherwise, collect it into the buffer while trimming `ivecs`.
225
0
  Span<uint8_t> remaining = suffix_buf;
226
0
  while (!ivecs.empty()) {
227
0
    Span<const uint8_t> src(ivecs.back().*ReadFrom, ivecs.back().len);
228
0
    if (src.size() >= remaining.size()) {
229
0
      CopySpan(src.last(remaining.size()), remaining);
230
0
      ivecs.back().len -= remaining.size();
231
0
      return suffix_buf;
232
0
    }
233
0
    CopySpan(src, remaining.last(src.size()));
234
0
    remaining = remaining.first(remaining.size() - src.size());
235
0
    ivecs.back().len = 0;
236
0
    ivecs = ivecs.first(ivecs.size() - 1);
237
0
  }
238
0
  return std::nullopt;
239
0
}
240
241
// GetAndRemoveOutSuffix is like `GetAndRemoveSuffix` but takes from a
242
// `CRYPTO_IOVEC`'s `out` member instead.
243
inline std::optional<Span<const uint8_t>> GetAndRemoveOutSuffix(
244
3.69k
    Span<uint8_t> out, Span<CRYPTO_IOVEC> iovecs) {
245
3.69k
  return GetAndRemoveSuffix<CRYPTO_IOVEC, /*ReadFromT=*/uint8_t *,
246
3.69k
                            /*ReadFrom=*/&CRYPTO_IOVEC::out>(out, iovecs);
247
3.69k
}
248
249
namespace internal {
250
inline void CopySpanToIOVec(Span<const uint8_t> out, CRYPTO_IOVEC head,
251
0
                            Span<const CRYPTO_IOVEC> rest) {
252
0
  for (;;) {
253
0
    size_t to_copy = std::min(head.len, out.size());
254
0
    CopySpan(out.first(to_copy), Span(head.out, to_copy));
255
0
    out = out.subspan(to_copy);
256
0
    if (out.empty()) {
257
0
      break;
258
0
    }
259
0
    head = rest.front();  // Checkfails if insufficient space in CRYPTO_IOVEC.
260
0
    rest = rest.subspan(1);
261
0
  }
262
0
}
263
}  // namespace internal
264
265
// ForEachBlockRange iterates over the `ivecs` as follows:
266
//
267
// - `f_whole` gets called on whole blocks crossing `ivecs` chunk boundaries, or
268
//   ranges of whole blocks that are entirely in chunks.
269
// - `f` gets called exactly once, on the last block range which may
270
//   end up with a partial block.
271
// - Both functions receive an `in` pointer that either points into `ivecs` or
272
//   into a chunk assembly buffer and a `len` which indicates the number of
273
//   bytes from `in` that can be accessed. If the function returns 0,
274
//   iteration stops.
275
// - If `WriteOut` is set, `f_whole` and `f` receive an extra `out`
276
//   argument to which they can write output. This output will be placed into
277
//   the `ivecs`'s `out` members either during or after the call. If iteration
278
//   was stopped, the contents of `out` are indeterminate.
279
// - The return value is true if iteration was not stopped by the callbacks.
280
template <
281
    size_t BlockSize, bool WriteOut = false, typename IVec,
282
    typename ReadFromT = const uint8_t *, ReadFromT IVec::*ReadFrom = &IVec::in,
283
    typename /* bool(const uint8_t *in, [uint8_t *out,] size_t len) */ FWhole,
284
    typename /* bool(const uint8_t *in, [uint8_t *out,] size_t len) */
285
    FFinal>
286
inline bool ForEachBlockRange(Span<IVec> ivecs, const FWhole &f_whole,
287
5.01k
                              const FFinal &f_final) {
288
5.01k
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
5.01k
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
5.01k
    if constexpr (WriteOut) {
292
5.01k
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
5.01k
    } else {
294
0
      return f(ivec.*ReadFrom, ivec.len);
295
0
    }
296
5.01k
  };
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
290
158
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
158
    if constexpr (WriteOut) {
292
158
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
    } else {
294
      return f(ivec.*ReadFrom, ivec.len);
295
    }
296
158
  };
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
290
3.59k
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
3.59k
    if constexpr (WriteOut) {
292
3.59k
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
    } else {
294
      return f(ivec.*ReadFrom, ivec.len);
295
    }
296
3.59k
  };
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
290
564
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
564
    if constexpr (WriteOut) {
292
564
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
    } else {
294
      return f(ivec.*ReadFrom, ivec.len);
295
    }
296
564
  };
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
290
689
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
689
    if constexpr (WriteOut) {
292
689
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
    } else {
294
      return f(ivec.*ReadFrom, ivec.len);
295
    }
296
689
  };
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_
297
  // Helper to cut from the start of an IVec.
298
5.01k
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
299
0
    ivec.*ReadFrom += by;
300
0
    if constexpr (WriteOut) {
301
0
      ivec.out += by;
302
0
    }
303
0
    ivec.len -= by;
304
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
305
  // Helper to copy a range to an iovec list.
306
5.01k
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
5.01k
                                 Span<IVec> rest) {
308
0
    if constexpr (WriteOut) {
309
0
      internal::CopySpanToIOVec(out, head, rest);
310
0
    }
311
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_
312
313
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
314
  // detecting being at the end and calling `f_final` at the appropriate time.
315
5.01k
  Span<IVec> ivecs_trimmed = ivecs;
316
5.01k
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
5.01k
  if (ivecs_trimmed.empty()) {
320
0
    return call_func(f_final, IVec{});
321
0
  }
322
323
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
324
  // last can be empty.
325
326
5.01k
  MutableIVec current_range_head = ivecs_trimmed.front();
327
5.01k
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
5.01k
  while (!current_range_rest.empty()) {
329
    // Process as many whole blocks as possible.
330
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
331
0
    if (whole_blocks_len != 0) {
332
0
      MutableIVec whole_part = current_range_head;
333
0
      whole_part.len = whole_blocks_len;
334
0
      if (!call_func(f_whole, whole_part)) {
335
0
        return false;
336
0
      }
337
0
      remove_prefix(current_range_head, whole_blocks_len);
338
0
    }
339
340
0
    if (current_range_head.len == 0) {
341
0
      current_range_head = current_range_rest.front();
342
0
      current_range_rest = current_range_rest.subspan(1);
343
0
      continue;
344
0
    }
345
346
    // Collect a whole block.
347
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
348
0
    alignas(BlockSize) uint8_t out[BlockSize];
349
0
    MutableIVec collect_from_head = current_range_head;
350
0
    Span<IVec> collect_from_rest = current_range_rest;
351
0
    while (in.size() <= BlockSize) {
352
0
      size_t remaining = BlockSize - in.size();
353
0
      if (remaining < collect_from_head.len) {
354
        // Got enough to complete the block _and more_.
355
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
356
0
        remove_prefix(collect_from_head, remaining);
357
0
        break;
358
0
      }
359
      // Consume all of `ivec` and advance.
360
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
361
0
      if (collect_from_rest.empty()) {
362
        // Nothing left - so this is the final block.
363
0
        auto finalout = Span(out).first(in.size());
364
0
        MutableIVec finalvec = {};
365
0
        finalvec.len = in.size();
366
0
        finalvec.*ReadFrom = in.data();
367
0
        if constexpr (WriteOut) {
368
0
          finalvec.out = finalout.data();
369
0
        }
370
0
        if (!call_func(f_final, finalvec)) {
371
0
          return false;
372
0
        }
373
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
374
0
        return true;
375
0
      }
376
0
      collect_from_head = collect_from_rest.front();
377
0
      collect_from_rest = collect_from_rest.subspan(1);
378
0
    }
379
0
    assert(in.size() == BlockSize);
380
381
    // The above loop ensures this condition by the `break` only happening if
382
    // `collect_from_head` has at least one byte remaining, and the loop
383
    // otherwise ensuring as an invariant that the final chunk - which is
384
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
385
    //
386
    // As such, at least one byte is remaining, and thus calling `f_whole` is
387
    // appropriate.
388
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
389
390
    // Process the block.
391
0
    MutableIVec wholevec = {};
392
0
    wholevec.len = in.size();
393
0
    wholevec.*ReadFrom = in.data();
394
0
    if constexpr (WriteOut) {
395
0
      wholevec.out = out;
396
0
    }
397
0
    if (!call_func(f_whole, wholevec)) {
398
0
      return false;
399
0
    }
400
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
401
0
                        current_range_rest);
402
403
    // Set the new position.
404
0
    current_range_head = collect_from_head;
405
0
    current_range_rest = collect_from_rest;
406
0
  }
407
408
  // If current_range_head.len is zero, then the last item of ivecs is empty.
409
  // That however was excluded at the start of the function to ensure `f_final`
410
  // is always used for the last call.
411
5.01k
  assert(current_range_head.len != 0);
412
413
5.01k
  return call_func(f_final, current_range_head);
414
5.01k
}
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
287
158
                              const FFinal &f_final) {
288
158
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
158
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
158
    if constexpr (WriteOut) {
292
158
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
158
    } else {
294
158
      return f(ivec.*ReadFrom, ivec.len);
295
158
    }
296
158
  };
297
  // Helper to cut from the start of an IVec.
298
158
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
299
158
    ivec.*ReadFrom += by;
300
158
    if constexpr (WriteOut) {
301
158
      ivec.out += by;
302
158
    }
303
158
    ivec.len -= by;
304
158
  };
305
  // Helper to copy a range to an iovec list.
306
158
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
158
                                 Span<IVec> rest) {
308
158
    if constexpr (WriteOut) {
309
158
      internal::CopySpanToIOVec(out, head, rest);
310
158
    }
311
158
  };
312
313
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
314
  // detecting being at the end and calling `f_final` at the appropriate time.
315
158
  Span<IVec> ivecs_trimmed = ivecs;
316
158
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
158
  if (ivecs_trimmed.empty()) {
320
0
    return call_func(f_final, IVec{});
321
0
  }
322
323
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
324
  // last can be empty.
325
326
158
  MutableIVec current_range_head = ivecs_trimmed.front();
327
158
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
158
  while (!current_range_rest.empty()) {
329
    // Process as many whole blocks as possible.
330
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
331
0
    if (whole_blocks_len != 0) {
332
0
      MutableIVec whole_part = current_range_head;
333
0
      whole_part.len = whole_blocks_len;
334
0
      if (!call_func(f_whole, whole_part)) {
335
0
        return false;
336
0
      }
337
0
      remove_prefix(current_range_head, whole_blocks_len);
338
0
    }
339
340
0
    if (current_range_head.len == 0) {
341
0
      current_range_head = current_range_rest.front();
342
0
      current_range_rest = current_range_rest.subspan(1);
343
0
      continue;
344
0
    }
345
346
    // Collect a whole block.
347
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
348
0
    alignas(BlockSize) uint8_t out[BlockSize];
349
0
    MutableIVec collect_from_head = current_range_head;
350
0
    Span<IVec> collect_from_rest = current_range_rest;
351
0
    while (in.size() <= BlockSize) {
352
0
      size_t remaining = BlockSize - in.size();
353
0
      if (remaining < collect_from_head.len) {
354
        // Got enough to complete the block _and more_.
355
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
356
0
        remove_prefix(collect_from_head, remaining);
357
0
        break;
358
0
      }
359
      // Consume all of `ivec` and advance.
360
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
361
0
      if (collect_from_rest.empty()) {
362
        // Nothing left - so this is the final block.
363
0
        auto finalout = Span(out).first(in.size());
364
0
        MutableIVec finalvec = {};
365
0
        finalvec.len = in.size();
366
0
        finalvec.*ReadFrom = in.data();
367
0
        if constexpr (WriteOut) {
368
0
          finalvec.out = finalout.data();
369
0
        }
370
0
        if (!call_func(f_final, finalvec)) {
371
0
          return false;
372
0
        }
373
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
374
0
        return true;
375
0
      }
376
0
      collect_from_head = collect_from_rest.front();
377
0
      collect_from_rest = collect_from_rest.subspan(1);
378
0
    }
379
0
    assert(in.size() == BlockSize);
380
381
    // The above loop ensures this condition by the `break` only happening if
382
    // `collect_from_head` has at least one byte remaining, and the loop
383
    // otherwise ensuring as an invariant that the final chunk - which is
384
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
385
    //
386
    // As such, at least one byte is remaining, and thus calling `f_whole` is
387
    // appropriate.
388
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
389
390
    // Process the block.
391
0
    MutableIVec wholevec = {};
392
0
    wholevec.len = in.size();
393
0
    wholevec.*ReadFrom = in.data();
394
0
    if constexpr (WriteOut) {
395
0
      wholevec.out = out;
396
0
    }
397
0
    if (!call_func(f_whole, wholevec)) {
398
0
      return false;
399
0
    }
400
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
401
0
                        current_range_rest);
402
403
    // Set the new position.
404
0
    current_range_head = collect_from_head;
405
0
    current_range_rest = collect_from_rest;
406
0
  }
407
408
  // If current_range_head.len is zero, then the last item of ivecs is empty.
409
  // That however was excluded at the start of the function to ensure `f_final`
410
  // is always used for the last call.
411
158
  assert(current_range_head.len != 0);
412
413
158
  return call_func(f_final, current_range_head);
414
158
}
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
287
3.59k
                              const FFinal &f_final) {
288
3.59k
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
3.59k
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
3.59k
    if constexpr (WriteOut) {
292
3.59k
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
3.59k
    } else {
294
3.59k
      return f(ivec.*ReadFrom, ivec.len);
295
3.59k
    }
296
3.59k
  };
297
  // Helper to cut from the start of an IVec.
298
3.59k
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
299
3.59k
    ivec.*ReadFrom += by;
300
3.59k
    if constexpr (WriteOut) {
301
3.59k
      ivec.out += by;
302
3.59k
    }
303
3.59k
    ivec.len -= by;
304
3.59k
  };
305
  // Helper to copy a range to an iovec list.
306
3.59k
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
3.59k
                                 Span<IVec> rest) {
308
3.59k
    if constexpr (WriteOut) {
309
3.59k
      internal::CopySpanToIOVec(out, head, rest);
310
3.59k
    }
311
3.59k
  };
312
313
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
314
  // detecting being at the end and calling `f_final` at the appropriate time.
315
3.59k
  Span<IVec> ivecs_trimmed = ivecs;
316
3.59k
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
3.59k
  if (ivecs_trimmed.empty()) {
320
0
    return call_func(f_final, IVec{});
321
0
  }
322
323
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
324
  // last can be empty.
325
326
3.59k
  MutableIVec current_range_head = ivecs_trimmed.front();
327
3.59k
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
3.59k
  while (!current_range_rest.empty()) {
329
    // Process as many whole blocks as possible.
330
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
331
0
    if (whole_blocks_len != 0) {
332
0
      MutableIVec whole_part = current_range_head;
333
0
      whole_part.len = whole_blocks_len;
334
0
      if (!call_func(f_whole, whole_part)) {
335
0
        return false;
336
0
      }
337
0
      remove_prefix(current_range_head, whole_blocks_len);
338
0
    }
339
340
0
    if (current_range_head.len == 0) {
341
0
      current_range_head = current_range_rest.front();
342
0
      current_range_rest = current_range_rest.subspan(1);
343
0
      continue;
344
0
    }
345
346
    // Collect a whole block.
347
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
348
0
    alignas(BlockSize) uint8_t out[BlockSize];
349
0
    MutableIVec collect_from_head = current_range_head;
350
0
    Span<IVec> collect_from_rest = current_range_rest;
351
0
    while (in.size() <= BlockSize) {
352
0
      size_t remaining = BlockSize - in.size();
353
0
      if (remaining < collect_from_head.len) {
354
        // Got enough to complete the block _and more_.
355
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
356
0
        remove_prefix(collect_from_head, remaining);
357
0
        break;
358
0
      }
359
      // Consume all of `ivec` and advance.
360
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
361
0
      if (collect_from_rest.empty()) {
362
        // Nothing left - so this is the final block.
363
0
        auto finalout = Span(out).first(in.size());
364
0
        MutableIVec finalvec = {};
365
0
        finalvec.len = in.size();
366
0
        finalvec.*ReadFrom = in.data();
367
0
        if constexpr (WriteOut) {
368
0
          finalvec.out = finalout.data();
369
0
        }
370
0
        if (!call_func(f_final, finalvec)) {
371
0
          return false;
372
0
        }
373
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
374
0
        return true;
375
0
      }
376
0
      collect_from_head = collect_from_rest.front();
377
0
      collect_from_rest = collect_from_rest.subspan(1);
378
0
    }
379
0
    assert(in.size() == BlockSize);
380
381
    // The above loop ensures this condition by the `break` only happening if
382
    // `collect_from_head` has at least one byte remaining, and the loop
383
    // otherwise ensuring as an invariant that the final chunk - which is
384
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
385
    //
386
    // As such, at least one byte is remaining, and thus calling `f_whole` is
387
    // appropriate.
388
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
389
390
    // Process the block.
391
0
    MutableIVec wholevec = {};
392
0
    wholevec.len = in.size();
393
0
    wholevec.*ReadFrom = in.data();
394
0
    if constexpr (WriteOut) {
395
0
      wholevec.out = out;
396
0
    }
397
0
    if (!call_func(f_whole, wholevec)) {
398
0
      return false;
399
0
    }
400
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
401
0
                        current_range_rest);
402
403
    // Set the new position.
404
0
    current_range_head = collect_from_head;
405
0
    current_range_rest = collect_from_rest;
406
0
  }
407
408
  // If current_range_head.len is zero, then the last item of ivecs is empty.
409
  // That however was excluded at the start of the function to ensure `f_final`
410
  // is always used for the last call.
411
3.59k
  assert(current_range_head.len != 0);
412
413
3.59k
  return call_func(f_final, current_range_head);
414
3.59k
}
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
287
564
                              const FFinal &f_final) {
288
564
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
564
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
564
    if constexpr (WriteOut) {
292
564
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
564
    } else {
294
564
      return f(ivec.*ReadFrom, ivec.len);
295
564
    }
296
564
  };
297
  // Helper to cut from the start of an IVec.
298
564
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
299
564
    ivec.*ReadFrom += by;
300
564
    if constexpr (WriteOut) {
301
564
      ivec.out += by;
302
564
    }
303
564
    ivec.len -= by;
304
564
  };
305
  // Helper to copy a range to an iovec list.
306
564
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
564
                                 Span<IVec> rest) {
308
564
    if constexpr (WriteOut) {
309
564
      internal::CopySpanToIOVec(out, head, rest);
310
564
    }
311
564
  };
312
313
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
314
  // detecting being at the end and calling `f_final` at the appropriate time.
315
564
  Span<IVec> ivecs_trimmed = ivecs;
316
564
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
564
  if (ivecs_trimmed.empty()) {
320
0
    return call_func(f_final, IVec{});
321
0
  }
322
323
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
324
  // last can be empty.
325
326
564
  MutableIVec current_range_head = ivecs_trimmed.front();
327
564
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
564
  while (!current_range_rest.empty()) {
329
    // Process as many whole blocks as possible.
330
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
331
0
    if (whole_blocks_len != 0) {
332
0
      MutableIVec whole_part = current_range_head;
333
0
      whole_part.len = whole_blocks_len;
334
0
      if (!call_func(f_whole, whole_part)) {
335
0
        return false;
336
0
      }
337
0
      remove_prefix(current_range_head, whole_blocks_len);
338
0
    }
339
340
0
    if (current_range_head.len == 0) {
341
0
      current_range_head = current_range_rest.front();
342
0
      current_range_rest = current_range_rest.subspan(1);
343
0
      continue;
344
0
    }
345
346
    // Collect a whole block.
347
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
348
0
    alignas(BlockSize) uint8_t out[BlockSize];
349
0
    MutableIVec collect_from_head = current_range_head;
350
0
    Span<IVec> collect_from_rest = current_range_rest;
351
0
    while (in.size() <= BlockSize) {
352
0
      size_t remaining = BlockSize - in.size();
353
0
      if (remaining < collect_from_head.len) {
354
        // Got enough to complete the block _and more_.
355
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
356
0
        remove_prefix(collect_from_head, remaining);
357
0
        break;
358
0
      }
359
      // Consume all of `ivec` and advance.
360
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
361
0
      if (collect_from_rest.empty()) {
362
        // Nothing left - so this is the final block.
363
0
        auto finalout = Span(out).first(in.size());
364
0
        MutableIVec finalvec = {};
365
0
        finalvec.len = in.size();
366
0
        finalvec.*ReadFrom = in.data();
367
0
        if constexpr (WriteOut) {
368
0
          finalvec.out = finalout.data();
369
0
        }
370
0
        if (!call_func(f_final, finalvec)) {
371
0
          return false;
372
0
        }
373
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
374
0
        return true;
375
0
      }
376
0
      collect_from_head = collect_from_rest.front();
377
0
      collect_from_rest = collect_from_rest.subspan(1);
378
0
    }
379
0
    assert(in.size() == BlockSize);
380
381
    // The above loop ensures this condition by the `break` only happening if
382
    // `collect_from_head` has at least one byte remaining, and the loop
383
    // otherwise ensuring as an invariant that the final chunk - which is
384
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
385
    //
386
    // As such, at least one byte is remaining, and thus calling `f_whole` is
387
    // appropriate.
388
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
389
390
    // Process the block.
391
0
    MutableIVec wholevec = {};
392
0
    wholevec.len = in.size();
393
0
    wholevec.*ReadFrom = in.data();
394
0
    if constexpr (WriteOut) {
395
0
      wholevec.out = out;
396
0
    }
397
0
    if (!call_func(f_whole, wholevec)) {
398
0
      return false;
399
0
    }
400
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
401
0
                        current_range_rest);
402
403
    // Set the new position.
404
0
    current_range_head = collect_from_head;
405
0
    current_range_rest = collect_from_rest;
406
0
  }
407
408
  // If current_range_head.len is zero, then the last item of ivecs is empty.
409
  // That however was excluded at the start of the function to ensure `f_final`
410
  // is always used for the last call.
411
564
  assert(current_range_head.len != 0);
412
413
564
  return call_func(f_final, current_range_head);
414
564
}
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
287
689
                              const FFinal &f_final) {
288
689
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
689
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
689
    if constexpr (WriteOut) {
292
689
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
689
    } else {
294
689
      return f(ivec.*ReadFrom, ivec.len);
295
689
    }
296
689
  };
297
  // Helper to cut from the start of an IVec.
298
689
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
299
689
    ivec.*ReadFrom += by;
300
689
    if constexpr (WriteOut) {
301
689
      ivec.out += by;
302
689
    }
303
689
    ivec.len -= by;
304
689
  };
305
  // Helper to copy a range to an iovec list.
306
689
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
689
                                 Span<IVec> rest) {
308
689
    if constexpr (WriteOut) {
309
689
      internal::CopySpanToIOVec(out, head, rest);
310
689
    }
311
689
  };
312
313
  // Ensure the last item in `ivecs` is nonempty. This is necessary for
314
  // detecting being at the end and calling `f_final` at the appropriate time.
315
689
  Span<IVec> ivecs_trimmed = ivecs;
316
689
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
689
  if (ivecs_trimmed.empty()) {
320
0
    return call_func(f_final, IVec{});
321
0
  }
322
323
  // Now there are at least two non-empty `ivecs`, and neither the first nor the
324
  // last can be empty.
325
326
689
  MutableIVec current_range_head = ivecs_trimmed.front();
327
689
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
689
  while (!current_range_rest.empty()) {
329
    // Process as many whole blocks as possible.
330
0
    size_t whole_blocks_len = (current_range_head.len / BlockSize) * BlockSize;
331
0
    if (whole_blocks_len != 0) {
332
0
      MutableIVec whole_part = current_range_head;
333
0
      whole_part.len = whole_blocks_len;
334
0
      if (!call_func(f_whole, whole_part)) {
335
0
        return false;
336
0
      }
337
0
      remove_prefix(current_range_head, whole_blocks_len);
338
0
    }
339
340
0
    if (current_range_head.len == 0) {
341
0
      current_range_head = current_range_rest.front();
342
0
      current_range_rest = current_range_rest.subspan(1);
343
0
      continue;
344
0
    }
345
346
    // Collect a whole block.
347
0
    alignas(BlockSize) InplaceVector<uint8_t, BlockSize> in;
348
0
    alignas(BlockSize) uint8_t out[BlockSize];
349
0
    MutableIVec collect_from_head = current_range_head;
350
0
    Span<IVec> collect_from_rest = current_range_rest;
351
0
    while (in.size() <= BlockSize) {
352
0
      size_t remaining = BlockSize - in.size();
353
0
      if (remaining < collect_from_head.len) {
354
        // Got enough to complete the block _and more_.
355
0
        in.Append(Span(collect_from_head.*ReadFrom, remaining));
356
0
        remove_prefix(collect_from_head, remaining);
357
0
        break;
358
0
      }
359
      // Consume all of `ivec` and advance.
360
0
      in.Append(Span(collect_from_head.*ReadFrom, collect_from_head.len));
361
0
      if (collect_from_rest.empty()) {
362
        // Nothing left - so this is the final block.
363
0
        auto finalout = Span(out).first(in.size());
364
0
        MutableIVec finalvec = {};
365
0
        finalvec.len = in.size();
366
0
        finalvec.*ReadFrom = in.data();
367
0
        if constexpr (WriteOut) {
368
0
          finalvec.out = finalout.data();
369
0
        }
370
0
        if (!call_func(f_final, finalvec)) {
371
0
          return false;
372
0
        }
373
0
        maybe_copy_to_iovec(finalout, current_range_head, current_range_rest);
374
0
        return true;
375
0
      }
376
0
      collect_from_head = collect_from_rest.front();
377
0
      collect_from_rest = collect_from_rest.subspan(1);
378
0
    }
379
0
    assert(in.size() == BlockSize);
380
381
    // The above loop ensures this condition by the `break` only happening if
382
    // `collect_from_head` has at least one byte remaining, and the loop
383
    // otherwise ensuring as an invariant that the final chunk - which is
384
    // nonempty - is among `collect_from_head` and `collect_from_rest`.
385
    //
386
    // As such, at least one byte is remaining, and thus calling `f_whole` is
387
    // appropriate.
388
0
    assert(collect_from_head.len != 0 || !collect_from_rest.empty());
389
390
    // Process the block.
391
0
    MutableIVec wholevec = {};
392
0
    wholevec.len = in.size();
393
0
    wholevec.*ReadFrom = in.data();
394
0
    if constexpr (WriteOut) {
395
0
      wholevec.out = out;
396
0
    }
397
0
    if (!call_func(f_whole, wholevec)) {
398
0
      return false;
399
0
    }
400
0
    maybe_copy_to_iovec(Span(out).first(in.size()), current_range_head,
401
0
                        current_range_rest);
402
403
    // Set the new position.
404
0
    current_range_head = collect_from_head;
405
0
    current_range_rest = collect_from_rest;
406
0
  }
407
408
  // If current_range_head.len is zero, then the last item of ivecs is empty.
409
  // That however was excluded at the start of the function to ensure `f_final`
410
  // is always used for the last call.
411
689
  assert(current_range_head.len != 0);
412
413
689
  return call_func(f_final, current_range_head);
414
689
}
415
416
// ForEachOutBlockRange is like `ForEachBlockRange` but reads from a
417
// `CRYPTO_IOVEC`'s `out` member instead.
418
template <
419
    size_t BlockSize,
420
    typename /* int(const uint8_t *in, [uint8_t *out,] size_t len) */ FWhole,
421
    typename /* int(const uint8_t *in, [uint8_t *out,] size_t len) */
422
    FFinal>
423
inline int ForEachOutBlockRange(Span<const CRYPTO_IOVEC> iovecs,
424
0
                                const FWhole &f_whole, const FFinal &f_final) {
425
0
  return ForEachBlockRange<BlockSize, /*WriteOut=*/false, const CRYPTO_IOVEC,
426
0
                           /*ReadFromT=*/uint8_t *,
427
0
                           /*ReadFrom=*/&CRYPTO_IOVEC::out>(iovecs, f_whole,
428
0
                                                            f_final);
429
0
}
430
431
// ForEachBlockRange_Dynamic is simply `ForEachBlockRange` with a
432
// runtime dispatch on the block size.
433
template <
434
    bool WriteOut = false, typename IVec, typename ReadFromT = const uint8_t *,
435
    ReadFromT IVec::*ReadFrom = &IVec::in,
436
    typename /* int(const uint8_t *in, uint8_t *out, size_t len) */ FWhole,
437
    typename /* int(const uint8_t *in, uint8_t *out, size_t len) */
438
    FFinal>
439
inline int ForEachBlockRange_Dynamic(size_t block_size, Span<IVec> ivecs,
440
                                     const FWhole &f_whole,
441
5.01k
                                     const FFinal &f_final) {
442
5.01k
  switch (block_size) {
443
722
    case 8:
444
722
      return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>(
445
722
          ivecs, f_whole, f_final);
446
0
      break;
447
4.28k
    case 16:
448
4.28k
      return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>(
449
4.28k
          ivecs, f_whole, f_final);
450
0
      break;
451
0
    default:
452
0
      return 0;
453
5.01k
  }
454
5.01k
}
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
441
3.75k
                                     const FFinal &f_final) {
442
3.75k
  switch (block_size) {
443
158
    case 8:
444
158
      return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>(
445
158
          ivecs, f_whole, f_final);
446
0
      break;
447
3.59k
    case 16:
448
3.59k
      return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>(
449
3.59k
          ivecs, f_whole, f_final);
450
0
      break;
451
0
    default:
452
0
      return 0;
453
3.75k
  }
454
3.75k
}
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
441
1.25k
                                     const FFinal &f_final) {
442
1.25k
  switch (block_size) {
443
564
    case 8:
444
564
      return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>(
445
564
          ivecs, f_whole, f_final);
446
0
      break;
447
689
    case 16:
448
689
      return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>(
449
689
          ivecs, f_whole, f_final);
450
0
      break;
451
0
    default:
452
0
      return 0;
453
1.25k
  }
454
1.25k
}
455
456
}  // namespace iovec
457
458
BSSL_NAMESPACE_END
459
460
#endif  // OPENSSL_HEADER_CRYPTO_FIPSMODULE_CIPHER_INTERNAL_H