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

randombit / botan / 24872040145

24 Apr 2026 01:10AM UTC coverage: 89.401% (-0.07%) from 89.474%
24872040145

push

github

web-flow
Merge pull request #5539 from randombit/jack/cert-cache

Refactor and optimize Windows certificate store

106671 of 119318 relevant lines covered (89.4%)

11479699.69 hits per line

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

93.88
/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/assert.h>
10
#include <botan/internal/ffi_cert.h>
11
#include <botan/internal/ffi_pkey.h>
12
#include <botan/internal/ffi_rng.h>
13
#include <botan/internal/ffi_util.h>
14
#include <memory>
15

16
#if defined(BOTAN_HAS_X509_CERTIFICATES)
17
   #include <botan/data_src.h>
18
   #include <botan/x509_crl.h>
19
   #include <botan/x509_ext.h>
20
   #include <botan/x509cert.h>
21
   #include <botan/x509path.h>
22
   #include <botan/internal/ffi_mp.h>
23
   #include <botan/internal/ffi_oid.h>
24
   #include <botan/internal/loadstor.h>
25
   #include <botan/internal/stl_util.h>
26
#endif
27

28
#if defined(BOTAN_HAS_X509_CERTIFICATES)
29

30
namespace Botan_FFI {
31

32
namespace {
33

34
/**
35
 * As specified in RFC 5280 Section 4.2.1.6. alternative names essentially are a
36
 * collection of GeneralNames. This allows mapping a single entry of @p altnames
37
 * to a GeneralName by its @p index. If the index is out of range, std::nullopt
38
 * is returned.
39
 *
40
 * NOTE: if the set of alternative name types handled here is extended,
41
 *       count_general_names_in() must be updated accordingly!
42
 */
43
std::optional<Botan::GeneralName> extract_general_name_at(const Botan::AlternativeName& altnames, size_t index) {
132✔
44
   if(index < altnames.email().size()) {
132✔
45
      auto itr = altnames.email().begin();
12✔
46
      std::advance(itr, index);
12✔
47
      return Botan::GeneralName::email(*itr);
36✔
48
   }
49
   index -= altnames.email().size();
120✔
50

51
   if(index < altnames.dns().size()) {
120✔
52
      auto itr = altnames.dns().begin();
36✔
53
      std::advance(itr, index);
36✔
54
      return Botan::GeneralName::dns(*itr);
108✔
55
   }
56
   index -= altnames.dns().size();
84✔
57

58
   if(index < altnames.directory_names().size()) {
84✔
59
      auto itr = altnames.directory_names().begin();
36✔
60
      std::advance(itr, index);
36✔
61
      return Botan::GeneralName::directory_name(*itr);
144✔
62
   }
63
   index -= altnames.directory_names().size();
48✔
64

65
   if(index < altnames.uris().size()) {
48✔
66
      auto itr = altnames.uris().begin();
24✔
67
      std::advance(itr, index);
24✔
68
      return Botan::GeneralName::uri(*itr);
72✔
69
   }
70
   index -= altnames.uris().size();
24✔
71

72
   if(index < altnames.ipv4_address().size()) {
24✔
73
      auto itr = altnames.ipv4_address().begin();
12✔
74
      std::advance(itr, index);
12✔
75
      return Botan::GeneralName::ipv4_address(*itr);
36✔
76
   }
77
   index -= altnames.ipv4_address().size();
12✔
78

79
   if(index < altnames.ipv6_address().size()) {
12✔
80
      auto itr = altnames.ipv6_address().begin();
×
81
      std::advance(itr, index);
×
82
      return Botan::GeneralName::ipv6_address(*itr);
×
83
   }
84

85
   return std::nullopt;
12✔
86
}
87

88
/**
89
 * Counts the total number of GeneralNames contained in the given
90
 * AlternativeName @p alt_names.
91
 *
92
 * NOTE: if the set of alternative name types handled here is extended,
93
 *       extract_general_name_at() must be updated accordingly!
94
 */
95
size_t count_general_names_in(const Botan::AlternativeName& alt_names) {
12✔
96
   return alt_names.email().size() + alt_names.dns().size() + alt_names.directory_names().size() +
12✔
97
          alt_names.uris().size() + alt_names.ipv4_address().size() + alt_names.ipv6_address().size();
12✔
98
}
99

100
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
302✔
101
   using Type = Botan::GeneralName::NameType;
302✔
102
   switch(gn_type) {
302✔
103
      case Type::Unknown:
×
104
         return std::nullopt;
×
105
      case Type::RFC822:
83✔
106
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
107
      case Type::DNS:
73✔
108
         return BOTAN_X509_DNS_NAME;
73✔
109
      case Type::URI:
28✔
110
         return BOTAN_X509_URI;
28✔
111
      case Type::DN:
95✔
112
         return BOTAN_X509_DIRECTORY_NAME;
95✔
113
      case Type::IPv4:
23✔
114
      case Type::IPv6:
23✔
115
         return BOTAN_X509_IP_ADDRESS;
23✔
116
      case Type::Other:
×
117
         return BOTAN_X509_OTHER_NAME;
×
118
   }
119

120
   BOTAN_ASSERT_UNREACHABLE();
×
121
}
122

123
/**
124
 * Given some enumerator-style function @p fn, count how many values it can
125
 * produce before returning BOTAN_FFI_ERROR_OUT_OF_RANGE. If the first call to
126
 * @p fn returns BOTAN_FFI_ERROR_NO_VALUE, zero is written to @p count.
127
 *
128
 * If this function returns BOTAN_FFI_SUCCESS, @p count contains the number of
129
 * values that can be enumerated. Otherwise, the value of @p count is undefined.
130
 */
131
template <std::invocable<size_t> EnumeratorT>
132
int enumerator_count_values(size_t* count, EnumeratorT fn) {
11✔
133
   if(Botan::any_null_pointers(count)) {
11✔
134
      return BOTAN_FFI_ERROR_NULL_POINTER;
135
   }
136

137
   *count = 0;
11✔
138
   for(;; ++(*count)) {
12✔
139
      const auto rc = fn(*count);
46✔
140
      switch(rc) {
23✔
141
         case BOTAN_FFI_ERROR_NO_VALUE:
142
         case BOTAN_FFI_ERROR_OUT_OF_RANGE:
143
            // hit the end of the enumeration
144
            return BOTAN_FFI_SUCCESS;
145
         case BOTAN_FFI_SUCCESS:
146
            // got a value, continue counting
147
            break;
148
         default:
149
            // unexpected error from enumerator function
150
            return rc;
151
      }
152
   }
153
}
154

155
std::chrono::system_clock::time_point timepoint_from_timestamp(uint64_t time_since_epoch) {
5✔
156
   return std::chrono::system_clock::time_point(std::chrono::seconds(time_since_epoch));
5✔
157
}
158

159
std::string default_from_ptr(const char* value) {
10✔
160
   std::string ret;
10✔
161
   if(value != nullptr) {
10✔
162
      ret = value;
×
163
   }
164
   return ret;
10✔
165
}
×
166

167
}  // namespace
168

