Coverage Report

Created: 2026-04-15 06: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
182k
#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 lenght 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.8k
inline void CopySpan(Span<const uint8_t> from, Span<uint8_t> to) {
148
12.8k
  BSSL_CHECK(from.size() == to.size());
149
12.8k
  std::copy(from.begin(), from.end(), to.begin());
150
12.8k
}
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.9k
inline void CopyToPrefix(Span<const uint8_t> from, Span<uint8_t> to) {
158
10.9k
  CopySpan(from, to.first(from.size()));
159
10.9k
}
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
20.8k
inline bool IsValid(Span<IVec> ivecs) {
170
20.8k
  if (ivecs.size() > CRYPTO_IOVEC_MAX) {
171
0
    return false;
172
0
  }
173
20.8k
  size_t allowed = SIZE_MAX;
174
21.4k
  for (const IVec &ivec : ivecs) {
175
21.4k
    size_t len = ivec.len;
176
21.4k
    if (len > allowed) {
177
0
      return false;
178
0
    }
179
21.4k
    allowed -= len;
180
21.4k
  }
181
20.8k
  return true;
182
20.8k
}
bool bssl::iovec::IsValid<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>)
Line
Count
Source
169
10.4k
inline bool IsValid(Span<IVec> ivecs) {
170
10.4k
  if (ivecs.size() > CRYPTO_IOVEC_MAX) {
171
0
    return false;
172
0
  }
173
10.4k
  size_t allowed = SIZE_MAX;
174
11.0k
  for (const IVec &ivec : ivecs) {
175
11.0k
    size_t len = ivec.len;
176
11.0k
    if (len > allowed) {
177
0
      return false;
178
0
    }
179
11.0k
    allowed -= len;
180
11.0k
  }
181
10.4k
  return true;
182
10.4k
}
bool bssl::iovec::IsValid<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>)
Line
Count
Source
169
10.4k
inline bool IsValid(Span<IVec> ivecs) {
170
10.4k
  if (ivecs.size() > CRYPTO_IOVEC_MAX) {
171
0
    return false;
172
0
  }
173
10.4k
  size_t allowed = SIZE_MAX;
174
10.4k
  for (const IVec &ivec : ivecs) {
175
10.4k
    size_t len = ivec.len;
176
10.4k
    if (len > allowed) {
177
0
      return false;
178
0
    }
179
10.4k
    allowed -= len;
180
10.4k
  }
181
10.4k
  return true;
182
10.4k
}
183
184
// Length returns the total length in bytes of a given |CRYPTO_IVEC| or
185
// |CRYPTO_IOVEC|.
186
template <typename IVec>
187
12.8k
inline size_t TotalLength(Span<IVec> ivecs) {
188
12.8k
  size_t total = 0;
189
13.0k
  for (const IVec &ivec : ivecs) {
190
13.0k
    total += ivec.len;
191
13.0k
  }
192
12.8k
  return total;
193
12.8k
}
unsigned long bssl::iovec::TotalLength<crypto_iovec_st const>(bssl::Span<crypto_iovec_st const, 18446744073709551615ul>)
Line
Count
Source
187
7.41k
inline size_t TotalLength(Span<IVec> ivecs) {
188
7.41k
  size_t total = 0;
189
7.66k
  for (const IVec &ivec : ivecs) {
190
7.66k
    total += ivec.len;
191
7.66k
  }
192
7.41k
  return total;
193
7.41k
}
unsigned long bssl::iovec::TotalLength<crypto_ivec_st const>(bssl::Span<crypto_ivec_st const, 18446744073709551615ul>)
Line
Count
Source
187
5.40k
inline size_t TotalLength(Span<IVec> ivecs) {
188
5.40k
  size_t total = 0;
189
5.40k
  for (const IVec &ivec : ivecs) {
190
5.40k
    total += ivec.len;
191
5.40k
  }
192
5.40k
  return total;
193
5.40k
}
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.99k
    Span<uint8_t> suffix_buf, Span<IVec> ivecs) {
208
  // Get the trivial case out.
209
3.99k
  if (suffix_buf.empty()) {
210
0
    return suffix_buf;
211
0
  }
212
  // Strip trailing zero length chunks.
213
3.99k
  while (!ivecs.empty() && ivecs.back().len == 0) {
214
0
    ivecs = ivecs.first(ivecs.size() - 1);
215
0
  }
216
3.99k
  if (ivecs.empty()) {
217
0
    return std::nullopt;
218
0
  }
219
  // Is the requested chunk entirely contained? If so, just return it.
220
3.99k
  if (ivecs.back().len >= suffix_buf.size()) {
221
3.99k
    ivecs.back().len -= suffix_buf.size();
222
3.99k
    return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size());
223
3.99k
  }
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.99k
    Span<uint8_t> suffix_buf, Span<IVec> ivecs) {
208
  // Get the trivial case out.
209
3.99k
  if (suffix_buf.empty()) {
210
0
    return suffix_buf;
211
0
  }
212
  // Strip trailing zero length chunks.
213
3.99k
  while (!ivecs.empty() && ivecs.back().len == 0) {
214
0
    ivecs = ivecs.first(ivecs.size() - 1);
215
0
  }
216
3.99k
  if (ivecs.empty()) {
217
0
    return std::nullopt;
218
0
  }
219
  // Is the requested chunk entirely contained? If so, just return it.
220
3.99k
  if (ivecs.back().len >= suffix_buf.size()) {
221
3.99k
    ivecs.back().len -= suffix_buf.size();
222
3.99k
    return Span(ivecs.back().*ReadFrom + ivecs.back().len, suffix_buf.size());
223
3.99k
  }
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.99k
    Span<uint8_t> out, Span<CRYPTO_IOVEC> iovecs) {
245
3.99k
  return GetAndRemoveSuffix<CRYPTO_IOVEC, /*ReadFromT=*/uint8_t *,
246
3.99k
                            /*ReadFrom=*/&CRYPTO_IOVEC::out>(out, iovecs);
247
3.99k
}
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.40k
                              const FFinal &f_final) {
288
5.40k
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
5.40k
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
5.40k
    if constexpr (WriteOut) {
292
5.40k
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
5.40k
    } else {
294
0
      return f(ivec.*ReadFrom, ivec.len);
295
0
    }
296
5.40k
  };
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
137
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
137
    if constexpr (WriteOut) {
292
137
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
    } else {
294
      return f(ivec.*ReadFrom, ivec.len);
295
    }
