Coverage Report

Created: 2026-06-15 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/bn/ctx.cc.inc
Line
Count
Source
1
// Copyright 2000-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
#include <openssl/bn.h>
16
17
#include <assert.h>
18
#include <string.h>
19
20
#include <utility>
21
22
#include <openssl/err.h>
23
#include <openssl/mem.h>
24
25
#include "../../internal.h"
26
#include "../../mem_internal.h"
27
28
29
using namespace bssl;
30
31
DECLARE_OPAQUE_STRUCT(bignum_ctx, BignumCtx)
32
33
BSSL_NAMESPACE_BEGIN
34
35
class BignumCtx : public bignum_ctx {
36
 public:
37
76.2k
  ~BignumCtx() {
38
    // All `BN_CTX_start` calls must be matched with `BN_CTX_end`, otherwise the
39
    // function may use more memory than expected, potentially without bound if
40
    // done in a loop. Assert that all `BIGNUM`s have been released.
41
76.2k
    assert(used_ == 0 || error_);
42
76.2k
  }
43
44
  // bignums_ is the stack of `BIGNUM`s managed by this `BN_CTX`.
45
  Vector<UniquePtr<BIGNUM>> bignums_;
46
  // stack_ is the stack of `BN_CTX_start` frames. It is the value of `used_` at
47
  // the time `BN_CTX_start` was called.
48
  Vector<size_t> stack_;
49
  // used_ is the number of `BIGNUM`s from `bignums_` that have been used.
50
  size_t used_ = 0;
51
  // error_ is whether any operation on this `BN_CTX` failed. All subsequent
52
  // operations will fail.
53
  bool error_ = false;
54
  // defer_error_ is whether an operation on this `BN_CTX` has failed, but no
55
  // error has been pushed to the queue yet. This is used to defer errors from
56
  // `BN_CTX_start` to `BN_CTX_get`.
57
  bool defer_error_ = false;
58
};
59
60
BSSL_NAMESPACE_END
61
62
76.2k
BN_CTX *BN_CTX_new() { return New<BignumCtx>(); }
63
64
90.4k
void BN_CTX_free(BN_CTX *ctx) {
65
90.4k
  if (ctx != nullptr) {
66
76.2k
    Delete(FromOpaque(ctx));
67
76.2k
  }
68
90.4k
}
69
70
19.2M
void BN_CTX_start(BN_CTX *ctx) {
71
19.2M
  auto *impl = FromOpaque(ctx);
72
73
19.2M
  if (impl->error_) {
74
    // Once an operation has failed, `impl->stack` no longer matches the number
75
    // of `BN_CTX_end` calls to come. Do nothing.
76
0
    return;
77
0
  }
78
79
19.2M
  if (!impl->stack_.Push(impl->used_)) {
80
0
    impl->error_ = true;
81
    // `BN_CTX_start` cannot fail, so defer the error to `BN_CTX_get`.
82
0
    impl->defer_error_ = true;
83
0
    ERR_clear_error();
84
0
  }
85
19.2M
}
86
87
32.2M
BIGNUM *BN_CTX_get(BN_CTX *ctx) {
88
32.2M
  auto *impl = FromOpaque(ctx);
89
90
  // Once any operation has failed, they all do.
91
32.2M
  if (impl->error_) {
92
0
    if (impl->defer_error_) {
93
0
      OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
94
0
      impl->defer_error_ = false;
95
0
    }
96
0
    return nullptr;
97
0
  }
98
99
32.2M
  if (impl->used_ == impl->bignums_.size()) {
100
335k
    UniquePtr<BIGNUM> bn(BN_new());
101
335k
    if (bn == nullptr || !impl->bignums_.Push(std::move(bn))) {
102
0
      OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES);
103
0
      impl->error_ = true;
104
0
      return nullptr;
105
0
    }
106
335k
  }
107
108
32.2M
  BIGNUM *ret = impl->bignums_[impl->used_].get();
109
32.2M
  BN_zero(ret);
110
  // This is bounded by `impl->bignums_.size()`, so it cannot overflow.
111
32.2M
  impl->used_++;
112
32.2M
  return ret;
113
32.2M
}
114
115
19.2M
void BN_CTX_end(BN_CTX *ctx) {
116
19.2M
  auto *impl = FromOpaque(ctx);
117
118
19.2M
  if (impl->error_) {
119
    // Once an operation has failed, `impl->stack_` no longer matches the number
120
    // of `BN_CTX_end` calls to come. Do nothing.
121
0
    return;
122
0
  }
123
124
19.2M
  assert(!impl->stack_.empty());
125
19.2M
  impl->used_ = impl->stack_.back();
126
19.2M
  impl->stack_.pop_back();
127
19.2M
}