169
}  // namespace Botan_FFI
170

171
#endif
172

173
extern "C" {
174

175
using namespace Botan_FFI;
176

177
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
37✔
178
   if(cert_obj == nullptr || cert_path == nullptr) {
37✔
179
      return BOTAN_FFI_ERROR_NULL_POINTER;
180
   }
181

182
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
183

184
   return ffi_guard_thunk(__func__, [=]() -> int {
37✔
185
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
37✔
186
      return ffi_new_object(cert_obj, std::move(c));
37✔
187
   });
74✔
188

189
#else
190
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
191
#endif
192
}
193

194
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
195
   if(cert_obj == nullptr) {
1✔
196
      return BOTAN_FFI_ERROR_NULL_POINTER;
197
   }
198

199
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
200

201
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
202
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
203
      return ffi_new_object(cert_obj, std::move(c));
1✔
204
   });
2✔
205

206
#else
207
   BOTAN_UNUSED(cert);
208
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
209
#endif
210
}
211

212
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
213
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
214
      return BOTAN_FFI_ERROR_NULL_POINTER;
215
   }
216

217
#if defined(BOTAN_HAS_X509_CERTIFICATES)
218
   return ffi_guard_thunk(__func__, [=]() -> int {
×
219
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
220
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
221
      return ffi_new_object(cert_obj, std::move(c));
×
222
   });
×
223
#else
224
   BOTAN_UNUSED(cert_bits_len);
225
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
226
#endif
227
}
228
}
229

230
namespace {
231

232
#if defined(BOTAN_HAS_X509_CERTIFICATES)
233

234
int botan_x509_object_view_value(const Botan::X509_Object& object,
6✔
235
                                 botan_x509_value_type value_type,
236
                                 size_t index,
237
                                 botan_view_ctx ctx,
238
                                 botan_view_str_fn view_fn) {
239
   if(index != 0) {
6✔
240
      // As of now there are no multi-value generic string entries.
241
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
242
   }
243

244
   auto view = [=](const std::string& value) { return invoke_view_callback(view_fn, ctx, value); };
4✔
245

246
   switch(value_type) {
4✔
247
      case BOTAN_X509_PEM_ENCODING:
4✔
248
         return view(object.PEM_encode());
8✔
249
      default:
×
250
         BOTAN_ASSERT_UNREACHABLE(); /* called with unexpected (non-generic) value_type */
×
251
   }
252
}
253

254
int botan_x509_object_view_value(const Botan::X509_Object& object,
8✔
255
                                 botan_x509_value_type value_type,
256
                                 size_t index,
257
                                 botan_view_ctx ctx,
258
                                 botan_view_bin_fn view_fn) {
259
   if(index != 0) {
8✔
260
      // As of now there are no multi-value generic binary entries.
261
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
262
   }
263

264
   auto view = [=](std::span<const uint8_t> value) { return invoke_view_callback(view_fn, ctx, value); };
2✔
265

266
   switch(value_type) {
8✔
267
      case BOTAN_X509_TBS_DATA_BITS:
2✔
268
         return view(object.tbs_data());
4✔
269
      case BOTAN_X509_SIGNATURE_SCHEME_BITS:
2✔
270
         return view(object.signature_algorithm().BER_encode());
4✔
271
      case BOTAN_X509_SIGNATURE_BITS:
2✔
272
         return view(object.signature());
10✔
273
      case BOTAN_X509_DER_ENCODING:
2✔
274
         return view(object.BER_encode());
4✔
275
      default:
×
276
         BOTAN_ASSERT_UNREACHABLE(); /* called with unexpected (non-generic) value_type */
×
277
   }
278
}
279

280
#endif
281

282
}  // namespace
283

284
extern "C" {
285

286
int botan_x509_cert_view_binary_values(botan_x509_cert_t cert,
22✔
287
                                       botan_x509_value_type value_type,
288
                                       size_t index,
289
                                       botan_view_ctx ctx,
290
                                       botan_view_bin_fn view_fn) {
291
#if defined(BOTAN_HAS_X509_CERTIFICATES)
292
   if(index != 0) {
22✔
293
      // As of now there are no multi-value binary entries.
294
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
295
   }
296

297
   auto view = [=](std::span<const uint8_t> value) -> int {
18✔
298
      if(value.empty()) {
5✔
299
         return BOTAN_FFI_ERROR_NO_VALUE;
300
      } else {
301
         return invoke_view_callback(view_fn, ctx, value);
4✔
302
      }
303
   };
13✔
304

305
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
39✔
306
      switch(value_type) {
307
         case BOTAN_X509_SERIAL_NUMBER:
308
            return view(c.serial_number());
309
         case BOTAN_X509_SUBJECT_DN_BITS:
310
            return view(c.raw_subject_dn());
311
         case BOTAN_X509_ISSUER_DN_BITS:
312
            return view(c.raw_issuer_dn());
313
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
314
            return view(c.subject_key_id());
315
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
316
            return view(c.authority_key_id());
317
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
318
            return view(c.subject_public_key_info());
319

320
         case BOTAN_X509_TBS_DATA_BITS:
321
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
322
         case BOTAN_X509_SIGNATURE_BITS:
323
         case BOTAN_X509_DER_ENCODING:
324
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
325

326
         case BOTAN_X509_PEM_ENCODING:
327
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
328
         case BOTAN_X509_OCSP_RESPONDER_URLS:
329
         case BOTAN_X509_CA_ISSUERS_URLS:
330
            return BOTAN_FFI_ERROR_NO_VALUE;
331
      }
332

333
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
334
   });
335
#else
336
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
337
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
338
#endif
339
}
340

341
int botan_x509_cert_view_binary_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
5✔
342
#if defined(BOTAN_HAS_X509_CERTIFICATES)
343
   return enumerator_count_values(count, [=](size_t index) {
5✔
344
      return botan_x509_cert_view_binary_values(
10✔
345
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
346
   });
5✔
347
#else
348
   BOTAN_UNUSED(cert, value_type, count);
349
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
350
#endif
351
}
352

353
int botan_x509_cert_view_string_values(botan_x509_cert_t cert,
19✔
354
                                       botan_x509_value_type value_type,
355
                                       size_t index,
356
                                       botan_view_ctx ctx,
357
                                       botan_view_str_fn view_fn) {
358
#if defined(BOTAN_HAS_X509_CERTIFICATES)
359
   auto enumerate = [view_fn, ctx](auto values, size_t idx) -> int {
10✔
360
      if(idx >= values.size()) {
10✔
361
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
362
      } else {
363
         return invoke_view_callback(view_fn, ctx, values[idx]);
6✔
364
      }
365
   };
19✔
366

367
   auto enumerate_crl_distribution_points = [view_fn, ctx](const Botan::X509_Certificate& c, size_t idx) -> int {
25✔
368
      const auto* crl_dp_ext =
6✔
369
         c.v3_extensions().get_extension_object_as<Botan::Cert_Extension::CRL_Distribution_Points>();
12✔
370
      if(crl_dp_ext == nullptr) {
6✔
371
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;  // essentially an empty list
372
      }
373

374
      const auto& dps = crl_dp_ext->distribution_points();
5✔
375
      for(size_t i = idx; const auto& dp : dps) {
6✔
376
         const auto& uris = dp.point().uris();
5✔
377
         if(i >= uris.size()) {
5✔
378
            i -= uris.size();
1✔
379
            continue;
1✔
380
         }
381

382
         auto itr = uris.begin();
4✔
383
         std::advance(itr, i);
4✔
384
         return invoke_view_callback(view_fn, ctx, *itr);
8✔
385
      }
386

387
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
388
   };
19✔
389

390
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
38✔
391
      switch(value_type) {
392
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
393
            return enumerate_crl_distribution_points(c, index);
394
         case BOTAN_X509_OCSP_RESPONDER_URLS:
395
            return enumerate(c.ocsp_responders(), index);
396
         case BOTAN_X509_CA_ISSUERS_URLS:
397
            return enumerate(c.ca_issuers(), index);
398
         case BOTAN_X509_PEM_ENCODING:
399
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
400

401
         case BOTAN_X509_SERIAL_NUMBER:
402
         case BOTAN_X509_SUBJECT_DN_BITS:
403
         case BOTAN_X509_ISSUER_DN_BITS:
404
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
405
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
406
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
407
         case BOTAN_X509_TBS_DATA_BITS:
408
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
409
         case BOTAN_X509_SIGNATURE_BITS:
410
         case BOTAN_X509_DER_ENCODING:
411
            return BOTAN_FFI_ERROR_NO_VALUE;
412
      }
413

414
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
415
   });
416
#else
417
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
418
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
419
#endif
420
}
421

422
int botan_x509_cert_view_string_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
4✔
423
#if defined(BOTAN_HAS_X509_CERTIFICATES)
424
   return enumerator_count_values(count, [=](size_t index) {
4✔
425
      return botan_x509_cert_view_string_values(
10✔
426
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
427
   });
4✔
428
#else
429
   BOTAN_UNUSED(cert, value_type, count);
430
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
431
#endif
432
}
433

434
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
435
#if defined(BOTAN_HAS_X509_CERTIFICATES)
436
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? 1 : 0; });
4✔
437
#else
438
   BOTAN_UNUSED(cert);
439
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
440
#endif
441
}
442

443
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
444
#if defined(BOTAN_HAS_X509_CERTIFICATES)
445
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
446
      if(Botan::any_null_pointers(path_limit)) {
447
         return BOTAN_FFI_ERROR_NULL_POINTER;
448
      }
449

450
      if(const auto path_len = c.path_length_constraint()) {
451
         *path_limit = path_len.value();
452
         return BOTAN_FFI_SUCCESS;
453
      } else {
454
         return BOTAN_FFI_ERROR_NO_VALUE;
455
      }
456
   });
457
#else
458
   BOTAN_UNUSED(cert, path_limit);
459
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
460
#endif
461
}
462

463
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
464
   if(key == nullptr) {
2✔
465
      return BOTAN_FFI_ERROR_NULL_POINTER;
466
   }
467

468
   *key = nullptr;
2✔
469

470
#if defined(BOTAN_HAS_X509_CERTIFICATES)
471
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
472
      auto public_key = safe_get(cert).subject_public_key();
2✔
473
      return ffi_new_object(key, std::move(public_key));
2✔
474
   });
4✔
475
#else
476
   BOTAN_UNUSED(cert);
477
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
478
#endif
479
}
480

481
int botan_x509_cert_get_issuer_dn(
8✔
482
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
483
   if(key == nullptr) {
8✔
484
      return BOTAN_FFI_ERROR_NULL_POINTER;
485
   }
486
#if defined(BOTAN_HAS_X509_CERTIFICATES)
487
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
488
      auto issuer_info = c.issuer_info(key);
489
      if(index < issuer_info.size()) {
490
         // TODO(Botan4) change the type of out and remove this cast
491
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
492
      } else {
493
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
494
      }
495
   });
496
#else
497
   BOTAN_UNUSED(cert, key, index, out, out_len);
498
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
499
#endif
500
}
501

