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

randombit / botan / 21657860772

04 Feb 2026 12:43AM UTC coverage: 90.078% (+0.007%) from 90.071%
21657860772

push

github

web-flow
Merge pull request #5279 from randombit/jack/asn1-time-h

Move ASN1_Time to its own header to avoid <chrono> inclusions

102242 of 113504 relevant lines covered (90.08%)

11609650.0 hits per line

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

95.08
/src/lib/ffi/ffi_cert.cpp
1
/*
2
* (C) 2015,2017,2018 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/internal/ffi_pkey.h>
10
#include <botan/internal/ffi_util.h>
11
#include <memory>
12

13
#if defined(BOTAN_HAS_X509_CERTIFICATES)
14
   #include <botan/asn1_time.h>
15
   #include <botan/data_src.h>
16
   #include <botan/x509_crl.h>
17
   #include <botan/x509cert.h>
18
   #include <botan/x509path.h>
19
   #include <botan/internal/ffi_mp.h>
20
   #include <botan/internal/ffi_oid.h>
21
#endif
22

23
extern "C" {
24

25
using namespace Botan_FFI;
26

27
#if defined(BOTAN_HAS_X509_CERTIFICATES)
28

29
BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
30✔
30
BOTAN_FFI_DECLARE_STRUCT(botan_x509_general_name_struct, Botan::GeneralName, 0x563654FD);
198✔
31

32
#endif
33

34
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
29✔
35
   if(cert_obj == nullptr || cert_path == nullptr) {
29✔
36
      return BOTAN_FFI_ERROR_NULL_POINTER;
37
   }
38

39
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
40

41
   return ffi_guard_thunk(__func__, [=]() -> int {
29✔
42
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
29✔
43
      return ffi_new_object(cert_obj, std::move(c));
29✔
44
   });
58✔
45

46
#else
47
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
48
#endif
49
}
50

51
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
52
   if(cert_obj == nullptr) {
1✔
53
      return BOTAN_FFI_ERROR_NULL_POINTER;
54
   }
55

56
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
57

58
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
59
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
60
      return ffi_new_object(cert_obj, std::move(c));
1✔
61
   });
2✔
62

63
#else
64
   BOTAN_UNUSED(cert);
65
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
66
#endif
67
}
68

69
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
70
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
71
      return BOTAN_FFI_ERROR_NULL_POINTER;
72
   }
73

74
#if defined(BOTAN_HAS_X509_CERTIFICATES)
75
   return ffi_guard_thunk(__func__, [=]() -> int {
×
76
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
77
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
78
      return ffi_new_object(cert_obj, std::move(c));
×
79
   });
×
80
#else
81
   BOTAN_UNUSED(cert_bits_len);
82
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
83
#endif
84
}
85

86
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
87
#if defined(BOTAN_HAS_X509_CERTIFICATES)
88
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? 1 : 0; });
4✔
89
#else
90
   BOTAN_UNUSED(cert);
91
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
92
#endif
93
}
94

95
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
96
#if defined(BOTAN_HAS_X509_CERTIFICATES)
97
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
98
      if(Botan::any_null_pointers(path_limit)) {
99
         return BOTAN_FFI_ERROR_NULL_POINTER;
100
      }
101

102
      if(const auto path_len = c.path_length_constraint()) {
103
         *path_limit = path_len.value();
104
         return BOTAN_FFI_SUCCESS;
105
      } else {
106
         return BOTAN_FFI_ERROR_NO_VALUE;
107
      }
108
   });
109
#else
110
   BOTAN_UNUSED(cert, path_limit);
111
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
112
#endif
113
}
114

115
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
116
   if(key == nullptr) {
2✔
117
      return BOTAN_FFI_ERROR_NULL_POINTER;
118
   }
119

120
   *key = nullptr;
2✔
121

122
#if defined(BOTAN_HAS_X509_CERTIFICATES)
123
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
124
      auto public_key = safe_get(cert).subject_public_key();
2✔
125
      return ffi_new_object(key, std::move(public_key));
2✔
126
   });
4✔
127
#else
128
   BOTAN_UNUSED(cert);
129
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
130
#endif
131
}
132

133
int botan_x509_cert_get_issuer_dn(
8✔
134
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
135
#if defined(BOTAN_HAS_X509_CERTIFICATES)
136
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
137
      auto issuer_info = c.issuer_info(key);
138
      if(index < issuer_info.size()) {
139
         // TODO(Botan4) change the type of out and remove this cast
140
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
141
      } else {
142
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
143
      }
144
   });
145
#else
146
   BOTAN_UNUSED(cert, key, index, out, out_len);
147
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
148
#endif
149
}
150

151
int botan_x509_cert_get_issuer_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
152
#if defined(BOTAN_HAS_X509_CERTIFICATES)
153
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
154
      if(Botan::any_null_pointers(count)) {
155
         return BOTAN_FFI_ERROR_NULL_POINTER;
156
      }
157

158
      *count = c.issuer_info(key).size();
159
      return BOTAN_FFI_SUCCESS;
160
   });
161
#else
162
   BOTAN_UNUSED(cert, key, count);
163
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
164
#endif
165
}
166

167
int botan_x509_cert_get_subject_dn(
8✔
168
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
169
#if defined(BOTAN_HAS_X509_CERTIFICATES)
170
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
171
      auto subject_info = c.subject_info(key);
172
      if(index < subject_info.size()) {
173
         // TODO(Botan4) change the type of out and remove this cast
174
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
175
      } else {
176
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
177
      }
178
   });
179
#else
180
   BOTAN_UNUSED(cert, key, index, out, out_len);
181
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
182
#endif
183
}
184

185
int botan_x509_cert_get_subject_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
186
#if defined(BOTAN_HAS_X509_CERTIFICATES)
187
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
188
      if(Botan::any_null_pointers(count)) {
189
         return BOTAN_FFI_ERROR_NULL_POINTER;
190
      }
191

192
      *count = c.subject_info(key).size();
193
      return BOTAN_FFI_SUCCESS;
194
   });
195
#else
196
   BOTAN_UNUSED(cert, key, count);
197
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
198
#endif
199
}
200

201
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
202
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
203
}
204

205
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
206
#if defined(BOTAN_HAS_X509_CERTIFICATES)
207
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
208
#else
209
   BOTAN_UNUSED(cert, ctx, view);
210
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
211
#endif
212
}
213

214
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
215
#if defined(BOTAN_HAS_X509_CERTIFICATES)
216
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
217
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
218
      if(c.allowed_usage(k)) {
219
         return BOTAN_FFI_SUCCESS;
220
      }
221
      return 1;
222
   });
223
#else
224
   BOTAN_UNUSED(cert, key_usage);
225
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
226
#endif
227
}
228

229
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
230
#if defined(BOTAN_HAS_X509_CERTIFICATES)
231
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
232
      if(Botan::any_null_pointers(oid)) {
233
         return BOTAN_FFI_ERROR_NULL_POINTER;
234
      }
235

236
      return c.has_ex_constraint(oid) ? BOTAN_FFI_SUCCESS : 1;
237
   });
238
#else
239
   BOTAN_UNUSED(cert, oid);
240
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
241
#endif
242
}
243

244
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
245
#if defined(BOTAN_HAS_X509_CERTIFICATES)
246
   return BOTAN_FFI_VISIT(
8✔
247
      cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? BOTAN_FFI_SUCCESS : 1; });
248
#else
249
   BOTAN_UNUSED(cert, oid);
250
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
251
#endif
252
}
253

254
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
30✔
255
#if defined(BOTAN_HAS_X509_CERTIFICATES)
256
   return BOTAN_FFI_CHECKED_DELETE(cert);
30✔
257
#else
258
   BOTAN_UNUSED(cert);
259
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
260
#endif
261
}
262

263
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
264
#if defined(BOTAN_HAS_X509_CERTIFICATES)
265
   return BOTAN_FFI_VISIT(cert,
6✔
266
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
267
#else
268
   BOTAN_UNUSED(cert, out, out_len);
269
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
270
#endif
271
}
272

273
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
274
#if defined(BOTAN_HAS_X509_CERTIFICATES)
275
   return BOTAN_FFI_VISIT(cert,
4✔
276
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
277
#else
278
   BOTAN_UNUSED(cert, out, out_len);
279
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
280
#endif
281
}
282

283
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
284
#if defined(BOTAN_HAS_X509_CERTIFICATES)
285
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
286
#else
287
   BOTAN_UNUSED(cert, time_since_epoch);
288
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
289
#endif
290
}
291

292
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
293
#if defined(BOTAN_HAS_X509_CERTIFICATES)
294
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
295
#else
296
   BOTAN_UNUSED(cert, time_since_epoch);
297
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
298
#endif
299
}
300

301
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
302
#if defined(BOTAN_HAS_X509_CERTIFICATES)
303
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
304
#else
305
   BOTAN_UNUSED(cert, out, out_len);
306
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
307
#endif
308
}
309

310
int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) {
1✔
311
#if defined(BOTAN_HAS_X509_CERTIFICATES)
312
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
2✔
313
      if(Botan::any_null_pointers(serial_number)) {
314
         return BOTAN_FFI_ERROR_NULL_POINTER;
315
      }
316

317
      auto serial_bn = Botan::BigInt::from_bytes(c.serial_number());
318
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
319
   });
320
#else
321
   BOTAN_UNUSED(cert, serial_number);
322
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
323
#endif
324
}
325

326
int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) {
3✔
327
#if defined(BOTAN_HAS_X509_CERTIFICATES)
328
   // TODO(Botan4) change the type of out and remove this cast
329

330
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
331
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
332
   });
333
#else
334
   BOTAN_UNUSED(cert, hash, out, out_len);
335
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
336
#endif
337
}
338

339
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
340
#if defined(BOTAN_HAS_X509_CERTIFICATES)
341
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
342
#else
343
   BOTAN_UNUSED(cert, out, out_len);
344
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
345
#endif
346
}
347

348
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
349
#if defined(BOTAN_HAS_X509_CERTIFICATES)
350
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
351
#else
352
   BOTAN_UNUSED(cert, out, out_len);
353
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
354
#endif
355
}
356

357
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
358
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
359
}
360

361
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
362
#if defined(BOTAN_HAS_X509_CERTIFICATES)
363
   return BOTAN_FFI_VISIT(cert,
6✔
364
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
365
#else
366
   BOTAN_UNUSED(cert, ctx, view);
367
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
368
#endif
369
}
370
}
371

372
namespace {
373

374
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
301✔
375
   using Type = Botan::GeneralName::NameType;
301✔
376
   switch(gn_type) {
301✔
377
      case Type::Unknown:
1✔
378
         return std::nullopt;
1✔
379
      case Type::RFC822:
83✔
380
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
381
      case Type::DNS:
73✔
382
         return BOTAN_X509_DNS_NAME;
73✔
383
      case Type::URI:
28✔
384
         return BOTAN_X509_URI;
28✔
385
      case Type::DN:
95✔
386
         return BOTAN_X509_DIRECTORY_NAME;
95✔
387
      case Type::IPv4:
21✔
388
         return BOTAN_X509_IP_ADDRESS;
21✔
389
      case Type::Other:
×
390
         return BOTAN_X509_OTHER_NAME;
×
391
   }
392

393
   BOTAN_ASSERT_UNREACHABLE();
×
394
}
395

396
}  // namespace
397

398
extern "C" {
399

400
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
401
#if defined(BOTAN_HAS_X509_CERTIFICATES)
402
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
403
      if(Botan::any_null_pointers(type)) {
404
         return BOTAN_FFI_ERROR_NULL_POINTER;
405
      }
406

407
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
408
      if(!mapped_type.has_value()) {
409
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
410
      }
411

412
      *type = mapped_type.value();
413
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
414
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
415
      }
416

417
      return BOTAN_FFI_SUCCESS;
418
   });
419
#else
420
   BOTAN_UNUSED(name, type);
421
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
422
#endif
423
}
424

425
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
426
                                              botan_view_ctx ctx,
427
                                              botan_view_str_fn view) {
428
#if defined(BOTAN_HAS_X509_CERTIFICATES)
429
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
430
      const auto type = to_botan_x509_general_name_types(n.type_code());
431
      if(!type) {
432
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
433
      }
434

435
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
436
         type != BOTAN_X509_IP_ADDRESS) {
437
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
438
      }
439

440
      return invoke_view_callback(view, ctx, n.name());
441
   });
442
#else
443
   BOTAN_UNUSED(name, ctx, view);
444
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
445
#endif
446
}
447

448
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
449
                                              botan_view_ctx ctx,
450
                                              botan_view_bin_fn view) {
451
#if defined(BOTAN_HAS_X509_CERTIFICATES)
452
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
453
      const auto type = to_botan_x509_general_name_types(n.type_code());
454
      if(!type) {
455
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
456
      }
457

458
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
459
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
460
      }
461

462
      return invoke_view_callback(view, ctx, n.binary_name());
463
   });
464
#else
465
   BOTAN_UNUSED(name, ctx, view);
466
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
467
#endif
468
}
469

470
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
471
#if defined(BOTAN_HAS_X509_CERTIFICATES)
472
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
473
#else
474
   BOTAN_UNUSED(name);
475
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
476
#endif
477
}
478

479
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
480
                                               size_t index,
481
                                               botan_x509_general_name_t* constraint) {
482
#if defined(BOTAN_HAS_X509_CERTIFICATES)
483
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
484
      if(Botan::any_null_pointers(constraint)) {
485
         return BOTAN_FFI_ERROR_NULL_POINTER;
486
      }
487

488
      const auto& constraints = c.name_constraints().permitted();
489
      if(index >= constraints.size()) {
490
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
491
      }
492

493
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
494
   });
495
#else
496
   BOTAN_UNUSED(cert, index, constraint);
497
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
498
#endif
499
}
500

501
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
502
#if defined(BOTAN_HAS_X509_CERTIFICATES)
503
   if(Botan::any_null_pointers(count)) {
1✔
504
      return BOTAN_FFI_ERROR_NULL_POINTER;
505
   }
506

507
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
508
#else
509
   BOTAN_UNUSED(cert, count);
510
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
511
#endif
512
}
513

514
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
515
                                              size_t index,
516
                                              botan_x509_general_name_t* constraint) {
517
#if defined(BOTAN_HAS_X509_CERTIFICATES)
518
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
519
      if(Botan::any_null_pointers(constraint)) {
520
         return BOTAN_FFI_ERROR_NULL_POINTER;
521
      }
522

523
      const auto& constraints = c.name_constraints().excluded();
524
      if(index >= constraints.size()) {
525
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
526
      }
527

528
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
529
   });
530
#else
531
   BOTAN_UNUSED(cert, index, constraint);
532
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
533
#endif
534
}
535

536
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
537
#if defined(BOTAN_HAS_X509_CERTIFICATES)
538
   if(Botan::any_null_pointers(count)) {
1✔
539
      return BOTAN_FFI_ERROR_NULL_POINTER;
540
   }
541

542
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
543
#else
544
   BOTAN_UNUSED(cert, count);
545
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
546
#endif
547
}
548
}
549

550
namespace {
551

552
/**
553
 * As specified in RFC 5280 Section 4.2.1.6. alternative names essentially are a
554
 * collection of GeneralNames. This allows mapping a single entry of @p altnames
555
 * to a GeneralName by its @p index. If the index is out of range, std::nullopt
556
 * is returned.
557
 *
558
 * NOTE: if the set of alternative name types handled here is extended,
559
 *       count_general_names_in() must be updated accordingly!
560
 */
