• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 25457312714

06 May 2026 07:43PM UTC coverage: 89.331% (-2.3%) from 91.667%
25457312714

push

github

randombit
In TLS 1.3 verification of client certs, check the correct extension for OCSP

This was checking if the client asked us (the server) for OCSP, instead of
checking if we asked the client for OCSP when we sent the CertificateRequest.

107574 of 120422 relevant lines covered (89.33%)

11482758.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.38
/src/lib/utils/ghash/ghash.cpp
1
/*
2
* GCM GHASH
3
* (C) 2013,2015,2017 Jack Lloyd
4
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5
* (C) 2024 René Meusel, Rohde & Schwarz Cybersecurity
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#include <botan/internal/ghash.h>
11

12
#include <botan/exceptn.h>
13
#include <botan/internal/ct_utils.h>
14
#include <botan/internal/loadstor.h>
15

16
#if defined(BOTAN_HAS_CPUID)
17
   #include <botan/internal/cpuid.h>
18
#endif
19

20
namespace Botan {
21

22
std::string GHASH::provider() const {
1,013✔
23
#if defined(BOTAN_HAS_GHASH_AVX512_CLMUL)
24
   if(auto feat = CPUID::check(CPUID::Feature::AVX512_CLMUL)) {
1,013✔
25
      return *feat;
×
26
   }
×
27
#endif
28

29
#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
30
   if(auto feat = CPUID::check(CPUID::Feature::HW_CLMUL)) {
1,013✔
31
      return *feat;
1,014✔
32
   }
507✔
33
#endif
34

35
#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM)
36
   if(auto feat = CPUID::check(CPUID::Feature::SIMD_4X32)) {
506✔
37
      return *feat;
506✔
38
   }
253✔
39
#endif
40

41
   return "base";
253✔
42
}
43

44
void GHASH::ghash_multiply(std::span<uint8_t, GCM_BS> x, std::span<const uint8_t> input, size_t blocks) {
56,371✔
45
   BOTAN_ASSERT_NOMSG(input.size() % GCM_BS == 0);
56,371✔
46

47
#if defined(BOTAN_HAS_GHASH_AVX512_CLMUL)
48
   if(CPUID::has(CPUID::Feature::AVX512_CLMUL)) {
56,371✔
49
      BOTAN_ASSERT_NOMSG(!m_H_pow.empty());
×
50
      return ghash_multiply_avx512_clmul(x.data(), m_H_pow.data(), input.data(), blocks);
48,659✔
51
   }
52
#endif
53

54
#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
55
   if(CPUID::has(CPUID::Feature::HW_CLMUL)) {
56,371✔
56
      BOTAN_ASSERT_NOMSG(!m_H_pow.empty());
40,952✔
57
      return ghash_multiply_cpu(x.data(), m_H_pow, input.data(), blocks);
40,952✔
58
   }
59
#endif
60

61
#if defined(BOTAN_HAS_GHASH_CLMUL_VPERM)
62
   if(CPUID::has(CPUID::Feature::SIMD_2X64)) {
15,419✔
63
      return ghash_multiply_vperm(x.data(), m_HM.data(), input.data(), blocks);
7,707✔
64
   }
65
#endif
66

67
   auto scope = CT::scoped_poison(x);
7,712✔
68

69
   auto X = load_be<std::array<uint64_t, 2>>(x);
7,712✔
70

71
   BufferSlicer in(input);
7,712✔
72
   for(size_t b = 0; b != blocks; ++b) {
39,095✔
73
      const auto I = load_be<std::array<uint64_t, 2>>(in.take<GCM_BS>());
31,383✔
74
      X[0] ^= I[0];
31,383✔
75
      X[1] ^= I[1];
31,383✔
76

77
      std::array<uint64_t, 2> Z{};
31,383✔
78

79
      for(size_t i = 0; i != 64; ++i) {
2,039,895✔
80
         const auto X0MASK = CT::Mask<uint64_t>::expand_top_bit(X[0]);
2,008,512✔
81
         const auto X1MASK = CT::Mask<uint64_t>::expand_top_bit(X[1]);
2,008,512✔
82

83
         X[0] <<= 1;
2,008,512✔
84
         X[1] <<= 1;
2,008,512✔
85

86
         Z[0] = X0MASK.select(Z[0] ^ m_HM[4 * i], Z[0]);
2,008,512✔
87
         Z[1] = X0MASK.select(Z[1] ^ m_HM[4 * i + 1], Z[1]);
2,008,512✔
88

89
         Z[0] = X1MASK.select(Z[0] ^ m_HM[4 * i + 2], Z[0]);
2,008,512✔
90
         Z[1] = X1MASK.select(Z[1] ^ m_HM[4 * i + 3], Z[1]);
2,008,512✔
91
      }
92

93
      X[0] = Z[0];
31,383✔
94
      X[1] = Z[1];
31,383✔
95
   }
96

97
   store_be(x, X);
7,712✔
98
}
7,712✔
99

100
bool GHASH::has_keying_material() const {
134,544✔
101
   return !m_HM.empty() || !m_H_pow.empty();
134,544✔
102
}
103

104
void GHASH::key_schedule(std::span<const uint8_t> key) {
8,029✔
105
   m_H_ad = {0};
8,029✔
106
   m_ad_len = 0;
8,029✔
107
   m_text_len = 0;
8,029✔
108

109
   BOTAN_ASSERT_NOMSG(key.size() == GCM_BS);
8,029✔
110
   auto H = load_be<std::array<uint64_t, 2>>(key.first<GCM_BS>());
8,029✔
111

112
#if defined(BOTAN_HAS_GHASH_AVX512_CLMUL)
113
   if(CPUID::has(CPUID::Feature::AVX512_CLMUL)) {
8,029✔
114
      zap(m_HM);
×
115
      if(m_H_pow.size() != 32) {
×
116
         m_H_pow.resize(32);
×
117
      }
118
      ghash_precompute_avx512_clmul(key.data(), m_H_pow.data());
×
119
      // m_HM left empty
120
      return;
×
121
   }
122
#endif
123

124
#if defined(BOTAN_HAS_GHASH_CLMUL_CPU)
125
   if(CPUID::has(CPUID::Feature::HW_CLMUL)) {
8,029✔
126
      zap(m_HM);
5,823✔
127
      ghash_precompute_cpu(key.data(), m_H_pow);
5,823✔
128
      // m_HM left empty
129
      return;
5,823✔
130
   }
131
#endif
132

133
   const uint64_t R = 0xE100000000000000;
2,206✔
134

135
   if(m_HM.size() != 256) {
2,206✔
136
      m_HM.resize(256);
2,206✔
137
   }
138

139
   // precompute the multiples of H
140
   for(size_t i = 0; i != 2; ++i) {
6,618✔
141
      for(size_t j = 0; j != 64; ++j) {
286,780✔
142
         /*
143
         we interleave H^1, H^65, H^2, H^66, H3, H67, H4, H68
144
         to make indexing nicer in the multiplication code
145
         */