502
int botan_x509_cert_get_issuer_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
503
#if defined(BOTAN_HAS_X509_CERTIFICATES)
504
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
505
      if(Botan::any_null_pointers(count)) {
506
         return BOTAN_FFI_ERROR_NULL_POINTER;
507
      }
508

509
      *count = c.issuer_info(key).size();
510
      return BOTAN_FFI_SUCCESS;
511
   });
512
#else
513
   BOTAN_UNUSED(cert, key, count);
514
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
515
#endif
516
}
517

518
int botan_x509_cert_get_subject_dn(
8✔
519
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
520
   if(key == nullptr) {
8✔
521
      return BOTAN_FFI_ERROR_NULL_POINTER;
522
   }
523
#if defined(BOTAN_HAS_X509_CERTIFICATES)
524
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
525
      auto subject_info = c.subject_info(key);
526
      if(index < subject_info.size()) {
527
         // TODO(Botan4) change the type of out and remove this cast
528
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
529
      } else {
530
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
531
      }
532
   });
533
#else
534
   BOTAN_UNUSED(cert, key, index, out, out_len);
535
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
536
#endif
537
}
538

539
int botan_x509_cert_get_subject_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
540
#if defined(BOTAN_HAS_X509_CERTIFICATES)
541
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
542
      if(Botan::any_null_pointers(count)) {
543
         return BOTAN_FFI_ERROR_NULL_POINTER;
544
      }
545

546
      *count = c.subject_info(key).size();
547
      return BOTAN_FFI_SUCCESS;
548
   });
549
#else
550
   BOTAN_UNUSED(cert, key, count);
551
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
552
#endif
553
}
554

555
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
556
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
557
}
558

559
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
560
#if defined(BOTAN_HAS_X509_CERTIFICATES)
561
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
562
#else
563
   BOTAN_UNUSED(cert, ctx, view);
564
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
565
#endif
566
}
567

568
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
569
#if defined(BOTAN_HAS_X509_CERTIFICATES)
570
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
571
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
572
      if(c.allowed_usage(k)) {
573
         return BOTAN_FFI_SUCCESS;
574
      }
575
      return 1;
576
   });
577
#else
578
   BOTAN_UNUSED(cert, key_usage);
579
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
580
#endif
581
}
582

583
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
584
#if defined(BOTAN_HAS_X509_CERTIFICATES)
585
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
586
      if(Botan::any_null_pointers(oid)) {
587
         return BOTAN_FFI_ERROR_NULL_POINTER;
588
      }
589

590
      return c.has_ex_constraint(oid) ? 1 : 0;
591
   });
592
#else
593
   BOTAN_UNUSED(cert, oid);
594
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
595
#endif
596
}
597

598
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
599
#if defined(BOTAN_HAS_X509_CERTIFICATES)
600
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? 1 : 0; });
8✔
601
#else
602
   BOTAN_UNUSED(cert, oid);
603
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
604
#endif
605
}
606

607
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
38✔
608
#if defined(BOTAN_HAS_X509_CERTIFICATES)
609
   return BOTAN_FFI_CHECKED_DELETE(cert);
38✔
610
#else
611
   BOTAN_UNUSED(cert);
612
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
613
#endif
614
}
615

616
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
617
#if defined(BOTAN_HAS_X509_CERTIFICATES)
618
   return BOTAN_FFI_VISIT(cert,
6✔
619
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
620
#else
621
   BOTAN_UNUSED(cert, out, out_len);
622
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
623
#endif
624
}
625

626
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
627
#if defined(BOTAN_HAS_X509_CERTIFICATES)
628
   return BOTAN_FFI_VISIT(cert,
4✔
629
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
630
#else
631
   BOTAN_UNUSED(cert, out, out_len);
632
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
633
#endif
634
}
635

636
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
637
   if(time_since_epoch == nullptr) {
2✔
638
      return BOTAN_FFI_ERROR_NULL_POINTER;
639
   }
640
#if defined(BOTAN_HAS_X509_CERTIFICATES)
641
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
642
#else
643
   BOTAN_UNUSED(cert, time_since_epoch);
644
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
645
#endif
646
}
647

648
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
649
   if(time_since_epoch == nullptr) {
2✔
650
      return BOTAN_FFI_ERROR_NULL_POINTER;
651
   }
652
#if defined(BOTAN_HAS_X509_CERTIFICATES)
653
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
654
#else
655
   BOTAN_UNUSED(cert, time_since_epoch);
656
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
657
#endif
658
}
659

660
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
661
#if defined(BOTAN_HAS_X509_CERTIFICATES)
662
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
663
#else
664
   BOTAN_UNUSED(cert, out, out_len);
665
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
666
#endif
667
}
668

669
int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) {
1✔
670
#if defined(BOTAN_HAS_X509_CERTIFICATES)
671
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
2✔
672
      if(Botan::any_null_pointers(serial_number)) {
673
         return BOTAN_FFI_ERROR_NULL_POINTER;
674
      }
675

676
      auto serial_bn = Botan::BigInt::from_bytes(c.serial_number());
677
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
678
   });
679
#else
680
   BOTAN_UNUSED(cert, serial_number);
681
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
682
#endif
683
}
684

685
int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) {
3✔
686
   if(hash == nullptr) {
3✔
687
      return BOTAN_FFI_ERROR_NULL_POINTER;
688
   }
689
#if defined(BOTAN_HAS_X509_CERTIFICATES)
690
   // TODO(Botan4) change the type of out and remove this cast
691

692
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
693
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
694
   });
695
#else
696
   BOTAN_UNUSED(cert, hash, out, out_len);
697
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
698
#endif
699
}
700

701
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
702
#if defined(BOTAN_HAS_X509_CERTIFICATES)
703
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
704
#else
705
   BOTAN_UNUSED(cert, out, out_len);
706
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
707
#endif
708
}
709

710
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
711
#if defined(BOTAN_HAS_X509_CERTIFICATES)
712
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
713
#else
714
   BOTAN_UNUSED(cert, out, out_len);
715
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
716
#endif
717
}
718

719
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
720
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
721
}
722

723
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
724
#if defined(BOTAN_HAS_X509_CERTIFICATES)
725
   return BOTAN_FFI_VISIT(cert,
6✔
726
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
727
#else
728
   BOTAN_UNUSED(cert, ctx, view);
729
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
730
#endif
731
}
732

733
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
734
#if defined(BOTAN_HAS_X509_CERTIFICATES)
735
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
736
      if(Botan::any_null_pointers(type)) {
737
         return BOTAN_FFI_ERROR_NULL_POINTER;
738
      }
739

740
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
741
      if(!mapped_type.has_value()) {
742
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
743
      }
744

745
      *type = mapped_type.value();
746
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
747
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
748
      }
749

750
      return BOTAN_FFI_SUCCESS;
751
   });
752
#else
753
   BOTAN_UNUSED(name, type);
754
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
755
#endif
756
}
757

758
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
67✔
759
                                              botan_view_ctx ctx,
760
                                              botan_view_str_fn view) {
761
#if defined(BOTAN_HAS_X509_CERTIFICATES)
762
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
200✔
763
      const auto type = to_botan_x509_general_name_types(n.type_code());
764
      if(!type) {
765
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
766
      }
767

768
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
769
         type != BOTAN_X509_IP_ADDRESS) {
770
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
771
      }
772

773
      return invoke_view_callback(view, ctx, n.name());
774
   });
775
#else
776
   BOTAN_UNUSED(name, ctx, view);
777
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
778
#endif
779
}
780

781
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
782
                                              botan_view_ctx ctx,
783
                                              botan_view_bin_fn view) {
784
#if defined(BOTAN_HAS_X509_CERTIFICATES)
785
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
109✔
786
      const auto type = to_botan_x509_general_name_types(n.type_code());
787
      if(!type) {
788
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
789
      }
790

791
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
792
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
793
      }
794

795
      return invoke_view_callback(view, ctx, n.binary_name());
796
   });
797
#else
798
   BOTAN_UNUSED(name, ctx, view);
799
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
800
#endif
801
}
802

803
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
804
#if defined(BOTAN_HAS_X509_CERTIFICATES)
805
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
806
#else
807
   BOTAN_UNUSED(name);
808
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
809
#endif
810
}
811

812
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
813
                                               size_t index,
814
                                               botan_x509_general_name_t* constraint) {
815
#if defined(BOTAN_HAS_X509_CERTIFICATES)
816
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
817
      if(Botan::any_null_pointers(constraint)) {
818
         return BOTAN_FFI_ERROR_NULL_POINTER;
819
      }
820

821
      const auto& constraints = c.name_constraints().permitted();
822
      if(index >= constraints.size()) {
823
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
824
      }
825

826
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
827
   });
828
#else
829
   BOTAN_UNUSED(cert, index, constraint);
830
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
831
#endif
832
}
833

834
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
835
#if defined(BOTAN_HAS_X509_CERTIFICATES)
836
   if(Botan::any_null_pointers(count)) {
1✔
837
      return BOTAN_FFI_ERROR_NULL_POINTER;
838
   }
839

840
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
841
#else
842
   BOTAN_UNUSED(cert, count);
843
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
844
#endif
845
}
846

847
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
848
                                              size_t index,
849
                                              botan_x509_general_name_t* constraint) {
850
#if defined(BOTAN_HAS_X509_CERTIFICATES)
851
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
852
      if(Botan::any_null_pointers(constraint)) {
853
         return BOTAN_FFI_ERROR_NULL_POINTER;
854
      }
855

856
      const auto& constraints = c.name_constraints().excluded();
857
      if(index >= constraints.size()) {
858
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
859
      }
860

861
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
862
   });
863
#else
864
   BOTAN_UNUSED(cert, index, constraint);
865
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
866
#endif
867
}
868

869
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
870
#if defined(BOTAN_HAS_X509_CERTIFICATES)
871
   if(Botan::any_null_pointers(count)) {
1✔
872
      return BOTAN_FFI_ERROR_NULL_POINTER;
873
   }
874

875
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
876
#else
877
   BOTAN_UNUSED(cert, count);
878
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
879
#endif
880
}
881

882
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
883
                                              size_t index,
884
                                              botan_x509_general_name_t* alt_name) {
885
#if defined(BOTAN_HAS_X509_CERTIFICATES)
886
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
887
      if(Botan::any_null_pointers(alt_name)) {
888
         return BOTAN_FFI_ERROR_NULL_POINTER;
889
      }
890

891
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
892
         return BOTAN_FFI_ERROR_NO_VALUE;
893
      }
894

895
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
896
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
897
      }
898

899
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
900
   });
901
#else
902
   BOTAN_UNUSED(cert, index, alt_name);
903
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
904
#endif
905
}
906

907
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
908
#if defined(BOTAN_HAS_X509_CERTIFICATES)
909
   if(Botan::any_null_pointers(count)) {
6✔
910
      return BOTAN_FFI_ERROR_NULL_POINTER;
911
   }
912

913
   return BOTAN_FFI_VISIT(
12✔
914
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
915
#else
916
   BOTAN_UNUSED(cert, count);
917
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
918
#endif
919
}
920

921
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
922
                                             size_t index,
923
                                             botan_x509_general_name_t* alt_name) {
924
#if defined(BOTAN_HAS_X509_CERTIFICATES)
925
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
926
      if(Botan::any_null_pointers(alt_name)) {
927
         return BOTAN_FFI_ERROR_NULL_POINTER;
928
      }
929

930
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
931
         return BOTAN_FFI_ERROR_NO_VALUE;
932
      }
933

934
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
935
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
936
      }
937

938
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
939
   });
940
#else
941
   BOTAN_UNUSED(cert, index, alt_name);
942
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
943
#endif
944
}
945

946
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
947
#if defined(BOTAN_HAS_X509_CERTIFICATES)
948
   if(Botan::any_null_pointers(count)) {
6✔
949
      return BOTAN_FFI_ERROR_NULL_POINTER;
950
   }
951

952
   return BOTAN_FFI_VISIT(
12✔
953
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.issuer_alt_name()); });
954
#else
955
   BOTAN_UNUSED(cert, count);
956
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
957
#endif
958
}
959

960
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
961
   if(hostname == nullptr) {
6✔
962
      return BOTAN_FFI_ERROR_NULL_POINTER;
963
   }
964

965
#if defined(BOTAN_HAS_X509_CERTIFICATES)
966
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
967
#else
968
   BOTAN_UNUSED(cert);
969
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
970
#endif
971
}
972

973
int botan_x509_cert_verify(int* result_code,
4✔
974
                           botan_x509_cert_t cert,
975
                           const botan_x509_cert_t* intermediates,
976
                           size_t intermediates_len,
977
                           const botan_x509_cert_t* trusted,
978
                           size_t trusted_len,
979
                           const char* trusted_path,
980
                           size_t required_strength,
981
                           const char* hostname_cstr,
982
                           uint64_t reference_time) {
983
   if(required_strength == 0) {
4✔
984
      required_strength = 110;
3✔
985
   }
986

987
#if defined(BOTAN_HAS_X509_CERTIFICATES)
988
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
989
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
990
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
991
      const auto validation_time = reference_time == 0
4✔
992
                                      ? std::chrono::system_clock::now()
4✔
993
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
994

995
      std::vector<Botan::X509_Certificate> end_certs;
4✔
996
      end_certs.push_back(safe_get(cert));
4✔
997
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
998
         end_certs.push_back(safe_get(intermediates[i]));
5✔
999
      }
1000

1001
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
1002
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
1003
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
1004

1005
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
1006
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
1007
         trusted_roots.push_back(trusted_from_path.get());
×
1008
      }
1009

1010
      if(trusted_len > 0) {
4✔
1011
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
1012
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
1013
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
1014
         }
1015
         trusted_roots.push_back(trusted_extra.get());
4✔
1016
      }
1017

1018
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
1019

1020
      auto validation_result =
4✔
1021
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
1022

1023
      if(result_code != nullptr) {
4✔
1024
         *result_code = static_cast<int>(validation_result.result());
4✔
1025
      }
1026

1027
      if(validation_result.successful_validation()) {
4✔
1028
         return 0;
1029
      } else {
1030
         return 1;
3✔
1031
      }
1032
   });
4✔
1033
#else
1034
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1035
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
1036
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1037
#endif
1038
}
1039

1040
const char* botan_x509_cert_validation_status(int code) {
11✔
1041
   if(code < 0) {
11✔
1042
      return nullptr;
1043
   }
1044

1045
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1046
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
1047
   return Botan::to_string(sc);
11✔
1048
#else
1049
   return nullptr;
1050
#endif
1051
}
1052

1053
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
1054
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
1055
      return BOTAN_FFI_ERROR_NULL_POINTER;
1056
   }
1057

1058
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1059

1060
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
1061
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
1062
      return ffi_new_object(crl_obj, std::move(c));
14✔
1063
   });
14✔
1064

1065
#else
1066
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1067
#endif
1068
}
1069

1070
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
1071
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
1072
      return BOTAN_FFI_ERROR_NULL_POINTER;
1073
   }
1074

1075
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1076
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
1077
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
1078
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
1079
      return ffi_new_object(crl_obj, std::move(c));
1✔
1080
   });
3✔
1081
#else
1082
   BOTAN_UNUSED(crl_bits_len);
1083
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1084
#endif
1085
}
1086

1087
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
1088
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1089
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
1090
      if(Botan::any_null_pointers(time_since_epoch)) {
1091
         return BOTAN_FFI_ERROR_NULL_POINTER;
1092
      }
1093
      *time_since_epoch = c.this_update().time_since_epoch();
1094
      return BOTAN_FFI_SUCCESS;
1095
   });
1096
#else
1097
   BOTAN_UNUSED(crl, time_since_epoch);
1098
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1099
#endif
1100
}
1101

1102
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
5✔
1103
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1104
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
10✔
1105
      const auto& time = c.next_update();
1106
      if(!time.time_is_set()) {
1107
         return BOTAN_FFI_ERROR_NO_VALUE;
1108
      }
1109

1110
      if(Botan::any_null_pointers(time_since_epoch)) {
1111
         return BOTAN_FFI_ERROR_NULL_POINTER;
1112
      }
1113

1114
      *time_since_epoch = c.next_update().time_since_epoch();
1115
      return BOTAN_FFI_SUCCESS;
1116
   });
1117
#else
1118
   BOTAN_UNUSED(crl, time_since_epoch);
1119
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1120
#endif
1121
}
1122

1123
int botan_x509_crl_create(botan_x509_crl_t* crl_obj,
2✔
1124
                          botan_rng_t rng,
1125
                          botan_x509_cert_t ca_cert,
1126
                          botan_privkey_t ca_key,
1127
                          uint64_t issue_time,
1128
                          uint32_t next_update,
1129
                          const char* hash_fn,
1130
                          const char* padding) {
1131
   if(Botan::any_null_pointers(crl_obj)) {
2✔
1132
      return BOTAN_FFI_ERROR_NULL_POINTER;
1133
   }
1134
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1135
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
1136
      auto& rng_ = safe_get(rng);
2✔
1137
      auto ca = Botan::X509_CA(
2✔
1138
         safe_get(ca_cert), safe_get(ca_key), default_from_ptr(hash_fn), default_from_ptr(padding), rng_);
4✔
1139
      auto crl = std::make_unique<Botan::X509_CRL>(
2✔
1140
         ca.new_crl(rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
2✔
1141
      return ffi_new_object(crl_obj, std::move(crl));
4✔
1142
   });
4✔
1143
#else
1144
   BOTAN_UNUSED(rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update);
1145
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1146
#endif
1147
}
1148

1149
int botan_x509_crl_entry_create(botan_x509_crl_entry_t* entry, botan_x509_cert_t cert, int reason_code) {
2✔
1150
   if(Botan::any_null_pointers(entry)) {
2✔
1151
      return BOTAN_FFI_ERROR_NULL_POINTER;
1152
   }
1153
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1154
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
1155
      return ffi_new_object(
2✔
1156
         entry, std::make_unique<Botan::CRL_Entry>(safe_get(cert), static_cast<Botan::CRL_Code>(reason_code)));
4✔
1157
   });