561
std::optional<Botan::GeneralName> extract_general_name_at(const Botan::AlternativeName& altnames, size_t index) {
132✔
562
   if(index < altnames.email().size()) {
132✔
563
      auto itr = altnames.email().begin();
12✔
564
      std::advance(itr, index);
12✔
565
      return Botan::GeneralName::email(*itr);
36✔
566
   }
567
   index -= altnames.email().size();
120✔
568

569
   if(index < altnames.dns().size()) {
120✔
570
      auto itr = altnames.dns().begin();
36✔
571
      std::advance(itr, index);
36✔
572
      return Botan::GeneralName::dns(*itr);
108✔
573
   }
574
   index -= altnames.dns().size();
84✔
575

576
   if(index < altnames.directory_names().size()) {
84✔
577
      auto itr = altnames.directory_names().begin();
36✔
578
      std::advance(itr, index);
36✔
579
      return Botan::GeneralName::directory_name(*itr);
108✔
580
   }
581
   index -= altnames.directory_names().size();
48✔
582

583
   if(index < altnames.uris().size()) {
48✔
584
      auto itr = altnames.uris().begin();
24✔
585
      std::advance(itr, index);
24✔
586
      return Botan::GeneralName::uri(*itr);
72✔
587
   }
588
   index -= altnames.uris().size();
24✔
589

590
   if(index < altnames.ipv4_address().size()) {
24✔
591
      auto itr = altnames.ipv4_address().begin();
12✔
592
      std::advance(itr, index);
12✔
593
      return Botan::GeneralName::ipv4_address(*itr);
36✔
594
   }
595

596
   return std::nullopt;
12✔
597
}
598