146
         m_HM[4 * j + 2 * i] = H[0];
282,368✔
147
         m_HM[4 * j + 2 * i + 1] = H[1];
282,368✔
148

149
         // GCM's bit ops are reversed so we carry out of the bottom
150
         const uint64_t carry = CT::Mask<uint64_t>::expand(H[1] & 1).if_set_return(R);
282,368✔
151
         H[1] = (H[1] >> 1) | (H[0] << 63);
282,368✔
152
         H[0] = (H[0] >> 1) ^ carry;
282,368✔
153
      }
154
   }
155
}
156

157
void GHASH::start(std::span<const uint8_t> nonce) {
15,319✔
158
   BOTAN_ARG_CHECK(nonce.size() == 16, "GHASH requires a 128-bit nonce");
15,319✔
159
   auto& n = m_nonce.emplace();
15,319✔
160
   copy_mem(n, nonce);
15,319✔
161
   copy_mem(m_ghash, m_H_ad);
15,319✔
162
   m_buffer.clear();
15,319✔
163
   m_text_len = 0;
15,319✔
164
}
15,319✔
165

166
void GHASH::set_associated_data(std::span<const uint8_t> input) {
10,469✔
167
   BOTAN_STATE_CHECK(!m_nonce);
10,469✔
168

169
   assert_key_material_set();
10,029✔
170
   m_H_ad = {0};
9,149✔
171
   ghash_update(m_H_ad, input);
9,149✔
172
   ghash_zeropad(m_H_ad);
9,149✔
173
   m_ad_len = input.size();
9,149✔
174
}
9,149✔
175

176
void GHASH::reset_associated_data() {
4,545✔
177
   // This should only be called in GMAC context
178
   BOTAN_STATE_CHECK(m_text_len == 0);
4,545✔
179
   assert_key_material_set();
4,545✔
180
   m_H_ad = {0};
4,545✔
181
   m_ad_len = 0;
4,545✔
182
}
4,545✔
183

184
void GHASH::update_associated_data(std::span<const uint8_t> ad) {
9,056✔
185
   assert_key_material_set();
9,056✔
186
   ghash_update(m_ghash, ad);
7,912✔
187
   m_ad_len += ad.size();
7,912✔
188
}
7,912✔
189