296
137
  };
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.93k
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
3.93k
    if constexpr (WriteOut) {
292
3.93k
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
    } else {
294
      return f(ivec.*ReadFrom, ivec.len);
295
    }
296
3.93k
  };
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
626
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
626
    if constexpr (WriteOut) {
292
626
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
    } else {
294
      return f(ivec.*ReadFrom, ivec.len);
295
    }
296
626
  };
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
714
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
714
    if constexpr (WriteOut) {
292
714
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
    } else {
294
      return f(ivec.*ReadFrom, ivec.len);
295
    }
296
714
  };
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.40k
  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.40k
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
5.40k
                                 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.40k
  Span<IVec> ivecs_trimmed = ivecs;
316
5.40k
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
5.40k
  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.40k
  MutableIVec current_range_head = ivecs_trimmed.front();
327
5.40k
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
5.40k
  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.40k
  assert(current_range_head.len != 0);
412
413
5.40k
  return call_func(f_final, current_range_head);
414
5.40k
}
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
137
                              const FFinal &f_final) {
288
137
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
137
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
137
    if constexpr (WriteOut) {
292
137
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
137
    } else {
294
137
      return f(ivec.*ReadFrom, ivec.len);
295
137
    }
296
137
  };
297
  // Helper to cut from the start of an IVec.
298
137
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
299
137
    ivec.*ReadFrom += by;
300
137
    if constexpr (WriteOut) {
301
137
      ivec.out += by;
302
137
    }
303
137
    ivec.len -= by;
304
137
  };
305
  // Helper to copy a range to an iovec list.
306
137
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
137
                                 Span<IVec> rest) {
308
137
    if constexpr (WriteOut) {
309
137
      internal::CopySpanToIOVec(out, head, rest);
310
137
    }
311
137
  };
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
137
  Span<IVec> ivecs_trimmed = ivecs;
316
137
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
137
  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
137
  MutableIVec current_range_head = ivecs_trimmed.front();
327
137
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
137
  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
137
  assert(current_range_head.len != 0);
412
413
137
  return call_func(f_final, current_range_head);
414
137
}
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.93k
                              const FFinal &f_final) {
288
3.93k
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
3.93k
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
3.93k
    if constexpr (WriteOut) {
292
3.93k
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
3.93k
    } else {
294
3.93k
      return f(ivec.*ReadFrom, ivec.len);
295
3.93k
    }
296
3.93k
  };
297
  // Helper to cut from the start of an IVec.
298
3.93k
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
299
3.93k
    ivec.*ReadFrom += by;
300
3.93k
    if constexpr (WriteOut) {
301
3.93k
      ivec.out += by;
302
3.93k
    }
303
3.93k
    ivec.len -= by;
304
3.93k
  };
305
  // Helper to copy a range to an iovec list.
306
3.93k
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
3.93k
                                 Span<IVec> rest) {
308
3.93k
    if constexpr (WriteOut) {
309
3.93k
      internal::CopySpanToIOVec(out, head, rest);
310
3.93k
    }
311
3.93k
  };
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.93k
  Span<IVec> ivecs_trimmed = ivecs;
316
3.93k
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
3.93k
  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.93k
  MutableIVec current_range_head = ivecs_trimmed.front();
