Coverage Report

Created: 2026-02-16 07:12

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
152k
size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; }
35
36
398k
size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead) { return aead->nonce_len; }
37
38
8.44k
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
490k
void EVP_AEAD_CTX_zero(EVP_AEAD_CTX *ctx) {
43
490k
  OPENSSL_memset(ctx, 0, sizeof(EVP_AEAD_CTX));
44
490k
}
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
306
                      ENGINE *impl) {
73
306
  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
306
  return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len,
79
306
                                          evp_aead_open);
80
306
}
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
119k
                                     enum evp_aead_direction_t dir) {
86
119k
  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
119k
  ctx->aead = aead;
93
94
119k
  int ok;
95
119k
  if (aead->init) {
96
86.7k
    ok = aead->init(ctx, key, key_len, tag_len);
97
86.7k
  } else {
98
33.1k
    ok = aead->init_with_direction(ctx, key, key_len, tag_len, dir);
99
33.1k
  }
100
101
119k
  if (!ok) {
102
0
    ctx->aead = nullptr;
103
0
  }
104
105
119k
  return ok;
106
119k
}
107
108
489k
void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) {
109
489k
  if (ctx->aead == nullptr) {
110
370k
    return;
111
370k
  }
112
119k
  ctx->aead->cleanup(ctx);
113
119k
  ctx->aead = nullptr;
114
119k
}
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.98k
                       size_t out_len) {
120
9.98k
  if (!buffers_alias(in, in_len, out, out_len)) {
121
4.03k
    return 1;
122
4.03k
  }
123
124
5.94k
  return in == out;
125
9.98k
}
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.06k
                              size_t ad_len) {
170
2.06k
  bool ok = false;
171
2.06k
  Cleanup cleanup([&] {
172
2.06k
    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.06k
  });
180
181
2.06k
  CRYPTO_IOVEC iovec[2];
182
2.06k
  iovec[0].in = in;
183
2.06k
  iovec[0].out = out;
184
2.06k
  iovec[0].len = in_len;
185
2.06k
  iovec[1].in = extra_in;
186
2.06k
  iovec[1].out = out_tag;
187
2.06k
  iovec[1].len = extra_in_len;
188
2.06k
  CRYPTO_IVEC aadvec[1];
189
2.06k
  aadvec[0].in = ad;
190
2.06k
  aadvec[0].len = ad_len;
191
2.06k
  if (!EVP_AEAD_CTX_sealv(
192
2.06k
          ctx, iovec, extra_in_len ? 2 : 1, out_tag + extra_in_len, out_tag_len,
193
2.06k
          max_out_tag_len - extra_in_len, nonce, nonce_len, aadvec, 1)) {
194
0
    *out_tag_len = 0;
195
0
    return 0;
196
0
  }
197
2.06k
  *out_tag_len += extra_in_len;
198
2.06k
  ok = true;
199
2.06k
  return 1;
200
2.06k
}
201
202
9.38k
static bool check_iovec_internal_alias(Span<const CRYPTO_IOVEC> iovecs) {
203
19.3k
  for (size_t i = 0; i < iovecs.size(); ++i) {
204
    // Same index check.
205
9.98k
    if (!check_alias(iovecs[i].in, iovecs[i].len, iovecs[i].out,
206
9.98k
                     iovecs[i].len)) {
207
0
      return false;
208
0
    }
209
9.98k
#if !defined(NDEBUG)
210
    // Unrealistic cases; they'd be harmful but also extremely unlikely anyone
211
    // will ever get those wrong. Thus skip them in release builds.
212
10.5k
    for (size_t j = i + 1; j < iovecs.size(); ++j) {
213
599
      if (buffers_alias(iovecs[i].in, iovecs[i].len,  //
214
599
                        iovecs[j].out, iovecs[j].len) ||
215
599
          buffers_alias(iovecs[i].out, iovecs[i].len,  //
216
599
                        iovecs[j].in, iovecs[j].len) ||
217
599
          buffers_alias(iovecs[i].out, iovecs[i].len,  //
218
599
                        iovecs[j].out, iovecs[j].len)) {
219
0
        return false;
220
0
      }
221
599
    }
222
9.98k
#endif
223
9.98k
  }
224
9.38k
  return true;
225
9.38k
}
226
227
#if !defined(NDEBUG)
228
static bool check_ivec_buf_alias(Span<const CRYPTO_IVEC> ivecs,
229
19.3k
                                 const uint8_t *buf, size_t buf_len) {
230
19.3k
  for (const CRYPTO_IVEC &ivec : ivecs) {
231
19.3k
    if (buffers_alias(ivec.in, ivec.len, buf, buf_len)) {
232
0
      return false;
233
0
    }
234
19.3k
  }
235
19.3k
  return true;
236
19.3k
}
237
238
static bool check_iovec_out_ivec_alias(Span<const CRYPTO_IOVEC> iovecs,
239
9.38k
                                       Span<const CRYPTO_IVEC> ivecs) {
240
9.98k
  for (const CRYPTO_IOVEC &iovec : iovecs) {
241
9.98k
    if (!check_ivec_buf_alias(ivecs, iovec.out, iovec.len)) {
242
0
      return false;
243
0
    }
244
9.98k
  }
245
9.38k
  return true;
246
9.38k
}
247
248
static bool check_iovec_buf_alias(Span<const CRYPTO_IOVEC> iovecs,
249
9.38k
                                  const uint8_t *buf, size_t buf_len) {
250
9.98k
  for (const CRYPTO_IOVEC &iovec : iovecs) {
251
9.98k
    if (buffers_alias(iovec.in, iovec.len, buf, buf_len)) {
252
0
      return false;
253
0
    }
254
9.98k
    if (buffers_alias(iovec.out, iovec.len, buf, buf_len)) {
255
0
      return false;
256
0
    }
257
9.98k
  }
258
9.38k
  return true;
259
9.38k
}
260
261
static bool check_iovec_out_buf_alias(Span<const CRYPTO_IOVEC> iovecs,
262
18.7k
                                      const uint8_t *buf, size_t buf_len) {
263
19.9k
  for (const CRYPTO_IOVEC &iovec : iovecs) {
264
19.9k
    if (buffers_alias(iovec.out, iovec.len, buf, buf_len)) {
265
0
      return false;
266
0
    }
267
19.9k
  }
268
18.7k
  return true;
269
18.7k
}
270
#endif
271
272
static bool check_iovec_alias(Span<const CRYPTO_IOVEC> iovecs,
273
                              Span<const CRYPTO_IVEC> aadvecs,
274
                              const uint8_t *out, size_t out_len,
275
                              const uint8_t *in1, size_t in1_len,
276
9.38k
                              const uint8_t *in2, size_t in2_len) {
277
9.38k
  return
278
9.38k
#if !defined(NDEBUG)
279
      // Unrealistic cases; they'd be harmful but also extremely unlikely anyone
280
      // will ever get those wrong. Thus skip them in release builds.
281
      //
282
      // iovec.out <-> aadvec.
283
9.38k
      check_iovec_out_ivec_alias(iovecs, aadvecs) &&
284
      // iovec <-> out.
285
9.38k
      check_iovec_buf_alias(iovecs, out, out_len) &&
286
      // iovec.out <-> in1.
287
9.38k
      check_iovec_out_buf_alias(iovecs, in1, in1_len) &&
288
      // iovec.out <-> in2.
289
9.38k
      check_iovec_out_buf_alias(iovecs, in2, in2_len) &&
290
      // aadvec <-> out.
291
9.38k
      check_ivec_buf_alias(aadvecs, out, out_len) &&
292
      // out <-> in1.
293
9.38k
      !buffers_alias(out, out_len, in1, in1_len) &&
294
      // out <-> in2.
295
9.38k
      !buffers_alias(out, out_len, in2, in2_len) &&
296
9.38k
#endif
297
      // iovec <-> iovec.
298
9.38k
      check_iovec_internal_alias(iovecs);
299
9.38k
}
300
301
2.94k
static void clear_iovec(Span<const CRYPTO_IOVEC> iovecs) {
302
2.94k
  for (const CRYPTO_IOVEC &iovec : iovecs) {
303
2.94k
    OPENSSL_memset(iovec.out, 0, iovec.len);
304
2.94k
  }
305
2.94k
}
306
307
int EVP_AEAD_CTX_sealv(const EVP_AEAD_CTX *ctx, const CRYPTO_IOVEC *iovec,
308
                       size_t num_iovec, uint8_t *out_tag, size_t *out_tag_len,
309
                       size_t max_out_tag_len, const uint8_t *nonce,
310
                       size_t nonce_len, const CRYPTO_IVEC *aadvec,
311
2.06k
                       size_t num_aadvec) {
312
2.06k
  Span<const CRYPTO_IOVEC> iovecs(iovec, num_iovec);
313
2.06k
  Span<const CRYPTO_IVEC> aadvecs(aadvec, num_aadvec);
314
315
2.06k
  bool ok = false;
316
2.06k
  Cleanup cleanup([&] {
317
2.06k
    if (!ok) {
318
      // In the event of an error, clear the output buffer so that a caller
319
      // that doesn't check the return value doesn't send raw data.
320
0
      clear_iovec(iovecs);
321
0
      OPENSSL_memset(out_tag, 0, max_out_tag_len);
322
0
      *out_tag_len = 0;
323
0
    }
324
2.06k
  });
325
326
2.06k
  if (!bssl::iovec::IsValid(iovecs) || !bssl::iovec::IsValid(aadvecs)) {
327
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
328
0
    return 0;
329
0
  }
330
331
  // Enforce aliasing rules: no output may alias any input, with the one
332
  // exception that an iovec member's |in| and |out| pointers may be identical
333
  // for in-place operation.
334
2.06k
  if (!check_iovec_alias(iovecs, aadvecs, out_tag, max_out_tag_len, nonce,
335
2.06k
                         nonce_len, nullptr, 0)) {
336
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
337
0
    return 0;
338
0
  }
339
340
2.06k
  if (!ctx->aead->sealv) {
341
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED);
342
0
    return 0;
343
0
  }
