Coverage Report

Created: 2026-08-08 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/cipher/aead.cc.inc
Line
Count
Source
1
// Copyright 2014 The BoringSSL Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include <openssl/aead.h>
16
17
#include <optional>
18
19
#include <assert.h>
20
#include <string.h>
21
22
#include <openssl/cipher.h>
23
#include <openssl/err.h>
24
#include <openssl/mem.h>
25
#include <openssl/span.h>
26
27
#include "../../internal.h"
28
#include "../../mem_internal.h"
29
#include "internal.h"
30
31
32
using namespace bssl;
33
34
166k
size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; }
35
36
443k
size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead) { return aead->nonce_len; }
37
38
12.8k
size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead) { return aead->overhead; }
39
40
0
size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; }
41
42
349k
void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) {
43
349k
  OPENSSL_memset(ctx, 0, sizeof(EVP_AEAD_CTX));
44
349k
}
45
46
EVP_AEAD_CTX *EVP_AEAD_CTX_new(const EVP_AEAD *aead, const uint8_t *key,
47
0
                               size_t key_len, size_t tag_len) {
48
0
  EVP_AEAD_CTX *ctx = New<EVP_AEAD_CTX>();
49
0
  if (!ctx) {
50
0
    return nullptr;
51
0
  }
52
0
  EVP_AEAD_CTX_zero(ctx);
53
54
0
  if (EVP_AEAD_CTX_init(ctx, aead, key, key_len, tag_len, nullptr)) {
55
0
    return ctx;
56
0
  }
57
58
0
  EVP_AEAD_CTX_free(ctx);
59
0
  return nullptr;
60
0
}
61
62
0
void EVP_AEAD_CTX_free(EVP_AEAD_CTX *ctx) {
63
0
  if (ctx == nullptr) {
64
0
    return;
65
0
  }
66
0
  EVP_AEAD_CTX_cleanup(ctx);
67
0
  Delete(ctx);
68
0
}
69
70
int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
71
                      const uint8_t *key, size_t key_len, size_t tag_len,
72
283
                      ENGINE *impl) {
73
283
  if (!aead->init) {
74
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_DIRECTION_SET);
75
0
    ctx->aead = nullptr;
76
0
    return 0;
77
0
  }
78
283
  return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len,
79
283
                                          evp_aead_open);
80
283
}
81
82
int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead,
83
                                     const uint8_t *key, size_t key_len,
84
                                     size_t tag_len,
85
136k
                                     enum evp_aead_direction_t dir) {
86
136k
  if (key_len != aead->key_len) {
87
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE);
88
0
    ctx->aead = nullptr;
89
0
    return 0;
90
0
  }
91
92
136k
  ctx->aead = aead;
93
94
136k
  int ok;
95
136k
  if (aead->init) {
96
105k
    ok = aead->init(ctx, key, key_len, tag_len);
97
105k
  } else {
98
30.7k
    ok = aead->init_with_direction(ctx, key, key_len, tag_len, dir);
99
30.7k
  }
100
101
136k
  if (!ok) {
102
0
    ctx->aead = nullptr;
103
0
  }
104
105
136k
  return ok;
106
136k
}
107
108
348k
void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) {
109
348k
  if (ctx->aead == nullptr) {
110
212k
    return;
111
212k
  }
112
136k
  ctx->aead->cleanup(ctx);
113
136k
  ctx->aead = nullptr;
114
136k
}
115
116
// check_alias returns 1 if `out` is compatible with `in` and 0 otherwise. If
117
// `in` and `out` alias, we require that `in` == `out`.
118
static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out,
119
9.89k
                       size_t out_len) {
120
9.89k
  if (!buffers_alias(in, in_len, out, out_len)) {
121
4.66k
    return 1;
122
4.66k
  }
123
124
5.22k
  return in == out;
125
9.89k
}
126
127
int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
128
                      size_t max_out_len, const uint8_t *nonce,
129
                      size_t nonce_len, const uint8_t *in, size_t in_len,