599
/**
600
 * Counts the total number of GeneralNames contained in the given
601
 * AlternativeName @p alt_names.
602
 *
603
 * NOTE: if the set of alternative name types handled here is extended,
604
 *       extract_general_name_at() must be updated accordingly!
605
 */
606
size_t count_general_names_in(const Botan::AlternativeName& alt_names) {
12✔
607
   return alt_names.email().size() + alt_names.dns().size() + alt_names.directory_names().size() +
12✔
608
          alt_names.uris().size() + alt_names.ipv4_address().size();
12✔
609
}
610

611
}  // namespace
612

613
extern "C" {
614

615
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
616
                                              size_t index,
617
                                              botan_x509_general_name_t* alt_name) {
618
#if defined(BOTAN_HAS_X509_CERTIFICATES)
619
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
620
      if(Botan::any_null_pointers(alt_name)) {
621
         return BOTAN_FFI_ERROR_NULL_POINTER;
622
      }
623

624
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
625
         return BOTAN_FFI_ERROR_NO_VALUE;
626
      }
627

628
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
629
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
630
      }
631

632
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
633
   });
634
#else
635
   BOTAN_UNUSED(cert, index, alt_name);
636
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
637
#endif
638
}
639

640
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
641
#if defined(BOTAN_HAS_X509_CERTIFICATES)
642
   if(Botan::any_null_pointers(count)) {
6✔
643
      return BOTAN_FFI_ERROR_NULL_POINTER;
644
   }
645

646
   return BOTAN_FFI_VISIT(
12✔
647
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
648
#else
649
   BOTAN_UNUSED(cert, count);
650
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
651
#endif
652
}
653

654
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
655
                                             size_t index,
656
                                             botan_x509_general_name_t* alt_name) {
657
#if defined(BOTAN_HAS_X509_CERTIFICATES)
658
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
659
      if(Botan::any_null_pointers(alt_name)) {
660
         return BOTAN_FFI_ERROR_NULL_POINTER;
661
      }
662

663
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
664
         return BOTAN_FFI_ERROR_NO_VALUE;
665
      }
666

667
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
668
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
669
      }
670

671
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
672
   });
673
#else
674
   BOTAN_UNUSED(cert, index, alt_name);
675
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
676
#endif
677
}
678

679
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
680
#if defined(BOTAN_HAS_X509_CERTIFICATES)
681
   if(Botan::any_null_pointers(count)) {
6✔
682
      return BOTAN_FFI_ERROR_NULL_POINTER;
683
   }
684

685
   return BOTAN_FFI_VISIT(
12✔
686
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.issuer_alt_name()); });
687
#else
688
   BOTAN_UNUSED(cert, count);
689
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
690
#endif
691
}
692

693
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
694
   if(hostname == nullptr) {
6✔
695
      return BOTAN_FFI_ERROR_NULL_POINTER;
696
   }