344
345
2.06k
  if (ctx->aead->sealv(ctx, iovecs, Span(out_tag, max_out_tag_len), out_tag_len,
346
2.06k
                       Span(nonce, nonce_len), aadvecs)) {
347
2.06k
    ok = true;
348
2.06k
    return 1;
349
2.06k
  }
350
351
0
  return 0;
352
2.06k
}
353
354
int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len,
355
                      size_t max_out_len, const uint8_t *nonce,
356
                      size_t nonce_len, const uint8_t *in, size_t in_len,
357
7.31k
                      const uint8_t *ad, size_t ad_len) {
358
7.31k
  bool ok = false;
359
7.31k
  Cleanup cleanup([&] {
360
7.31k
    if (!ok) {
361
      // In the event of an error, clear the output buffer so that a caller
362
      // that doesn't check the return value doesn't try and process bad
363
      // data.
364
2.94k
      OPENSSL_memset(out, 0, max_out_len);
365
2.94k
      *out_len = 0;
366
2.94k
    }
367
7.31k
  });
368
369
7.31k
  if (ctx->tag_len) {
370
    // If the tag length is known, the caller only needs to provide enough
371
    // space for in_len - tag_len.
372
3.28k
    if (in_len < ctx->tag_len) {
373
0
      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
374
0
      return 0;
375
0
    }
376
3.28k
    size_t plaintext_len = in_len - ctx->tag_len;
377
3.28k
    if (max_out_len < plaintext_len) {
378
0
      OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
379
0
      return 0;
380
0
    }
381
382
3.28k
    CRYPTO_IOVEC iovec[1];
383
3.28k
    iovec[0].in = in;
384
3.28k
    iovec[0].out = out;
385
3.28k
    iovec[0].len = plaintext_len;
386
3.28k
    CRYPTO_IVEC aadvec[1];
387
3.28k
    aadvec[0].in = ad;
388
3.28k
    aadvec[0].len = ad_len;
389
3.28k
    if (!EVP_AEAD_CTX_openv_detached(ctx, iovec, 1, nonce, nonce_len,
390
3.28k
                                     in + plaintext_len, ctx->tag_len, aadvec,
391
3.28k
                                     1)) {
392
2.63k
      return 0;
393
2.63k
    }
394
650
    *out_len = plaintext_len;
395
650
    ok = true;
396
650
    return 1;
397
3.28k
  }
398
399
4.02k
  if (max_out_len < in_len) {
400
    // Variable tag length AEADs need to be able to decrypt the entire
401
    // plaintext before they can split it up. So the caller has to provide
402
    // sufficient max_out_len for temporary data.
403
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL);
404
0
    return 0;
405
0
  }