190
void GHASH::update(std::span<const uint8_t> input) {
96,367✔
191
   assert_key_material_set();
96,367✔
192
   BOTAN_STATE_CHECK(m_nonce);
95,939✔
193
   ghash_update(m_ghash, input);
95,279✔
194
   m_text_len += input.size();
95,279✔
195

196
   // NIST SP 800-38D limits plaintext/ciphertext to 2^39 - 256 bits
197
   constexpr uint64_t GHASH_MAX_BYTES = (((static_cast<uint64_t>(1) << 39)) - 256) / 8;
95,279✔
198
   if(m_text_len > GHASH_MAX_BYTES) {
95,279✔
199
      throw Invalid_State("GCM message length limit exceeded");
×
200
   }
201
}
95,279✔
202

203
void GHASH::final(std::span<uint8_t> mac) {
13,743✔
204
   BOTAN_ARG_CHECK(!mac.empty() && mac.size() <= GCM_BS, "GHASH output length");
13,743✔
205
   BOTAN_STATE_CHECK(m_nonce);
13,743✔
206
   assert_key_material_set();
13,291✔
207

208
   ghash_zeropad(m_ghash);
13,291✔
209
   ghash_final_block(m_ghash, m_ad_len, m_text_len);
13,291✔
210

211
   xor_buf(mac, std::span{m_ghash}.first(mac.size()), std::span{*m_nonce}.first(mac.size()));
13,291✔
212

213
   secure_scrub_memory(m_ghash);
13,291✔
214
   m_text_len = 0;
13,291✔
215
   m_nonce.reset();
13,291✔
216
}
13,291✔
217

218
void GHASH::nonce_hash(std::span<uint8_t, GCM_BS> y0, std::span<const uint8_t> nonce) {
1,256✔
219
   assert_key_material_set();
1,256✔
220
   BOTAN_STATE_CHECK(!m_nonce);
1,256✔
221

222
   ghash_update(y0, nonce);
1,256✔
223
   ghash_zeropad(y0);
1,256✔
224
   ghash_final_block(y0, 0, nonce.size());
1,256✔
225
}
1,256✔
226

227
void GHASH::clear() {
5,559✔
228
   zap(m_HM);
5,559✔
229
   zap(m_H_pow);
5,559✔
230
   this->reset_state();
5,559✔
231
}
5,559✔
232

233
void GHASH::reset_state() {
8,387✔
234
   m_H_ad = {0};
8,387✔
235
   secure_scrub_memory(m_ghash);
8,387✔
236
   if(m_nonce) {
8,387✔
237
      secure_scrub_memory(m_nonce.value());
1,456✔
238
      m_nonce.reset();
1,456✔
239
   }
240
   m_buffer.clear();
8,387✔
241
   m_text_len = 0;
8,387✔
242
   m_ad_len = 0;
8,387✔
243
}
8,387✔
244

245
void GHASH::ghash_update(std::span<uint8_t, GCM_BS> x, std::span<const uint8_t> input) {
113,596✔
246
   BufferSlicer in(input);
113,596✔
247
   while(!in.empty()) {
352,006✔
248
      if(const auto one_block = m_buffer.handle_unaligned_data(in)) {
124,814✔
249
         ghash_multiply(x, one_block.value(), 1);
6,408✔
250
      }
251

252
      if(m_buffer.in_alignment()) {
124,814✔
253
         const auto [aligned_data, full_blocks] = m_buffer.aligned_data_to_process(in);
21,859✔
254
         if(full_blocks > 0) {
21,859✔
255
            ghash_multiply(x, aligned_data, full_blocks);
16,507✔
256
         }
257
      }
258
   }
259
   BOTAN_ASSERT_NOMSG(in.empty());
113,596✔
260
}
113,596✔
261

262
void GHASH::ghash_zeropad(std::span<uint8_t, GCM_BS> x) {
23,696✔
263
   if(!m_buffer.in_alignment()) {
23,696✔
264
      m_buffer.fill_up_with_zeros();
18,909✔
265
      ghash_multiply(x, m_buffer.consume(), 1);
18,909✔
266
   }
267
}
23,696✔
268

269
void GHASH::ghash_final_block(std::span<uint8_t, GCM_BS> x, uint64_t ad_len, uint64_t text_len) {
14,547✔
270
   BOTAN_STATE_CHECK(m_buffer.in_alignment());
14,547✔
271
   const auto final_block = store_be(8 * ad_len, 8 * text_len);
14,547✔
272
   ghash_multiply(x, final_block, 1);
14,547✔
273
}
14,547✔
274

275
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc