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

randombit / botan / 21164304246

20 Jan 2026 08:18AM UTC coverage: 90.397% (-0.08%) from 90.477%
21164304246

Pull #5252

github

web-flow
Merge 77c7c8f8c into 87c26d8ba
Pull Request #5252: FIX: `botan_x509_cert_allowed_extended_usage_*` should return "1" on true

102434 of 113316 relevant lines covered (90.4%)

12498413.76 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() ? 1 : 0; });
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) ? 1 : 0;
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(cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? 1 : 0; });
8✔
246
#else
247
   BOTAN_UNUSED(cert, oid);
248
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
249
#endif
250
}
251

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

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

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

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

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

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

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

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

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

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

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

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

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

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

370
namespace {
371

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

391
   BOTAN_ASSERT_UNREACHABLE();
×
392
}
393

394
}  // namespace
395

396
extern "C" {
397

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

548
namespace {
549

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

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

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

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

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

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

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

609
}  // namespace
610

611
extern "C" {
612

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

784
#if defined(BOTAN_HAS_X509_CERTIFICATES)
785

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

789
#endif
790

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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