406
4.02k
  CRYPTO_IOVEC iovec[1];
407
4.02k
  iovec[0].in = in;
408
4.02k
  iovec[0].out = out;
409
4.02k
  iovec[0].len = in_len;
410
4.02k
  CRYPTO_IVEC aadvec[1];
411
4.02k
  aadvec[0].in = ad;
412
4.02k
  aadvec[0].len = ad_len;
413
4.02k
  if (!EVP_AEAD_CTX_openv(ctx, iovec, 1, out_len, nonce, nonce_len, aadvec,
414
4.02k
                          1)) {
415
304
    return 0;
416
304
  }
417
3.72k
  ok = true;
418
3.72k
  return 1;
419
4.02k
}
420
421
int EVP_AEAD_CTX_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
422
                             const uint8_t *nonce, size_t nonce_len,
423
                             const uint8_t *in, size_t in_len,
424
                             const uint8_t *in_tag, size_t in_tag_len,
425
0
                             const uint8_t *ad, size_t ad_len) {
426
0
  bool ok = false;
427
0
  Cleanup cleanup([&] {
428
0
    if (!ok) {
429
      // In the event of an error, clear the output buffer so that a caller
430
      // that doesn't check the return value doesn't try and process bad
431
      // data.
432
0
      OPENSSL_memset(out, 0, in_len);
433
0
    }
434
0
  });
435
436
0
  CRYPTO_IOVEC iovec[1];
437
0
  iovec[0].in = in;
438
0
  iovec[0].out = out;
439
0
  iovec[0].len = in_len;
440
0
  CRYPTO_IVEC aadvec[1];
441
0
  aadvec[0].in = ad;
442
0
  aadvec[0].len = ad_len;
443
0
  if (!EVP_AEAD_CTX_openv_detached(ctx, iovec, 1, nonce, nonce_len, in_tag,
444
0
                                   in_tag_len, aadvec, 1)) {
445
0
    return 0;
446
0
  }
447
0
  ok = true;
448
0
  return 1;
449
0
}
450
451
int EVP_AEAD_CTX_openv(const EVP_AEAD_CTX *ctx, const CRYPTO_IOVEC *iovec,
452
                       size_t num_iovec, size_t *out_total_bytes,
453
                       const uint8_t *nonce, size_t nonce_len,
454
4.02k
                       const CRYPTO_IVEC *aadvec, size_t num_aadvec) {
455
4.02k
  Span<const CRYPTO_IOVEC> iovecs(iovec, num_iovec);
456
4.02k
  Span<const CRYPTO_IVEC> aadvecs(aadvec, num_aadvec);
457
458
4.02k
  bool ok = false;
459
4.02k
  Cleanup cleanup([&] {
460
4.02k
    if (!ok) {
461
      // In the event of an error, clear the output buffer so that a caller
462
      // that doesn't check the return value doesn't try and process bad
463
      // data.
464
304
      clear_iovec(iovecs);
465
304
      *out_total_bytes = 0;
466
304
    }
467
4.02k
  });
468
469
4.02k
  if (!bssl::iovec::IsValid(iovecs) || !bssl::iovec::IsValid(aadvecs)) {
470
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
471
0
    return 0;
472
0
  }
473
474
  // Enforce aliasing rules: no output may alias any input, with the one
475
  // exception that an iovec member's |in| and |out| pointers may be identical
476
  // for in-place operation.
477
4.02k
  if (!check_iovec_alias(iovecs, aadvecs, nullptr, 0, nonce, nonce_len, nullptr,
478
4.02k
                         0)) {
479
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
480
0
    return 0;
481
0
  }
482
483
4.02k
  if (!ctx->aead->openv) {
484
0
    if (ctx->tag_len && ctx->aead->openv_detached) {
485
      // Try with a detached tag.
486
0
      InplaceVector<CRYPTO_IOVEC, CRYPTO_IOVEC_MAX> detached_iovecs;
487
0
      detached_iovecs.CopyFrom(iovecs);
488
489
0
      uint8_t tagbuf[EVP_AEAD_MAX_OVERHEAD];
490
0
      std::optional<Span<const uint8_t>> tag = bssl::iovec::GetAndRemoveSuffix(
491
0
          Span(tagbuf).first(ctx->tag_len), Span(detached_iovecs));
492
493
0
      if (!tag.has_value()) {  // I.e. no |ctx->tag_len| bytes available.
494
0
        OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT);
495
0
        return 0;
496
0
      }
497
498
0
      if (ctx->aead->openv_detached(ctx, detached_iovecs,
499
0
                                    Span(nonce, nonce_len), *tag, aadvecs)) {
500
0
        ok = true;
501
0
        *out_total_bytes = bssl::iovec::TotalLength(Span(detached_iovecs));
502
0
        return 1;
503
0
      }
504
0
      return 0;
505
0
    }
506
507
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED);
508
0
    return 0;
