• 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

83.62
/src/lib/ffi/ffi.cpp
1
/*
2
* (C) 2015,2017 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/ffi.h>
8

9
#include <botan/base64.h>
10
#include <botan/hex.h>
11
#include <botan/mem_ops.h>
12
#include <botan/version.h>
13
#include <botan/internal/ct_utils.h>
14
#include <botan/internal/ffi_util.h>
15
#include <cstdio>
16

17
#if defined(BOTAN_HAS_OS_UTILS)
18
   #include <botan/internal/os_utils.h>
19
#endif
20

21
namespace Botan_FFI {
22

23
namespace {
24

25
// NOLINTNEXTLINE(*-avoid-non-const-global-variables)
26
thread_local std::string g_last_exception_what;
98,293✔
27

28
int ffi_map_error_type(Botan::ErrorType err) {
15✔
29
   switch(err) {
15✔
30
      case Botan::ErrorType::Unknown:
31
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
32

33
      case Botan::ErrorType::SystemError:
×
34
      case Botan::ErrorType::IoError:
×
35
      case Botan::ErrorType::Pkcs11Error:
×
36
      case Botan::ErrorType::CommonCryptoError:
×
37
      case Botan::ErrorType::ZlibError:
×
38
      case Botan::ErrorType::Bzip2Error:
×
39
      case Botan::ErrorType::LzmaError:
×
40
      case Botan::ErrorType::DatabaseError:
×
41
         return BOTAN_FFI_ERROR_SYSTEM_ERROR;
×
42

43
      case Botan::ErrorType::TPMError:
×
44
         return BOTAN_FFI_ERROR_TPM_ERROR;
×
45

46
      case Botan::ErrorType::NotImplemented:
47
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
48
      case Botan::ErrorType::OutOfMemory:
×
49
         return BOTAN_FFI_ERROR_OUT_OF_MEMORY;
×
50
      case Botan::ErrorType::InternalError:
×
51
         return BOTAN_FFI_ERROR_INTERNAL_ERROR;
×
52
      case Botan::ErrorType::InvalidObjectState:
6✔
53
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
6✔
54
      case Botan::ErrorType::KeyNotSet:
2✔
55
         return BOTAN_FFI_ERROR_KEY_NOT_SET;
2✔
56
      case Botan::ErrorType::InvalidArgument:
3✔
57
      case Botan::ErrorType::InvalidNonceLength:
3✔
58
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
3✔
59

60
      case Botan::ErrorType::EncodingFailure:
2✔
61
      case Botan::ErrorType::DecodingFailure:
2✔
62
         return BOTAN_FFI_ERROR_INVALID_INPUT;
2✔
63

64
      case Botan::ErrorType::InvalidTag:
×
65
         return BOTAN_FFI_ERROR_BAD_MAC;
×
66

67
      case Botan::ErrorType::InvalidKeyLength:
×
68
         return BOTAN_FFI_ERROR_INVALID_KEY_LENGTH;
×
69
      case Botan::ErrorType::LookupError:
70
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
71

72
      case Botan::ErrorType::HttpError:
×
73
         return BOTAN_FFI_ERROR_HTTP_ERROR;
×
74
      case Botan::ErrorType::TLSError:
×
75
         return BOTAN_FFI_ERROR_TLS_ERROR;
×
76
      case Botan::ErrorType::RoughtimeError:
×
77
         return BOTAN_FFI_ERROR_ROUGHTIME_ERROR;
×
78
   }
79

80
   return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
81
}
82

83
}  // namespace
84

85
void ffi_clear_last_exception() {
98,262✔
86
   g_last_exception_what.clear();
98,262✔
87
}
98,253✔
88

89
int ffi_error_exception_thrown(const char* func_name, const char* exn, int rc) {
22✔
90
   g_last_exception_what.assign(exn);
22✔
91

92
#if defined(BOTAN_HAS_OS_UTILS)
93
   std::string val;
22✔
94
   if(Botan::OS::read_env_variable(val, "BOTAN_FFI_PRINT_EXCEPTIONS") && !val.empty()) {
22✔
95
      // NOLINTNEXTLINE(*-vararg)
96
      static_cast<void>(std::fprintf(stderr, "in %s exception '%s' returning %d\n", func_name, exn, rc));
×
97
   }
98
#endif
99

100
   return rc;
22✔
101
}
22✔
102

103
int ffi_error_exception_thrown(const char* func_name, const char* exn, Botan::ErrorType err) {
15✔
104
   return ffi_error_exception_thrown(func_name, exn, ffi_map_error_type(err));
15✔
105
}
106

107
int botan_view_str_bounce_fn(botan_view_ctx vctx, const char* str, size_t len) {
74✔
108
   return botan_view_bin_bounce_fn(vctx, reinterpret_cast<const uint8_t*>(str), len);
74✔
109
}
110

111
int botan_view_bin_bounce_fn(botan_view_ctx vctx, const uint8_t* buf, size_t len) {
168✔
112
   if(vctx == nullptr || buf == nullptr) {
168✔
113
      return BOTAN_FFI_ERROR_NULL_POINTER;
114
   }
115

116
   const botan_view_bounce_struct* ctx = static_cast<botan_view_bounce_struct*>(vctx);
168✔
117

118
   const size_t avail = *ctx->out_len;
168✔
119
   *ctx->out_len = len;
168✔
120

121
   if(avail < len || ctx->out_ptr == nullptr) {
168✔
122
      if(ctx->out_ptr != nullptr) {
78✔
123
         Botan::clear_mem(ctx->out_ptr, avail);
×
124
      }
125
      return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
78✔
126
   } else {
127
      Botan::copy_mem(ctx->out_ptr, buf, len);
90✔
128
      return BOTAN_FFI_SUCCESS;
90✔
129
   }
130
}
131

132
}  // namespace Botan_FFI
133

134
extern "C" {
135

136
using namespace Botan_FFI;
137

138
const char* botan_error_last_exception_message() {
9✔
139
   return g_last_exception_what.c_str();
9✔
140
}
141

142
const char* botan_error_description(int err) {
159✔
143
   switch(err) {
159✔
144
      case BOTAN_FFI_SUCCESS:
145
         return "OK";
146

147
      case BOTAN_FFI_INVALID_VERIFIER:
1✔
148
         return "Invalid verifier";
1✔
149

150
      case BOTAN_FFI_ERROR_INVALID_INPUT:
2✔
151
         return "Invalid input";
2✔
152

153
      case BOTAN_FFI_ERROR_BAD_MAC:
1✔
154
         return "Invalid authentication code";
1✔
155

156
      case BOTAN_FFI_ERROR_NO_VALUE:
2✔
157
         return "No value available";
2✔
158

159
      case BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE:
2✔
160
         return "Insufficient buffer space";
2✔
161

162
      case BOTAN_FFI_ERROR_STRING_CONVERSION_ERROR:
1✔
163
         return "String conversion error";
1✔
164

165
      case BOTAN_FFI_ERROR_EXCEPTION_THROWN:
1✔
166
         return "Exception thrown";
1✔
167

168
      case BOTAN_FFI_ERROR_OUT_OF_MEMORY:
1✔
169
         return "Out of memory";
1✔
170

171
      case BOTAN_FFI_ERROR_SYSTEM_ERROR:
1✔
172
         return "Error while calling system API";
1✔
173

174
      case BOTAN_FFI_ERROR_INTERNAL_ERROR:
1✔
175
         return "Internal error";
1✔
176

177
      case BOTAN_FFI_ERROR_BAD_FLAG:
1✔
178
         return "Bad flag";
1✔
179

180
      case BOTAN_FFI_ERROR_NULL_POINTER:
1✔
181
         return "Null pointer argument";
1✔
182

183
      case BOTAN_FFI_ERROR_BAD_PARAMETER:
1✔
184
         return "Bad parameter";
1✔
185

186
      case BOTAN_FFI_ERROR_KEY_NOT_SET:
1✔
187
         return "Key not set on object";
1✔
188

189
      case BOTAN_FFI_ERROR_INVALID_KEY_LENGTH:
1✔
190
         return "Invalid key length";
1✔
191

192
      case BOTAN_FFI_ERROR_INVALID_OBJECT_STATE:
3✔
193
         return "Invalid object state";
3✔
194

195
      case BOTAN_FFI_ERROR_OUT_OF_RANGE:
1✔
196
         return "Index out of range";
1✔
197

198
      case BOTAN_FFI_ERROR_NOT_IMPLEMENTED:
5✔
199
         return "Not implemented";
5✔
200

201
      case BOTAN_FFI_ERROR_INVALID_OBJECT:
1✔
202
         return "Invalid object handle";
1✔
203

204
      case BOTAN_FFI_ERROR_TLS_ERROR:
1✔
205
         return "TLS error";
1✔
206

207
      case BOTAN_FFI_ERROR_HTTP_ERROR:
1✔
208
         return "HTTP error";
1✔
209

210
      case BOTAN_FFI_ERROR_UNKNOWN_ERROR:
128✔
211
      default:
128✔
212
         return "Unknown error";
128✔
213
   }
214
}
215

216
/*
217
* Versioning
218
*/
219
uint32_t botan_ffi_api_version() {
4✔
220
   return BOTAN_HAS_FFI;
4✔
221
}
222

223
int botan_ffi_supports_api(uint32_t api_version) {
7✔
224
   // This is the API introduced in 3.12
225
   if(api_version == 20260506) {
7✔
226
      return BOTAN_FFI_SUCCESS;
227
   }
228

229
   // This is the API introduced in 3.11
230
   if(api_version == 20260303) {
5✔
231
      return BOTAN_FFI_SUCCESS;
232
   }
233

234
   // This is the API introduced in 3.10
235
   if(api_version == 20250829) {
5✔
236
      return BOTAN_FFI_SUCCESS;
237
   }
238

239
   // This is the API introduced in 3.8
240
   if(api_version == 20250506) {
5✔
241
      return BOTAN_FFI_SUCCESS;
242
   }
243

244
   // This is the API introduced in 3.4
245
   if(api_version == 20240408) {
5✔
246
      return BOTAN_FFI_SUCCESS;
247
   }
248

249
   // This is the API introduced in 3.2
250
   if(api_version == 20231009) {
5✔
251
      return BOTAN_FFI_SUCCESS;
252
   }
253

254
   // This is the API introduced in 3.1
255
   if(api_version == 20230711) {
5✔
256
      return BOTAN_FFI_SUCCESS;
257
   }
258

259
   // This is the API introduced in 3.0
260
   if(api_version == 20230403) {
5✔
261
      return BOTAN_FFI_SUCCESS;
262
   }
263

264
   // This is the API introduced in 2.18
265
   if(api_version == 20210220) {
5✔
266
      return BOTAN_FFI_SUCCESS;
267
   }
268

269
   // This is the API introduced in 2.13
270
   if(api_version == 20191214) {
5✔
271
      return BOTAN_FFI_SUCCESS;
272
   }
273

274
   // This is the API introduced in 2.8
275
   if(api_version == 20180713) {
5✔
276
      return BOTAN_FFI_SUCCESS;
277
   }
278

279
   // This is the API introduced in 2.3
280
   if(api_version == 20170815) {
4✔
281
      return BOTAN_FFI_SUCCESS;
282
   }
283

284
   // This is the API introduced in 2.1
285
   if(api_version == 20170327) {
3✔
286
      return BOTAN_FFI_SUCCESS;
287
   }
288

289
   // This is the API introduced in 2.0
290
   if(api_version == 20150515) {
2✔
291
      return BOTAN_FFI_SUCCESS;
1✔
292
   }
293

294
   // Something else:
295
   return -1;
296
}
297