130
0
                      const uint8_t *ad, size_t ad_len) {
131
0
  bool ok = false;
132
0
  Cleanup cleanup([&] {
133
0
    if (!ok) {
134
      // In the event of an error, clear the output buffer so that a caller
135
      // that doesn't check the return value doesn't send raw data.
136
0
      OPENSSL_memset(out, 0, max_out_len);
137
0
      *out_len = 0;
138
0
    }
139
0
  });
140
141
0
  if (max_out_len < in_len) {
142
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
143
0
    return 0;
144
0
  }
145
146
0
  CRYPTO_IOVEC iovec[1];
147
0
  iovec[0].in = in;
148
0
  iovec[0].out = out;
149
0
  iovec[0].len = in_len;
150
0
  CRYPTO_IVEC aadvec[1];
151
0
  aadvec[0].in = ad;
152
0
  aadvec[0].len = ad_len;
153
0
  if (!EVP_AEAD_CTX_sealv(ctx, iovec, 1, out + in_len, out_len,
154
0
                          max_out_len - in_len, nonce, nonce_len, aadvec, 1)) {
155
0
    *out_len = 0;
156
0
    return 0;
157
0
  }
158
0
  *out_len += in_len;
159
0
  ok = true;
160
0
  return 1;
161
0
}
162
163
int EVP_AEAD_CTX_seal_scatter(const EVP_AEAD_CTX *ctx, uint8_t *out,
164
                              uint8_t *out_tag, size_t *out_tag_len,
165
                              size_t max_out_tag_len, const uint8_t *nonce,
166
                              size_t nonce_len, const uint8_t *in,
167
                              size_t in_len, const uint8_t *extra_in,
168
                              size_t extra_in_len, const uint8_t *ad,
169
2.26k
                              size_t ad_len) {
170
2.26k
  bool ok = false;
171
2.26k
  Cleanup cleanup([&] {
172
2.26k
    if (!ok) {
173
      // In the event of an error, clear the output buffer so that a caller
174
      // that doesn't check the return value doesn't send raw data.
175
0
      OPENSSL_memset(out, 0, in_len);
176
0
      OPENSSL_memset(out_tag, 0, max_out_tag_len);
177
0
      *out_tag_len = 0;
178
0
    }
179
2.26k
  });
180
181
  // `out_tag` contains both the encryption of `extra_in` and the tag.
182
2.26k
  Span<uint8_t> out_tag_span(out_tag, max_out_tag_len);
183
2.26k
  if (out_tag_span.size() < extra_in_len) {
184
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
185
0
    return 0;
186
0
  }
187
2.26k
  Span<uint8_t> extra_out = out_tag_span.first(extra_in_len);
188
2.26k
  Span<uint8_t> tag_only_out = out_tag_span.subspan(extra_in_len);
189
190
2.26k
  CRYPTO_IOVEC iovec[2];
191
2.26k
  iovec[0].in = in;
192
2.26k
  iovec[0].out = out;
193
2.26k
  iovec[0].len = in_len;
194
2.26k
  iovec[1].in = extra_in;
195
2.26k
  iovec[1].out = extra_out.data();
196
2.26k
  iovec[1].len = extra_in_len;
197
2.26k
  CRYPTO_IVEC aadvec[1];
198
2.26k
  aadvec[0].in = ad;
199
2.26k
  aadvec[0].len = ad_len;
200
2.26k
  if (!EVP_AEAD_CTX_sealv(ctx, iovec, extra_in_len ? 2 : 1, tag_only_out.data(),
201
2.26k
                          out_tag_len, tag_only_out.size(), nonce, nonce_len,
202
2.26k
                          aadvec, 1)) {
203
0
    *out_tag_len = 0;
204
0
    return 0;
205
0
  }
206
2.26k
  *out_tag_len += extra_in_len;
207
2.26k
  ok = true;
208
2.26k
  return 1;
209
2.26k
}
210
211
9.25k
static bool check_iovec_internal_alias(Span<const CRYPTO_IOVEC> iovecs) {
212
19.1k
  for (size_t i = 0; i < iovecs.size(); ++i) {
213
    // Same index check.
214
9.89k
    if (!check_alias(iovecs[i].in, iovecs[i].len, iovecs[i].out,
215
9.89k
                     iovecs[i].len)) {
216
0
      return false;
217
0
    }
218
9.89k
#if !defined(NDEBUG)
219
    // Unrealistic cases; they'd be harmful but also extremely unlikely anyone
220
    // will ever get those wrong. Thus skip them in release builds.
221
10.5k
    for (size_t j = i + 1; j < iovecs.size(); ++j) {
222
636
      if (buffers_alias(iovecs[i].in, iovecs[i].len,  //
223
636
                        iovecs[j].out, iovecs[j].len) ||
224
636
          buffers_alias(iovecs[i].out, iovecs[i].len,  //
225
636
                        iovecs[j].in, iovecs[j].len) ||
226
636
          buffers_alias(iovecs[i].out, iovecs[i].len,  //
227
636
                        iovecs[j].out, iovecs[j].len)) {
228
0
        return false;
229
0
      }
230
636
    }
231
9.89k
#endif
232
9.89k
  }
233
9.25k
  return true;
234
9.25k
}
235
236
#if !defined(NDEBUG)
237
static bool check_ivec_buf_alias(Span<const CRYPTO_IVEC> ivecs,
238
19.1k
                                 const uint8_t *buf, size_t buf_len) {
239
19.1k
  for (const CRYPTO_IVEC &ivec : ivecs) {
240
19.1k
    if (buffers_alias(ivec.in, ivec.len, buf, buf_len)) {
241
0
      return false;
242
0
    }
243
19.1k
  }
244
19.1k
  return true;
245
19.1k
}
246
247
static bool check_iovec_out_ivec_alias(Span<const CRYPTO_IOVEC> iovecs,
248
9.25k
                                       Span<const CRYPTO_IVEC> ivecs) {
249
9.89k
  for (const CRYPTO_IOVEC &iovec : iovecs) {
250
9.89k
    if (!check_ivec_buf_alias(ivecs, iovec.out, iovec.len)) {
251
0
      return false;
252
0
    }
253
9.89k
  }
254
9.25k
  return true;
255
9.25k
}
256
257
static bool check_iovec_buf_alias(Span<const CRYPTO_IOVEC> iovecs,
258
9.25k
                                  const uint8_t *buf, size_t buf_len) {
259
9.89k
  for (const CRYPTO_IOVEC &iovec : iovecs) {
260
9.89k
    if (buffers_alias(iovec.in, iovec.len, buf, buf_len)) {
261
0
      return false;
262
0
    }
263
9.89k
    if (buffers_alias(iovec.out, iovec.len, buf, buf_len)) {
264
0
      return false;
265
0
    }
266
9.89k
  }
267
9.25k
  return true;
268
9.25k
}
269
270
static bool check_iovec_out_buf_alias(Span<const CRYPTO_IOVEC> iovecs,
271
18.5k
                                      const uint8_t *buf, size_t buf_len) {
272
19.7k
  for (const CRYPTO_IOVEC &iovec : iovecs) {
273
19.7k
    if (buffers_alias(iovec.out, iovec.len, buf, buf_len)) {
274
0
      return false;
275
0
    }
276
19.7k
  }
277
18.5k
  return true;
278
18.5k
}
279
#endif
280
281
static bool check_iovec_alias(Span<const CRYPTO_IOVEC> iovecs,
282
                              Span<const CRYPTO_IVEC> aadvecs,
283
                              const uint8_t *out, size_t out_len,
284
                              const uint8_t *in1, size_t in1_len,
285
9.25k
                              const uint8_t *in2, size_t in2_len) {
286
9.25k
  return
287
9.25k
#if !defined(NDEBUG)
288
      // Unrealistic cases; they'd be harmful but also extremely unlikely anyone
289
      // will ever get those wrong. Thus skip them in release builds.
290
      //
291
      // iovec.out <-> aadvec.
292
9.25k
      check_iovec_out_ivec_alias(iovecs, aadvecs) &&
293
      // iovec <-> out.
294
9.25k
      check_iovec_buf_alias(iovecs, out, out_len) &&
295
      // iovec.out <-> in1.
296
9.25k
      check_iovec_out_buf_alias(iovecs, in1, in1_len) &&
297
      // iovec.out <-> in2.
298
9.25k
      check_iovec_out_buf_alias(iovecs, in2, in2_len) &&
299
      // aadvec <-> out.
300
9.25k
      check_ivec_buf_alias(aadvecs, out, out_len) &&
301
      // out <-> in1.
302
9.25k
      !buffers_alias(out, out_len, in1, in1_len) &&
303
      // out <-> in2.
304
9.25k
      !buffers_alias(out, out_len, in2, in2_len) &&
305
9.25k
#endif
306
      // iovec <-> iovec.
307
9.25k
      check_iovec_internal_alias(iovecs);
308
9.25k
}
309
310
3.09k
static void clear_iovec(Span<const CRYPTO_IOVEC> iovecs) {
311
3.09k
  for (const CRYPTO_IOVEC &iovec : iovecs) {
312
3.09k
    OPENSSL_memset(iovec.out, 0, iovec.len);
313
3.09k
  }
314
3.09k
}
315
316
int EVP_AEAD_CTX_sealv(const EVP_AEAD_CTX *ctx, const CRYPTO_IOVEC *iovec,
317
                       size_t num_iovec, uint8_t *out_tag, size_t *out_tag_len,
318
                       size_t max_out_tag_len, const uint8_t *nonce,
319
                       size_t nonce_len, const CRYPTO_IVEC *aadvec,
320
2.26k
                       size_t num_aadvec) {
321
2.26k
  Span<const CRYPTO_IOVEC> iovecs(iovec, num_iovec);
322
2.26k
  Span<const CRYPTO_IVEC> aadvecs(aadvec, num_aadvec);
323
324
2.26k
  bool ok = false;
325
2.26k
  Cleanup cleanup([&] {
326
2.26k
    if (!ok) {
327
      // In the event of an error, clear the output buffer so that a caller
328
      // that doesn't check the return value doesn't send raw data.
329
0
      clear_iovec(iovecs);
330
0
      OPENSSL_memset(out_tag, 0, max_out_tag_len);
331
0
      *out_tag_len = 0;
332
0
    }
333
2.26k
  });
334
335
2.26k
  if (!bssl::iovec::IsValid(iovecs) || !bssl::iovec::IsValid(aadvecs)) {
336
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
337
0
    return 0;
338
0
  }
339
340
  // Enforce aliasing rules: no output may alias any input, with the one
341
  // exception that an iovec member's `in` and `out` pointers may be identical
342
  // for in-place operation.
343
2.26k
  if (!check_iovec_alias(iovecs, aadvecs, out_tag, max_out_tag_len, nonce,
344
2.26k
                         nonce_len, nullptr, 0)) {
345
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
346
0
    return 0;
347
0
  }
348
349
2.26k
  if (!ctx->aead->sealv) {
350
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED);
351
0
    return 0;
352
0
  }
353
354
2.26k
  if (ctx->aead->sealv(ctx, iovecs, Span(out_tag, max_out_tag_len), out_tag_len,
355
2.26k
                       Span(nonce, nonce_len), aadvecs)) {
356
2.26k
    ok = true;
357
2.26k
    return 1;
358
2.26k
  }
359
360
0
  return 0;
361
2.26k
}
362
363
int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
364
                      size_t max_out_len, const uint8_t *nonce,
365
                      size_t nonce_len, const uint8_t *in, size_t in_len,
366
6.99k
                      const uint8_t *ad, size_t ad_len) {
367
6.99k
  bool ok = false;
368
6.99k
  Cleanup cleanup([&] {
369
6.99k
    if (!ok) {
370
      // In the event of an error, clear the output buffer so that a caller
371
      // that doesn't check the return value doesn't try and process bad
372
      // data.
373
3.09k
      OPENSSL_memset(out, 0, max_out_len);
374
3.09k
      *out_len = 0;
375
3.09k
    }
376
6.99k
  });
377
378
6.99k
  if (ctx->tag_len) {
379
    // If the tag length is known, the caller only needs to provide enough
380
    // space for in_len - tag_len.
381
3.19k
    if (in_len < ctx->tag_len) {
382
0
      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
383
0
      return 0;
384
0
    }
385
3.19k
    size_t plaintext_len = in_len - ctx->tag_len;
386
3.19k
    if (max_out_len < plaintext_len) {
387
0
      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
388
0
      return 0;
389
0
    }
390
391
3.19k
    CRYPTO_IOVEC iovec[1];
392
3.19k
    iovec[0].in = in;
393
3.19k
    iovec[0].out = out;
394
3.19k
    iovec[0].len = plaintext_len;
395
3.19k
    CRYPTO_IVEC aadvec[1];
396
3.19k
    aadvec[0].in = ad;
397
3.19k
    aadvec[0].len = ad_len;
398
3.19k
    if (!EVP_AEAD_CTX_openv_detached(ctx, iovec, 1, nonce, nonce_len,
399
3.19k
                                     in + plaintext_len, ctx->tag_len, aadvec,
400
3.19k
                                     1)) {
401
2.75k
      return 0;
402
2.75k
    }
403
436
    *out_len = plaintext_len;
404
436
    ok = true;
405
436
    return 1;
406
3.19k
  }
407
408
3.80k
  if (max_out_len < in_len) {
409
    // Variable tag length AEADs need to be able to decrypt the entire
410
    // plaintext before they can split it up. So the caller has to provide
411
    // sufficient max_out_len for temporary data.
412
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
413
0
    return 0;
414
0
  }
415
3.80k
  CRYPTO_IOVEC iovec[1];
416
3.80k
  iovec[0].in = in;
417
3.80k
  iovec[0].out = out;
418
3.80k
  iovec[0].len = in_len;
419
3.80k
  CRYPTO_IVEC aadvec[1];
420
3.80k
  aadvec[0].in = ad;
421
3.80k
  aadvec[0].len = ad_len;
422
3.80k
  if (!EVP_AEAD_CTX_openv(ctx, iovec, 1, out_len, nonce, nonce_len, aadvec,
423
3.80k
                          1)) {
424
335
    return 0;
425
335
  }
426
3.46k
  ok = true;
427
3.46k
  return 1;
428
3.80k
}
429
430
int EVP_AEAD_CTX_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
431
                             const uint8_t *nonce, size_t nonce_len,