509
0
  }
510
511
4.02k
  if (ctx->aead->openv(ctx, iovecs, out_total_bytes, Span(nonce, nonce_len),
512
4.02k
                       aadvecs)) {
513
3.72k
    ok = true;
514
3.72k
    return 1;
515
3.72k
  }
516
517
304
  return 0;
518
4.02k
}
519
520
int EVP_AEAD_CTX_openv_detached(const EVP_AEAD_CTX *ctx,
521
                                const CRYPTO_IOVEC *iovec, size_t num_iovec,
522
                                const uint8_t *nonce, size_t nonce_len,
523
                                const uint8_t *in_tag, size_t in_tag_len,
524
3.28k
                                const CRYPTO_IVEC *aadvec, size_t num_aadvec) {
525
3.28k
  Span<const CRYPTO_IOVEC> iovecs(iovec, num_iovec);
526
3.28k
  Span<const CRYPTO_IVEC> aadvecs(aadvec, num_aadvec);
527
528
3.28k
  bool ok = false;
529
3.28k
  Cleanup cleanup([&] {
530
3.28k
    if (!ok) {
531
      // In the event of an error, clear the output buffer so that a caller
532
      // that doesn't check the return value doesn't try and process bad
533
      // data.
534
2.63k
      clear_iovec(iovecs);
535
2.63k
    }
536
3.28k
  });
537
538
3.28k
  if (!bssl::iovec::IsValid(iovecs) || !bssl::iovec::IsValid(aadvecs)) {
539
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE);
540
0
    return 0;
541
0
  }