2✔
1158
#else
1159
   BOTAN_UNUSED(cert, reason_code);
1160
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1161
#endif
1162
}
1163

1164
int botan_x509_crl_update(botan_x509_crl_t* crl_obj,
4✔
1165
                          botan_x509_crl_t last_crl,
1166
                          botan_rng_t rng,
1167
                          botan_x509_cert_t ca_cert,
1168
                          botan_privkey_t ca_key,
1169
                          uint64_t issue_time,
1170
                          uint32_t next_update,
1171
                          const botan_x509_crl_entry_t* new_entries,
1172
                          size_t new_entries_len,
1173
                          const char* hash_fn,
1174
                          const char* padding) {
1175
   if(Botan::any_null_pointers(crl_obj)) {
4✔
1176
      return BOTAN_FFI_ERROR_NULL_POINTER;
1177
   }
1178
   if(new_entries_len > 0 && Botan::any_null_pointers(new_entries)) {
4✔
1179
      return BOTAN_FFI_ERROR_NULL_POINTER;
1180
   }
1181
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1182
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
1183
      auto& rng_ = safe_get(rng);
3✔
1184
      auto ca = Botan::X509_CA(
3✔
1185
         safe_get(ca_cert), safe_get(ca_key), default_from_ptr(hash_fn), default_from_ptr(padding), rng_);
6✔
1186

1187
      std::vector<Botan::CRL_Entry> entries;
3✔
1188
      entries.reserve(new_entries_len);
3✔
1189
      for(size_t i = 0; i < new_entries_len; i++) {
5✔
1190
         entries.push_back(safe_get(new_entries[i]));
2✔
1191
      }
1192

1193
      auto crl = std::make_unique<Botan::X509_CRL>(ca.update_crl(
6✔
1194
         safe_get(last_crl), entries, rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
6✔
1195
      return ffi_new_object(crl_obj, std::move(crl));
6✔
1196
   });
6✔
1197
#else
1198
   BOTAN_UNUSED(
1199
      last_crl, rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update, new_entries, new_entries_len);
1200
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1201
#endif
1202
}
1203

1204
int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key) {
3✔
1205
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1206
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) -> int { return c.check_signature(safe_get(key)) ? 1 : 0; });
6✔
1207
#else
1208
   BOTAN_UNUSED(crl, key);
1209
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1210
#endif
1211
}
1212

1213
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
13✔
1214
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1215
   return BOTAN_FFI_CHECKED_DELETE(crl);
13✔
1216
#else
1217
   BOTAN_UNUSED(crl);
1218
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1219
#endif
1220
}
1221

1222
int botan_x509_crl_view_binary_values(botan_x509_crl_t crl_obj,
3✔
1223
                                      botan_x509_value_type value_type,
1224
                                      size_t index,
1225
                                      botan_view_ctx ctx,
1226
                                      botan_view_bin_fn view_fn) {
1227
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1228
   if(index != 0) {
3✔
1229
      // As of now there are no multi-value binary entries.
1230
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1231
   }
1232

1233
   auto view = [=](std::span<const uint8_t> value) -> int {
4✔
1234
      if(value.empty()) {
1✔
1235
         return BOTAN_FFI_ERROR_NO_VALUE;
1236
      } else {
1237
         return invoke_view_callback(view_fn, ctx, value);
1✔
1238
      }
1239
   };
3✔
1240

1241
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
12✔
1242
      switch(value_type) {
1243
         case BOTAN_X509_SERIAL_NUMBER:
1244
            return view(Botan::store_be(crl.crl_number()));
1245
         case BOTAN_X509_ISSUER_DN_BITS:
1246
            return view(Botan::ASN1::put_in_sequence(crl.issuer_dn().get_bits()));
1247
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1248
            return view(crl.authority_key_id());
1249

1250
         case BOTAN_X509_TBS_DATA_BITS:
1251
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1252
         case BOTAN_X509_SIGNATURE_BITS:
1253
         case BOTAN_X509_DER_ENCODING:
1254
            return botan_x509_object_view_value(crl, value_type, index, ctx, view_fn);
1255

1256
         case BOTAN_X509_SUBJECT_DN_BITS:
1257
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1258
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1259
         case BOTAN_X509_PEM_ENCODING:
1260
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1261
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1262
         case BOTAN_X509_CA_ISSUERS_URLS:
1263
            return BOTAN_FFI_ERROR_NO_VALUE;
1264
      }
1265

1266
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1267
   });
1268
#else
1269
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view_fn);
1270
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1271
#endif
1272
}
1273

1274
int botan_x509_crl_view_binary_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1275
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1276
   return enumerator_count_values(count, [=](size_t index) {
1✔
1277
      return botan_x509_crl_view_binary_values(
1✔
1278
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1279
   });
1✔
1280
#else
1281
   BOTAN_UNUSED(crl_obj, value_type, count);
1282
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1283
#endif
1284
}
1285

1286
int botan_x509_crl_view_string_values(botan_x509_crl_t crl_obj,
3✔
1287
                                      botan_x509_value_type value_type,
1288
                                      size_t index,
1289
                                      botan_view_ctx ctx,
1290
                                      botan_view_str_fn view) {
1291
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1292
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
6✔
1293
      switch(value_type) {
1294
         case BOTAN_X509_PEM_ENCODING:
1295
            return botan_x509_object_view_value(crl, value_type, index, ctx, view);
1296

1297
         case BOTAN_X509_SERIAL_NUMBER:
1298
         case BOTAN_X509_SUBJECT_DN_BITS:
1299
         case BOTAN_X509_ISSUER_DN_BITS:
1300
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1301
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1302
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1303
         case BOTAN_X509_TBS_DATA_BITS:
1304
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1305
         case BOTAN_X509_SIGNATURE_BITS:
1306
         case BOTAN_X509_DER_ENCODING:
1307
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1308
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1309
         case BOTAN_X509_CA_ISSUERS_URLS:
1310
            return BOTAN_FFI_ERROR_NO_VALUE;
1311
      }
1312

1313
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1314
   });