697

698
#if defined(BOTAN_HAS_X509_CERTIFICATES)
699
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
700
#else
701
   BOTAN_UNUSED(cert);
702
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
703
#endif
704
}
705

706
int botan_x509_cert_verify(int* result_code,
4✔
707
                           botan_x509_cert_t cert,
708
                           const botan_x509_cert_t* intermediates,
709
                           size_t intermediates_len,
710
                           const botan_x509_cert_t* trusted,
711
                           size_t trusted_len,
712
                           const char* trusted_path,
713
                           size_t required_strength,
714
                           const char* hostname_cstr,
715
                           uint64_t reference_time) {
716
   if(required_strength == 0) {
4✔
717
      required_strength = 110;
3✔
718
   }
719

720
#if defined(BOTAN_HAS_X509_CERTIFICATES)
721
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
722
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
723
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
724
      const auto validation_time = reference_time == 0
4✔
725
                                      ? std::chrono::system_clock::now()
4✔
726
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
727

728
      std::vector<Botan::X509_Certificate> end_certs;
4✔
729
      end_certs.push_back(safe_get(cert));
4✔
730
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
731
         end_certs.push_back(safe_get(intermediates[i]));
5✔
732
      }
733

734
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
735
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
736
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
737

738
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
739
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
740
         trusted_roots.push_back(trusted_from_path.get());
×
741
      }
742

743
      if(trusted_len > 0) {
4✔
744
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
745
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
746
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
747
         }
748
         trusted_roots.push_back(trusted_extra.get());
4✔
749
      }
750

751
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
752

753
      auto validation_result =
4✔
754
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
755

756
      if(result_code != nullptr) {
4✔
757
         *result_code = static_cast<int>(validation_result.result());
4✔
758
      }
759

760
      if(validation_result.successful_validation()) {
4✔
761
         return 0;
762
      } else {
763
         return 1;
3✔
764
      }
765
   });
4✔
766
#else
767
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
768
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
769
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
770
#endif
771
}
772

773
const char* botan_x509_cert_validation_status(int code) {
11✔
774
   if(code < 0) {
11✔
775
      return nullptr;
776
   }
777

778
#if defined(BOTAN_HAS_X509_CERTIFICATES)
779
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
780
   return Botan::to_string(sc);
11✔
781
#else
782
   return nullptr;
783
#endif
784
}
785

786
#if defined(BOTAN_HAS_X509_CERTIFICATES)
787

788
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
8✔
789
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_entry_struct, Botan::CRL_Entry, 0x4EAA5346);
1✔
790

791
#endif
792

793
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
794
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
795
      return BOTAN_FFI_ERROR_NULL_POINTER;
796
   }
797

798
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
799

800
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
801
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
802
      return ffi_new_object(crl_obj, std::move(c));
14✔
803
   });
14✔
804

805
#else
806
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
807
#endif
808
}
809

810
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
811
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
812
      return BOTAN_FFI_ERROR_NULL_POINTER;
813
   }
814

815
#if defined(BOTAN_HAS_X509_CERTIFICATES)
816
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
817
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
818
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
819
      return ffi_new_object(crl_obj, std::move(c));
1✔
820
   });
3✔
821
#else
822
   BOTAN_UNUSED(crl_bits_len);
823
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
824
#endif
825
}
826

827
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
828
#if defined(BOTAN_HAS_X509_CERTIFICATES)
829
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
830
      if(Botan::any_null_pointers(time_since_epoch)) {
831
         return BOTAN_FFI_ERROR_NULL_POINTER;
832
      }
833
      *time_since_epoch = c.this_update().time_since_epoch();
834
      return BOTAN_FFI_SUCCESS;
835
   });
836
#else
837
   BOTAN_UNUSED(crl, time_since_epoch);
838
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
839
#endif
840
}
841

842
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
4✔
843
#if defined(BOTAN_HAS_X509_CERTIFICATES)
844
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
8✔
845
      const auto& time = c.next_update();
846
      if(!time.time_is_set()) {
847
         return BOTAN_FFI_ERROR_NO_VALUE;
848
      }
849

850
      if(Botan::any_null_pointers(time_since_epoch)) {
851
         return BOTAN_FFI_ERROR_NULL_POINTER;
852
      }
853

854
      *time_since_epoch = c.next_update().time_since_epoch();
855
      return BOTAN_FFI_SUCCESS;
856
   });
857
#else
858
   BOTAN_UNUSED(crl, time_since_epoch);
859
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
860
#endif
861
}
862

863
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
8✔
864
#if defined(BOTAN_HAS_X509_CERTIFICATES)
865
   return BOTAN_FFI_CHECKED_DELETE(crl);
8✔
866
#else
867
   BOTAN_UNUSED(crl);
868
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
869
#endif
870
}
871

872
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
873
#if defined(BOTAN_HAS_X509_CERTIFICATES)
874
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
875
#else
876
   BOTAN_UNUSED(cert);
877
   BOTAN_UNUSED(crl);
878
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
879
#endif
880
}
881

882
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
3✔
883
#if defined(BOTAN_HAS_X509_CERTIFICATES)
884
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
6✔
885
      const auto& entries = c.get_revoked();
886
      if(index >= entries.size()) {
887
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
888
      }
889

890
      if(Botan::any_null_pointers(entry)) {
891
         return BOTAN_FFI_ERROR_NULL_POINTER;
892
      }
893

894
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
895
   });
896
#else
897
   BOTAN_UNUSED(crl, index, entry);
898
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
899
#endif
900
}
901

902
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
2✔
903
#if defined(BOTAN_HAS_X509_CERTIFICATES)
904
   if(Botan::any_null_pointers(count)) {
2✔
905
      return BOTAN_FFI_ERROR_NULL_POINTER;
906
   }
907

908
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
4✔
909
#else
910
   BOTAN_UNUSED(crl, count);
911
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
912
#endif
913
}
914

915
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
1✔
916
#if defined(BOTAN_HAS_X509_CERTIFICATES)
917
   return BOTAN_FFI_CHECKED_DELETE(entry);
1✔
918
#else
919
   BOTAN_UNUSED(entry);
920
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
921
#endif
922
}
923

924
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
1✔
925
#if defined(BOTAN_HAS_X509_CERTIFICATES)
926
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
927
      if(Botan::any_null_pointers(reason_code)) {
928
         return BOTAN_FFI_ERROR_NULL_POINTER;
929
      }
930

931
      *reason_code = static_cast<int>(e.reason_code());
932
      return BOTAN_FFI_SUCCESS;
933
   });
934
#else
935
   BOTAN_UNUSED(entry, reason_code);
936
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
937
#endif
938
}
939