542
3.28k
  if (in_tag_len > EVP_AEAD_MAX_OPEN_OVERHEAD) {
543
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE);
544
0
    return 0;
545
0
  }
546
547
  // Enforce aliasing rules: no output may alias any input, with the one
548
  // exception that an iovec member's |in| and |out| pointers may be identical
549
  // for in-place operation.
550
3.28k
  if (!check_iovec_alias(iovecs, aadvecs, nullptr, 0, nonce, nonce_len, in_tag,
551
3.28k
                         in_tag_len)) {
552
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT);
553
0
    return 0;
554
0
  }
555
556
3.28k
  if (!ctx->aead->openv_detached) {
557
    // AEADs with variable overhead may provide openv instead of openv_detached.
558
    // While one might call openv and then, on success, discard the result if
559
    // the length was wrong, this requires callers to predict the plaintext
560
    // length first. We do not expect callers to do this, especially in the TLS
561
    // CBC construction, where this length is sensitive to the Lucky 13 attack.
562
0
    OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED);
563
0
    return 0;
564
0
  }
565
566
3.28k
  if (ctx->aead->openv_detached(ctx, iovecs, Span(nonce, nonce_len),
567
3.28k
                                Span(in_tag, in_tag_len), aadvecs)) {
568
650
    ok = true;
569
650
    return 1;
570
650
  }
571
572
2.63k
  return 0;
573
3.28k
}
574
575
8.44k
const EVP_AEAD *EVP_AEAD_CTX_aead(const EVP_AEAD_CTX *ctx) { return ctx->aead; }
576
577
int EVP_AEAD_CTX_get_iv(const EVP_AEAD_CTX *ctx, const uint8_t **out_iv,
578
0
                        size_t *out_len) {
579
0
  if (ctx->aead->get_iv == nullptr) {
580
0
    OPENSSL_PUT_ERROR(CIPHER, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
581
0
    return 0;
582
0
  }
583
584
0
  return ctx->aead->get_iv(ctx, out_iv, out_len);
585
0
}
586
587
int EVP_AEAD_CTX_tag_len(const EVP_AEAD_CTX *ctx, size_t *out_tag_len,
588
8.27k
                         const size_t in_len, const size_t extra_in_len) {
589
8.27k
  size_t tag_len;
590
8.27k
  if (ctx->aead->tag_len) {
591
4.87k
    if (in_len + extra_in_len < in_len) {
592
0
      OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW);
593
0
      *out_tag_len = 0;
594
0
      return 0;
595
0
    }
596
4.87k
    tag_len = ctx->aead->tag_len(ctx, in_len + extra_in_len);
597
4.87k
  } else {
598
3.40k
    tag_len = ctx->tag_len;
599
3.40k
  }
600
601
8.27k
  if (extra_in_len + tag_len < extra_in_len) {
602
0
    OPENSSL_PUT_ERROR(CIPHER, ERR_R_OVERFLOW);
603
0
    *out_tag_len = 0;
604
0
    return 0;
605
0
  }
606
8.27k
  *out_tag_len = extra_in_len + tag_len;
607
8.27k
  return 1;
608
8.27k
}