1315
#else
1316
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view);
1317
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1318
#endif
1319
}
1320

1321
int botan_x509_crl_view_string_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1322
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1323
   return enumerator_count_values(count, [=](size_t index) {
1✔
1324
      return botan_x509_crl_view_string_values(
2✔
1325
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1326
   });
1✔
1327
#else
1328
   BOTAN_UNUSED(crl_obj, value_type, count);
1329
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1330
#endif
1331
}
1332

1333
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
1334
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1335
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
1336
#else
1337
   BOTAN_UNUSED(cert);
1338
   BOTAN_UNUSED(crl);
1339
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1340
#endif
1341
}
1342

1343
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
8✔
1344
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1345
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
16✔
1346
      const auto& entries = c.get_revoked();
1347
      if(index >= entries.size()) {
1348
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1349
      }
1350

1351
      if(Botan::any_null_pointers(entry)) {
1352
         return BOTAN_FFI_ERROR_NULL_POINTER;
1353
      }
1354

1355
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
1356
   });
1357
#else
1358
   BOTAN_UNUSED(crl, index, entry);
1359
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1360
#endif
1361
}
1362

1363
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
4✔
1364
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1365
   if(Botan::any_null_pointers(count)) {
4✔
1366
      return BOTAN_FFI_ERROR_NULL_POINTER;
1367
   }
1368

1369
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
8✔
1370
#else
1371
   BOTAN_UNUSED(crl, count);
1372
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1373
#endif
1374
}
1375

1376
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
6✔
1377
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1378
   return BOTAN_FFI_CHECKED_DELETE(entry);
6✔
1379
#else
1380
   BOTAN_UNUSED(entry);
1381
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1382
#endif
1383
}
1384

1385
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
3✔
1386
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1387
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1388
      if(Botan::any_null_pointers(reason_code)) {
1389
         return BOTAN_FFI_ERROR_NULL_POINTER;
1390
      }
1391

1392
      *reason_code = static_cast<int>(e.reason_code());
1393
      return BOTAN_FFI_SUCCESS;
1394
   });
1395
#else
1396
   BOTAN_UNUSED(entry, reason_code);
1397
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1398
#endif
1399
}
1400

1401
int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) {
3✔
1402
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1403
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1404
      if(Botan::any_null_pointers(serial_number)) {
1405
         return BOTAN_FFI_ERROR_NULL_POINTER;
1406
      }
1407

1408
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
1409
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
1410
   });
1411
#else
1412
   BOTAN_UNUSED(entry, serial_number);
1413
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1414
#endif
1415
}
1416

1417
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
1418
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1419
   return BOTAN_FFI_VISIT(
2✔
1420
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
1421
#else
1422
   BOTAN_UNUSED(entry, ctx, view);
1423
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1424
#endif
1425
}
1426

1427
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
3✔
1428
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1429
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1430
      if(Botan::any_null_pointers(time_since_epoch)) {
1431
         return BOTAN_FFI_ERROR_NULL_POINTER;
1432
      }
1433

1434
      *time_since_epoch = e.expire_time().time_since_epoch();
1435
      return BOTAN_FFI_SUCCESS;
1436
   });
1437
#else
1438
   BOTAN_UNUSED(entry, time_since_epoch);
1439
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1440
#endif
1441
}
1442

1443
int botan_x509_cert_verify_with_crl(int* result_code,
20✔
1444
                                    botan_x509_cert_t cert,
1445
                                    const botan_x509_cert_t* intermediates,
1446
                                    size_t intermediates_len,
1447
                                    const botan_x509_cert_t* trusted,
1448
                                    size_t trusted_len,
1449
                                    const botan_x509_crl_t* crls,
1450
                                    size_t crls_len,
1451
                                    const char* trusted_path,
1452
                                    size_t required_strength,
1453
                                    const char* hostname_cstr,
1454
                                    uint64_t reference_time) {
1455
   if(required_strength == 0) {
20✔
1456
      required_strength = 110;
10✔
1457
   }
1458

1459
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1460
   return ffi_guard_thunk(__func__, [=]() -> int {
20✔
1461
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
22✔
1462
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
20✔
1463
      const auto validation_time = reference_time == 0
20✔
1464
                                      ? std::chrono::system_clock::now()
20✔
1465
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1466

1467
      std::vector<Botan::X509_Certificate> end_certs;
20✔
1468
      end_certs.push_back(safe_get(cert));
20✔
1469
      for(size_t i = 0; i != intermediates_len; ++i) {
38✔
1470
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1471
      }
1472

1473
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
20✔
1474
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
20✔
1475
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
20✔
1476
      std::vector<Botan::Certificate_Store*> trusted_roots;
20✔
1477

1478
      if(trusted_path != nullptr && *trusted_path != 0) {
20✔
1479
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1480
         trusted_roots.push_back(trusted_from_path.get());
2✔
1481
      }
1482

1483
      if(trusted_len > 0) {
20✔
1484
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
34✔
1485
         for(size_t i = 0; i != trusted_len; ++i) {
34✔
1486
            trusted_extra->add_certificate(safe_get(trusted[i]));
17✔
1487
         }
1488
         trusted_roots.push_back(trusted_extra.get());
17✔
1489
      }
1490

1491
      if(crls_len > 0) {
20✔
1492
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
26✔
1493
         for(size_t i = 0; i != crls_len; ++i) {
29✔
1494
            trusted_crls->add_crl(safe_get(crls[i]));
16✔
1495
         }
1496
         trusted_roots.push_back(trusted_crls.get());
13✔
1497
      }
1498

1499
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
40✔
1500

1501
      auto validation_result =
20✔
1502
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
20✔
1503

1504
      if(result_code != nullptr) {
20✔
1505
         *result_code = static_cast<int>(validation_result.result());
20✔
1506
      }
1507

1508
      if(validation_result.successful_validation()) {
20✔
1509
         return 0;
1510
      } else {
1511
         return 1;
10✔
1512
      }
1513
   });
22✔
1514
#else
1515
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1516
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1517
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1518
#endif
1519
}
1520
}
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