327
3.93k
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
3.93k
  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.93k
  assert(current_range_head.len != 0);
412
413
3.93k
  return call_func(f_final, current_range_head);
414
3.93k
}
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
626
                              const FFinal &f_final) {
288
626
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
626
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
626
    if constexpr (WriteOut) {
292
626
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
626
    } else {
294
626
      return f(ivec.*ReadFrom, ivec.len);
295
626
    }
296
626
  };
297
  // Helper to cut from the start of an IVec.
298
626
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
299
626
    ivec.*ReadFrom += by;
300
626
    if constexpr (WriteOut) {
301
626
      ivec.out += by;
302
626
    }
303
626
    ivec.len -= by;
304
626
  };
305
  // Helper to copy a range to an iovec list.
306
626
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
626
                                 Span<IVec> rest) {
308
626
    if constexpr (WriteOut) {
309
626
      internal::CopySpanToIOVec(out, head, rest);
310
626
    }
311
626
  };
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
626
  Span<IVec> ivecs_trimmed = ivecs;
316
626
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
626
  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
626
  MutableIVec current_range_head = ivecs_trimmed.front();
327
626
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
626
  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
626
  assert(current_range_head.len != 0);
412
413
626
  return call_func(f_final, current_range_head);
414
626
}
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
714
                              const FFinal &f_final) {
288
714
  using MutableIVec = std::remove_const_t<IVec>;
289
  // Helper to make the function calls simpler.
290
714
  auto call_func = [&](const auto &f, const IVec &ivec) {
291
714
    if constexpr (WriteOut) {
292
714
      return f(ivec.*ReadFrom, ivec.out, ivec.len);
293
714
    } else {
294
714
      return f(ivec.*ReadFrom, ivec.len);
295
714
    }
296
714
  };
297
  // Helper to cut from the start of an IVec.
298
714
  auto remove_prefix = [&](MutableIVec &ivec, size_t by) {
299
714
    ivec.*ReadFrom += by;
300
714
    if constexpr (WriteOut) {
301
714
      ivec.out += by;
302
714
    }
303
714
    ivec.len -= by;
304
714
  };
305
  // Helper to copy a range to an iovec list.
306
714
  auto maybe_copy_to_iovec = [&](Span<const uint8_t> out, MutableIVec head,
307
714
                                 Span<IVec> rest) {
308
714
    if constexpr (WriteOut) {
309
714
      internal::CopySpanToIOVec(out, head, rest);
310
714
    }
311
714
  };
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
714
  Span<IVec> ivecs_trimmed = ivecs;
316
714
  while (!ivecs_trimmed.empty() && ivecs_trimmed.back().len == 0) {
317
0
    ivecs_trimmed = ivecs_trimmed.first(ivecs_trimmed.size() - 1);
318
0
  }
319
714
  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
714
  MutableIVec current_range_head = ivecs_trimmed.front();
327
714
  Span<IVec> current_range_rest = ivecs_trimmed.subspan(1);
328
714
  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
714
  assert(current_range_head.len != 0);
412
413
714
  return call_func(f_final, current_range_head);
414
714
}
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.40k
                                     const FFinal &f_final) {
442
5.40k
  switch (block_size) {
443
763
    case 8:
444
763
      return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>(
445
763
          ivecs, f_whole, f_final);
446
0
      break;
447
4.64k
    case 16:
448
4.64k
      return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>(
449
4.64k
          ivecs, f_whole, f_final);
450
0
      break;
451
0
    default:
452
0
      return 0;
453
5.40k
  }
454
5.40k
}
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
4.06k
                                     const FFinal &f_final) {
442
4.06k
  switch (block_size) {
443
137
    case 8:
444
137
      return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>(
445
137
          ivecs, f_whole, f_final);
446
0
      break;
447
3.93k
    case 16:
448
3.93k
      return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>(
449
3.93k
          ivecs, f_whole, f_final);
450
0
      break;
451
0
    default:
452
0
      return 0;
453
4.06k
  }
454
4.06k
}
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.34k
                                     const FFinal &f_final) {
442
1.34k
  switch (block_size) {
443
626
    case 8:
444
626
      return ForEachBlockRange<8, WriteOut, IVec, ReadFromT, ReadFrom>(
445
626
          ivecs, f_whole, f_final);
446
0
      break;
447
714
    case 16:
448
714
      return ForEachBlockRange<16, WriteOut, IVec, ReadFromT, ReadFrom>(
449
714
          ivecs, f_whole, f_final);
450
0
      break;
451
0
    default:
452
0
      return 0;
453
1.34k
  }
454
1.34k
}
455
456
}  // namespace iovec
457
458
BSSL_NAMESPACE_END
459
460
#endif  // OPENSSL_HEADER_CRYPTO_FIPSMODULE_CIPHER_INTERNAL_H