Coverage Report

Created: 2025-11-03 06:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/crypto/fipsmodule/rsa/blinding.cc.inc
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
#include <openssl/rsa.h>
16
17
#include <string.h>
18
19
#include <openssl/bn.h>
20
#include <openssl/err.h>
21
#include <openssl/mem.h>
22
23
#include "../../internal.h"
24
#include "../bn/internal.h"
25
#include "internal.h"
26
27
28
42.3k
#define BN_BLINDING_COUNTER 32
29
30
struct bn_blinding_st {
31
  BIGNUM *A;   // The base blinding factor, Montgomery-encoded.
32
  BIGNUM *Ai;  // The inverse of the blinding factor, Montgomery-encoded.
33
  unsigned counter;
34
};
35
36
static int bn_blinding_create_param(BN_BLINDING *b, const BIGNUM *e,
37
                                    const BN_MONT_CTX *mont, BN_CTX *ctx);
38
39
6
BN_BLINDING *BN_BLINDING_new(void) {
40
6
  BN_BLINDING *ret =
41
6
      reinterpret_cast<BN_BLINDING *>(OPENSSL_zalloc(sizeof(BN_BLINDING)));
42
6
  if (ret == nullptr) {
43
0
    return nullptr;
44
0
  }
45
46
6
  ret->A = BN_new();
47
6
  if (ret->A == nullptr) {
48
0
    goto err;
49
0
  }
50
51
6
  ret->Ai = BN_new();
52
6
  if (ret->Ai == nullptr) {
53
0
    goto err;
54
0
  }
55
56
  // The blinding values need to be created before this blinding can be used.
57
6
  ret->counter = BN_BLINDING_COUNTER - 1;
58
59
6
  return ret;
60
61
0
err:
62
0
  BN_BLINDING_free(ret);
63
0
  return nullptr;
64
6
}
65
66
0
void BN_BLINDING_free(BN_BLINDING *r) {
67
0
  if (r == nullptr) {
68
0
    return;
69
0
  }
70
0
  BN_free(r->A);
71
0
  BN_free(r->Ai);
72
0
  OPENSSL_free(r);
73
0
}
74
75
0
void BN_BLINDING_invalidate(BN_BLINDING *b) {
76
0
  b->counter = BN_BLINDING_COUNTER - 1;
77
0
}
78
79
static int bn_blinding_update(BN_BLINDING *b, const BIGNUM *e,
80
42.3k
                              const BN_MONT_CTX *mont, BN_CTX *ctx) {
81
42.3k
  if (++b->counter == BN_BLINDING_COUNTER) {
82
    // re-create blinding parameters
83
1.32k
    if (!bn_blinding_create_param(b, e, mont, ctx)) {
84
0
      goto err;
85
0
    }
86
1.32k
    b->counter = 0;
87
41.0k
  } else {
88
41.0k
    if (!BN_mod_mul_montgomery(b->A, b->A, b->A, mont, ctx) ||
89
41.0k
        !BN_mod_mul_montgomery(b->Ai, b->Ai, b->Ai, mont, ctx)) {
90
0
      goto err;
91
0
    }
92
41.0k
  }
93
94
42.3k
  return 1;
95
96
0
err:
97
  // |A| and |Ai| may be in an inconsistent state so they both need to be
98
  // replaced the next time this blinding is used. Note that this is only
99
  // sufficient because support for |BN_BLINDING_NO_UPDATE| and
100
  // |BN_BLINDING_NO_RECREATE| was previously dropped.
101
0
  b->counter = BN_BLINDING_COUNTER - 1;
102
103
0
  return 0;
104
42.3k
}
105
106
int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, const BIGNUM *e,
107
42.3k
                        const BN_MONT_CTX *mont, BN_CTX *ctx) {
108
  // |n| is not Montgomery-encoded and |b->A| is. |BN_mod_mul_montgomery|
109
  // cancels one Montgomery factor, so the resulting value of |n| is unencoded.
110
42.3k
  if (!bn_blinding_update(b, e, mont, ctx) ||
111
42.3k
      !BN_mod_mul_montgomery(n, n, b->A, mont, ctx)) {
112
0
    return 0;
113
0
  }
114
115
42.3k
  return 1;
116
42.3k
}
117
118
int BN_BLINDING_invert(BIGNUM *n, const BN_BLINDING *b, BN_MONT_CTX *mont,
119
42.3k
                       BN_CTX *ctx) {
120
  // |n| is not Montgomery-encoded and |b->A| is. |BN_mod_mul_montgomery|
121
  // cancels one Montgomery factor, so the resulting value of |n| is unencoded.
122
42.3k
  return BN_mod_mul_montgomery(n, n, b->Ai, mont, ctx);
123
42.3k
}
124
125
static int bn_blinding_create_param(BN_BLINDING *b, const BIGNUM *e,
126
1.32k
                                    const BN_MONT_CTX *mont, BN_CTX *ctx) {
127
1.32k
  int no_inverse;
128
1.32k
  if (!BN_rand_range_ex(b->A, 1, &mont->N) ||
129
      // Compute |b->A|^-1 in Montgomery form. Note |BN_from_montgomery| +
130
      // |BN_mod_inverse_blinded| is equivalent to, but more efficient than,
131
      // |BN_mod_inverse_blinded| + |BN_to_montgomery|.
132
      //
133
      // We do not retry if |b->A| has no inverse. Finding a non-invertible
134
      // value of |b->A| is equivalent to factoring |mont->N|. There is
135
      // negligible probability of stumbling on one at random.
136
1.32k
      !BN_from_montgomery(b->Ai, b->A, mont, ctx) ||
137
1.32k
      !BN_mod_inverse_blinded(b->Ai, &no_inverse, b->Ai, mont, ctx) ||
138
      // TODO(davidben): |BN_mod_exp_mont| internally computes the result in
139
      // Montgomery form. Save a pair of Montgomery reductions and a
140
      // multiplication by returning that value directly.
141
1.32k
      !BN_mod_exp_mont(b->A, b->A, e, &mont->N, ctx, mont) ||
142
1.32k
      !BN_to_montgomery(b->A, b->A, mont, ctx)) {
143
0
    OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
144
0
    return 0;
145
0
  }
146
147
1.32k
  return 1;
148
1.32k
}