940
int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) {
1✔
941
#if defined(BOTAN_HAS_X509_CERTIFICATES)
942
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
943
      if(Botan::any_null_pointers(serial_number)) {
944
         return BOTAN_FFI_ERROR_NULL_POINTER;
945
      }
946

947
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
948
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
949
   });
950
#else
951
   BOTAN_UNUSED(entry, serial_number);
952
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
953
#endif
954
}
955

956
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
957
#if defined(BOTAN_HAS_X509_CERTIFICATES)
958
   return BOTAN_FFI_VISIT(
2✔
959
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
960
#else
961
   BOTAN_UNUSED(entry, ctx, view);
962
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
963
#endif
964
}
965

966
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
1✔
967
#if defined(BOTAN_HAS_X509_CERTIFICATES)
968
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
969
      if(Botan::any_null_pointers(time_since_epoch)) {
970
         return BOTAN_FFI_ERROR_NULL_POINTER;
971
      }
972

973
      *time_since_epoch = e.expire_time().time_since_epoch();
974
      return BOTAN_FFI_SUCCESS;
975
   });
976
#else
977
   BOTAN_UNUSED(entry, time_since_epoch);
978
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
979
#endif
980
}
981

982
int botan_x509_cert_verify_with_crl(int* result_code,
12✔
983
                                    botan_x509_cert_t cert,
984
                                    const botan_x509_cert_t* intermediates,
985
                                    size_t intermediates_len,
986
                                    const botan_x509_cert_t* trusted,
987
                                    size_t trusted_len,
988
                                    const botan_x509_crl_t* crls,
989
                                    size_t crls_len,
990
                                    const char* trusted_path,
991
                                    size_t required_strength,
992
                                    const char* hostname_cstr,
993
                                    uint64_t reference_time) {
994
   if(required_strength == 0) {
12✔
995
      required_strength = 110;
2✔
996
   }
997

998
#if defined(BOTAN_HAS_X509_CERTIFICATES)
999
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
1000
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
14✔
1001
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
12✔
1002
      const auto validation_time = reference_time == 0
12✔
1003
                                      ? std::chrono::system_clock::now()
12✔
1004
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1005

1006
      std::vector<Botan::X509_Certificate> end_certs;
12✔
1007
      end_certs.push_back(safe_get(cert));
12✔
1008
      for(size_t i = 0; i != intermediates_len; ++i) {
30✔
1009
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1010
      }
1011

1012
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
12✔
1013
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
12✔
1014
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
12✔
1015
      std::vector<Botan::Certificate_Store*> trusted_roots;
12✔
1016

1017
      if(trusted_path != nullptr && *trusted_path != 0) {
12✔
1018
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1019
         trusted_roots.push_back(trusted_from_path.get());
2✔
1020
      }
1021

1022
      if(trusted_len > 0) {
12✔
1023
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
18✔
1024
         for(size_t i = 0; i != trusted_len; ++i) {
18✔
1025
            trusted_extra->add_certificate(safe_get(trusted[i]));
9✔
1026
         }
1027
         trusted_roots.push_back(trusted_extra.get());
9✔
1028
      }
1029

1030
      if(crls_len > 0) {
12✔
1031
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
1032
         for(size_t i = 0; i != crls_len; ++i) {
13✔
1033
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
1034
         }
1035
         trusted_roots.push_back(trusted_crls.get());
5✔
1036
      }
1037

1038
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
24✔
1039

1040
      auto validation_result =
12✔
1041
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
12✔
1042

1043
      if(result_code != nullptr) {
12✔
1044
         *result_code = static_cast<int>(validation_result.result());
12✔
1045
      }
1046

1047
      if(validation_result.successful_validation()) {
12✔
1048
         return 0;
1049
      } else {
1050
         return 1;
8✔
1051
      }
1052
   });
14✔
1053
#else
1054
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1055
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1056
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1057
#endif
1058
}
1059
}
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