432
                             const uint8_t *in, size_t in_len,
433
                             const uint8_t *in_tag, size_t in_tag_len,
434
0
                             const uint8_t *ad, size_t ad_len) {
435
0
  bool ok = false;
436
0
  Cleanup cleanup([&] {
437
0
    if (!ok) {
438
      // In the event of an error, clear the output buffer so that a caller
439
      // that doesn't check the return value doesn't try and process bad
440
      // data.
441
0
      OPENSSL_memset(out, 0, in_len);
442
0
    }
443
0
  });
444
445
0
  CRYPTO_IOVEC iovec[1];
446
0
  iovec[0].in = in;
447
0
  iovec[0].out = out;
448
0
  iovec[0].len = in_len;
449
0
  CRYPTO_IVEC aadvec[1];
450
0
  aadvec[0].in = ad;
451
0
  aadvec[0].len = ad_len;
452
0
  if (!EVP_AEAD_CTX_openv_detached(ctx, iovec, 1, nonce, nonce_len, in_tag,
453
0
                                   in_tag_len, aadvec, 1)) {
454
0
    return 0;
455
0
  }
456
0
  ok = true;
457
0
  return 1;
458
0
}
459
460
int EVP_AEAD_CTX_openv(const EVP_AEAD_CTX *ctx, const CRYPTO_IOVEC *iovec,
461
                       size_t num_iovec, size_t *out_total_bytes,
462
                       const uint8_t *nonce, size_t nonce_len,
463
3.80k
                       const CRYPTO_IVEC *aadvec, size_t num_aadvec) {
464
3.80k
  Span<const CRYPTO_IOVEC> iovecs(iovec, num_iovec);
465
3.80k
  Span<const CRYPTO_IVEC> aadvecs(aadvec, num_aadvec);
466
467
3.80k
  bool ok = false;
468
3.80k
  Cleanup cleanup([&] {
469
3.80k
    if (!ok) {
470
      // In the event of an error, clear the output buffer so that a caller
471
      // that doesn't check the return value doesn't try and process bad
472
      // data.
473
335
      clear_iovec(iovecs);
474
335
      *out_total_bytes = 0;
475
335
    }
476
3.80k
  });
477
478
3.80k
  if (!bssl::iovec::IsValid(iovecs) || !bssl::iovec::IsValid(aadvecs)) {
479
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
480
0
    return 0;
481
0
  }
482
483
  // Enforce aliasing rules: no output may alias any input, with the one
484
  // exception that an iovec member's `in` and `out` pointers may be identical
485
  // for in-place operation.
486
3.80k
  if (!check_iovec_alias(iovecs, aadvecs, nullptr, 0, nonce, nonce_len, nullptr,
487
3.80k
                         0)) {
488
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
489
0
    return 0;
490
0
  }
491
492
3.80k
  if (!ctx->aead->openv) {
493
0
    if (ctx->tag_len && ctx->aead->openv_detached) {
494
      // Try with a detached tag.
495
0
      InplaceVector<CRYPTO_IOVEC, CRYPTO_IOVEC_MAX> detached_iovecs;
496
0
      detached_iovecs.CopyFrom(iovecs);
497
498
0
      uint8_t tagbuf[EVP_AEAD_MAX_OVERHEAD];
499
0
      std::optional<Span<const uint8_t>> tag = bssl::iovec::GetAndRemoveSuffix(
500
0
          Span(tagbuf).first(ctx->tag_len), Span(detached_iovecs));
501
502
0
      if (!tag.has_value()) {  // I.e. no `ctx->tag_len` bytes available.
503
0
        OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
504
0
        return 0;
505
0
      }
506
507
0
      if (ctx->aead->openv_detached(ctx, detached_iovecs,
508
0
                                    Span(nonce, nonce_len), *tag, aadvecs)) {
509
0
        ok = true;
510
0
        *out_total_bytes = bssl::iovec::TotalLength(Span(detached_iovecs));
511
0
        return 1;
512
0
      }
513
0
      return 0;
514
0
    }
515
516
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED);
517
0
    return 0;
518
0
  }
519
520
3.80k
  if (ctx->aead->openv(ctx, iovecs, out_total_bytes, Span(nonce, nonce_len),
521
3.80k
                       aadvecs)) {
522
3.46k
    ok = true;
523
3.46k
    return 1;
524
3.46k
  }
525
526
335
  return 0;
527
3.80k
}
528
529
int EVP_AEAD_CTX_openv_detached(const EVP_AEAD_CTX *ctx,
530
                                const CRYPTO_IOVEC *iovec, size_t num_iovec,
531
                                const uint8_t *nonce, size_t nonce_len,
532
                                const uint8_t *in_tag, size_t in_tag_len,
533
3.19k
                                const CRYPTO_IVEC *aadvec, size_t num_aadvec) {
534
3.19k
  Span<const CRYPTO_IOVEC> iovecs(iovec, num_iovec);
535
3.19k
  Span<const CRYPTO_IVEC> aadvecs(aadvec, num_aadvec);
536
537
3.19k
  bool ok = false;
538
3.19k
  Cleanup cleanup([&] {
539
3.19k
    if (!ok) {
540
      // In the event of an error, clear the output buffer so that a caller
541
      // that doesn't check the return value doesn't try and process bad
542
      // data.
543
2.75k
      clear_iovec(iovecs);
544
2.75k
    }
545
3.19k
  });
546
547
3.19k
  if (!bssl::iovec::IsValid(iovecs) || !bssl::iovec::IsValid(aadvecs)) {
548
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
549
0
    return 0;
550
0
  }
551
3.19k
  if (in_tag_len > EVP_AEAD_MAX_OPEN_OVERHEAD) {
552
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE);
553
0
    return 0;
554
0
  }
555
556
  // Enforce aliasing rules: no output may alias any input, with the one
557
  // exception that an iovec member's `in` and `out` pointers may be identical
558
  // for in-place operation.
559
3.19k
  if (!check_iovec_alias(iovecs, aadvecs, nullptr, 0, nonce, nonce_len, in_tag,
560
3.19k
                         in_tag_len)) {
561
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
562
0
    return 0;
563
0
  }
564
565
3.19k
  if (!ctx->aead->openv_detached) {
566
    // AEADs with variable overhead may provide openv instead of openv_detached.
567
    // While one might call openv and then, on success, discard the result if
568
    // the length was wrong, this requires callers to predict the plaintext
569
    // length first. We do not expect callers to do this, especially in the TLS
570
    // CBC construction, where this length is sensitive to the Lucky 13 attack.
571
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED);
572
0
    return 0;
573
0
  }
574
575
3.19k
  if (ctx->aead->openv_detached(ctx, iovecs, Span(nonce, nonce_len),
576
3.19k
                                Span(in_tag, in_tag_len), aadvecs)) {
577
436
    ok = true;
578
436
    return 1;
579
436
  }
580
581
2.75k
  return 0;
582
3.19k
}
583
584
12.8k
const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx) { return ctx->aead; }
585
586
int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
587
0
                        size_t *out_len) {
588
0
  if (ctx->aead->get_iv == nullptr) {
589
0
    OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
590
0
    return 0;
591
0
  }
592
593
0
  return ctx->aead->get_iv(ctx, out_iv, out_len);
594
0
}
595
596
int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx, size_t *out_tag_len,
597
9.05k
                         const size_t in_len, const size_t extra_in_len) {
598
9.05k
  size_t tag_len;
599
9.05k
  if (ctx->aead->tag_len) {
600
5.22k
    if (in_len + extra_in_len < in_len) {
601
0
      OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW);
602
0
      *out_tag_len = 0;
603
0
      return 0;
604
0
    }
605
5.22k
    tag_len = ctx->aead->tag_len(ctx, in_len + extra_in_len);
606
5.22k
  } else {
607
3.82k
    tag_len = ctx->tag_len;
608
3.82k
  }
609
610
9.05k
  if (extra_in_len + tag_len < extra_in_len) {
611
0
    OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW);
612
0
    *out_tag_len = 0;
613
0
    return 0;
614
0
  }
615
9.05k
  *out_tag_len = extra_in_len + tag_len;
616
9.05k
  return 1;
617
9.05k
}