298
const char* botan_version_string() {
2✔
299
   return Botan::version_cstr();
2✔
300
}
301

302
uint32_t botan_version_major() {
2✔
303
   return Botan::version_major();
2✔
304
}
305

306
uint32_t botan_version_minor() {
2✔
307
   return Botan::version_minor();
2✔
308
}
309

310
uint32_t botan_version_patch() {
1✔
311
   return Botan::version_patch();
1✔
312
}
313

314
uint32_t botan_version_datestamp() {
1✔
315
   return Botan::version_datestamp();
1✔
316
}
317

318
int botan_constant_time_compare(const uint8_t* x, const uint8_t* y, size_t len) {
28✔
319
   if(len > 0 && any_null_pointers(x, y)) {
28✔
320
      return BOTAN_FFI_ERROR_NULL_POINTER;
321
   }
322
   auto same = Botan::CT::is_equal(x, y, len);
28✔
323
   // Return 0 if same or -1 otherwise
324
   return static_cast<int>(same.select(1, 0)) - 1;
28✔
325
}
326

327
int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len) {
×
328
   return botan_constant_time_compare(x, y, len);
×
329
}
330

331
int botan_scrub_mem(void* mem, size_t bytes) {
1✔
332
   if(bytes > 0 && mem == nullptr) {
1✔
333
      return BOTAN_FFI_ERROR_NULL_POINTER;
334
   }
335
   Botan::secure_scrub_memory(mem, bytes);
1✔
336
   return BOTAN_FFI_SUCCESS;
1✔
337
}
338

339
int botan_hex_encode(const uint8_t* in, size_t len, char* out, uint32_t flags) {
3✔
340
   if(len > 0 && (in == nullptr || out == nullptr)) {
3✔
341
      return BOTAN_FFI_ERROR_NULL_POINTER;
342
   }
343
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
344
      const bool uppercase = (flags & BOTAN_FFI_HEX_LOWER_CASE) == 0;
3✔
345
      Botan::hex_encode(out, in, len, uppercase);
3✔
346
      return BOTAN_FFI_SUCCESS;
347
   });
3✔
348
}
349

350
int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len) {
2✔
351
   if(any_null_pointers(hex_str, out_len)) {
2✔
352
      return BOTAN_FFI_ERROR_NULL_POINTER;
353
   }
354
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
355
      const std::vector<uint8_t> bin = Botan::hex_decode(hex_str, in_len);
2✔
356
      return Botan_FFI::write_vec_output(out, out_len, bin);
2✔
357
   });
2✔
358
}
359

360
int botan_base64_encode(const uint8_t* in, size_t len, char* out, size_t* out_len) {
2✔
361
   if(len > 0 && in == nullptr) {
2✔
362
      return BOTAN_FFI_ERROR_NULL_POINTER;
363
   }
364
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
365
      const std::string base64 = Botan::base64_encode(in, len);
2✔
366
      return Botan_FFI::write_str_output(out, out_len, base64);
2✔
367
   });
2✔
368
}
369

370
int botan_base64_decode(const char* base64_str, size_t in_len, uint8_t* out, size_t* out_len) {
2✔
371
   if(any_null_pointers(out, out_len, base64_str)) {
2✔
372
      return BOTAN_FFI_ERROR_NULL_POINTER;
373
   }
374

375
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
376
      if(*out_len < Botan::base64_decode_max_output(in_len)) {
2✔
377
         *out_len = Botan::base64_decode_max_output(in_len);
1✔
378
         return BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE;
1✔
379
      }
380

381
      *out_len = Botan::base64_decode(out, std::string(base64_str, in_len));
1✔
382
      return BOTAN_FFI_SUCCESS;
1✔
383
   });
2✔
384
}
385
}
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