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

randombit / botan / 20953750484

13 Jan 2026 10:42AM UTC coverage: 90.455% (-0.004%) from 90.459%
20953750484

push

github

web-flow
Merge pull request #5234 from Rohde-Schwarz/feature/ffi_count_for_dn

FFI: add `*_count()` functions for DN enumerators

102152 of 112931 relevant lines covered (90.46%)

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

22
extern "C" {
23

24
using namespace Botan_FFI;
25

26
#if defined(BOTAN_HAS_X509_CERTIFICATES)
27

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

31
#endif
32

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

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

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

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

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

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

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

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

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

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

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

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

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

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

119
   *key = nullptr;
2✔
120

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

371
namespace {
372

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

392
   BOTAN_ASSERT_UNREACHABLE();
×
393
}
394

395
}  // namespace
396

397
extern "C" {
398

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

549
namespace {
550

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

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

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

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

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

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

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

610
}  // namespace
611

612
extern "C" {
613

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

785
#if defined(BOTAN_HAS_X509_CERTIFICATES)
786

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

790
#endif
791

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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