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

randombit / botan / 21850311256

10 Feb 2026 03:17AM UTC coverage: 91.635% (+0.001%) from 91.634%
21850311256

Pull #5302

github

web-flow
Merge 26bacb252 into 1d119e57a
Pull Request #5302: Cleanup various header inclusions

104007 of 113502 relevant lines covered (91.63%)

11071649.74 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/assert.h>
15
   #include <botan/asn1_time.h>
16
   #include <botan/data_src.h>
17
   #include <botan/x509_crl.h>
18
   #include <botan/x509cert.h>
19
   #include <botan/x509path.h>
20
   #include <botan/internal/ffi_mp.h>
21
   #include <botan/internal/ffi_oid.h>
22
#endif
23

24
extern "C" {
25

26
using namespace Botan_FFI;
27

28
#if defined(BOTAN_HAS_X509_CERTIFICATES)
29

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

33
#endif
34

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

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

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

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

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

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

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

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

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

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

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

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

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

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

121
   *key = nullptr;
2✔
122

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

373
namespace {
374

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

394
   BOTAN_ASSERT_UNREACHABLE();
×
395
}
396

397
}  // namespace
398

399
extern "C" {
400

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

551
namespace {
552

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

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

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

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

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

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

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

612
}  // namespace
613

614
extern "C" {
615

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

787
#if defined(BOTAN_HAS_X509_CERTIFICATES)
788

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

792
#endif
793

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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