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

randombit / botan / 24063525848

06 Apr 2026 10:36PM UTC coverage: 89.448% (-0.007%) from 89.455%
24063525848

push

github

web-flow
Merge pull request #5521 from randombit/jack/fix-rollup

Rollup of small fixes

105878 of 118368 relevant lines covered (89.45%)

11475460.89 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/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

78
   return std::nullopt;
12✔
79
}
80

81
/**
82
 * Counts the total number of GeneralNames contained in the given
83
 * AlternativeName @p alt_names.
84
 *
85
 * NOTE: if the set of alternative name types handled here is extended,
86
 *       extract_general_name_at() must be updated accordingly!
87
 */
88
size_t count_general_names_in(const Botan::AlternativeName& alt_names) {
12✔
89
   return alt_names.email().size() + alt_names.dns().size() + alt_names.directory_names().size() +
12✔
90
          alt_names.uris().size() + alt_names.ipv4_address().size();
12✔
91
}
92

93
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
301✔
94
   using Type = Botan::GeneralName::NameType;
301✔
95
   switch(gn_type) {
301✔
96
      case Type::Unknown:
1✔
97
         return std::nullopt;
1✔
98
      case Type::RFC822:
83✔
99
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
100
      case Type::DNS:
73✔
101
         return BOTAN_X509_DNS_NAME;
73✔
102
      case Type::URI:
28✔
103
         return BOTAN_X509_URI;
28✔
104
      case Type::DN:
95✔
105
         return BOTAN_X509_DIRECTORY_NAME;
95✔
106
      case Type::IPv4:
21✔
107
         return BOTAN_X509_IP_ADDRESS;
21✔
108
      case Type::Other:
×
109
         return BOTAN_X509_OTHER_NAME;
×
110
   }
111

112
   BOTAN_ASSERT_UNREACHABLE();
×
113
}
114

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

129
   *count = 0;
11✔
130
   for(;; ++(*count)) {
12✔
131
      const auto rc = fn(*count);
46✔
132
      switch(rc) {
23✔
133
         case BOTAN_FFI_ERROR_NO_VALUE:
134
         case BOTAN_FFI_ERROR_OUT_OF_RANGE:
135
            // hit the end of the enumeration
136
            return BOTAN_FFI_SUCCESS;
137
         case BOTAN_FFI_SUCCESS:
138
            // got a value, continue counting
139
            break;
140
         default:
141
            // unexpected error from enumerator function
142
            return rc;
143
      }
144
   }
145
}
146

147
std::chrono::system_clock::time_point timepoint_from_timestamp(uint64_t time_since_epoch) {
5✔
148
   return std::chrono::system_clock::time_point(std::chrono::seconds(time_since_epoch));
5✔
149
}
150

151
std::string default_from_ptr(const char* value) {
10✔
152
   std::string ret;
10✔
153
   if(value != nullptr) {
10✔
154
      ret = value;
×
155
   }
156
   return ret;
10✔
157
}
×
158

159
}  // namespace
160

161
}  // namespace Botan_FFI
162

163
#endif
164

165
extern "C" {
166

167
using namespace Botan_FFI;
168

169
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
37✔
170
   if(cert_obj == nullptr || cert_path == nullptr) {
37✔
171
      return BOTAN_FFI_ERROR_NULL_POINTER;
172
   }
173

174
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
175

176
   return ffi_guard_thunk(__func__, [=]() -> int {
37✔
177
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
37✔
178
      return ffi_new_object(cert_obj, std::move(c));
37✔
179
   });
74✔
180

181
#else
182
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
183
#endif
184
}
185

186
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
187
   if(cert_obj == nullptr) {
1✔
188
      return BOTAN_FFI_ERROR_NULL_POINTER;
189
   }
190

191
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
192

193
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
194
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
195
      return ffi_new_object(cert_obj, std::move(c));
1✔
196
   });
2✔
197

198
#else
199
   BOTAN_UNUSED(cert);
200
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
201
#endif
202
}
203

204
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
205
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
206
      return BOTAN_FFI_ERROR_NULL_POINTER;
207
   }
208

209
#if defined(BOTAN_HAS_X509_CERTIFICATES)
210
   return ffi_guard_thunk(__func__, [=]() -> int {
×
211
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
212
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
213
      return ffi_new_object(cert_obj, std::move(c));
×
214
   });
×
215
#else
216
   BOTAN_UNUSED(cert_bits_len);
217
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
218
#endif
219
}
220
}
221

222
namespace {
223

224
#if defined(BOTAN_HAS_X509_CERTIFICATES)
225

226
int botan_x509_object_view_value(const Botan::X509_Object& object,
6✔
227
                                 botan_x509_value_type value_type,
228
                                 size_t index,
229
                                 botan_view_ctx ctx,
230
                                 botan_view_str_fn view_fn) {
231
   if(index != 0) {
6✔
232
      // As of now there are no multi-value generic string entries.
233
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
234
   }
235

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

238
   switch(value_type) {
4✔
239
      case BOTAN_X509_PEM_ENCODING:
4✔
240
         return view(object.PEM_encode());
8✔
241
      default:
×
242
         BOTAN_ASSERT_UNREACHABLE(); /* called with unexpected (non-generic) value_type */
×
243
   }
244
}
245

246
int botan_x509_object_view_value(const Botan::X509_Object& object,
8✔
247
                                 botan_x509_value_type value_type,
248
                                 size_t index,
249
                                 botan_view_ctx ctx,
250
                                 botan_view_bin_fn view_fn) {
251
   if(index != 0) {
8✔
252
      // As of now there are no multi-value generic binary entries.
253
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
254
   }
255

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

258
   switch(value_type) {
8✔
259
      case BOTAN_X509_TBS_DATA_BITS:
2✔
260
         return view(object.tbs_data());
4✔
261
      case BOTAN_X509_SIGNATURE_SCHEME_BITS:
2✔
262
         return view(object.signature_algorithm().BER_encode());
4✔
263
      case BOTAN_X509_SIGNATURE_BITS:
2✔
264
         return view(object.signature());
10✔
265
      case BOTAN_X509_DER_ENCODING:
2✔
266
         return view(object.BER_encode());
4✔
267
      default:
×
268
         BOTAN_ASSERT_UNREACHABLE(); /* called with unexpected (non-generic) value_type */
×
269
   }
270
}
271

272
#endif
273

274
}  // namespace
275

276
extern "C" {
277

278
int botan_x509_cert_view_binary_values(botan_x509_cert_t cert,
22✔
279
                                       botan_x509_value_type value_type,
280
                                       size_t index,
281
                                       botan_view_ctx ctx,
282
                                       botan_view_bin_fn view_fn) {
283
#if defined(BOTAN_HAS_X509_CERTIFICATES)
284
   if(index != 0) {
22✔
285
      // As of now there are no multi-value binary entries.
286
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
287
   }
288

289
   auto view = [=](std::span<const uint8_t> value) -> int {
18✔
290
      if(value.empty()) {
5✔
291
         return BOTAN_FFI_ERROR_NO_VALUE;
292
      } else {
293
         return invoke_view_callback(view_fn, ctx, value);
4✔
294
      }
295
   };
13✔
296

297
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
39✔
298
      switch(value_type) {
299
         case BOTAN_X509_SERIAL_NUMBER:
300
            return view(c.serial_number());
301
         case BOTAN_X509_SUBJECT_DN_BITS:
302
            return view(c.raw_subject_dn());
303
         case BOTAN_X509_ISSUER_DN_BITS:
304
            return view(c.raw_issuer_dn());
305
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
306
            return view(c.subject_key_id());
307
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
308
            return view(c.authority_key_id());
309
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
310
            return view(c.subject_public_key_info());
311

312
         case BOTAN_X509_TBS_DATA_BITS:
313
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
314
         case BOTAN_X509_SIGNATURE_BITS:
315
         case BOTAN_X509_DER_ENCODING:
316
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
317

318
         case BOTAN_X509_PEM_ENCODING:
319
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
320
         case BOTAN_X509_OCSP_RESPONDER_URLS:
321
         case BOTAN_X509_CA_ISSUERS_URLS:
322
            return BOTAN_FFI_ERROR_NO_VALUE;
323
      }
324

325
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
326
   });
327
#else
328
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
329
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
330
#endif
331
}
332

333
int botan_x509_cert_view_binary_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
5✔
334
#if defined(BOTAN_HAS_X509_CERTIFICATES)
335
   return enumerator_count_values(count, [=](size_t index) {
5✔
336
      return botan_x509_cert_view_binary_values(
10✔
337
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
338
   });
5✔
339
#else
340
   BOTAN_UNUSED(cert, value_type, count);
341
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
342
#endif
343
}
344

345
int botan_x509_cert_view_string_values(botan_x509_cert_t cert,
19✔
346
                                       botan_x509_value_type value_type,
347
                                       size_t index,
348
                                       botan_view_ctx ctx,
349
                                       botan_view_str_fn view_fn) {
350
#if defined(BOTAN_HAS_X509_CERTIFICATES)
351
   auto enumerate = [view_fn, ctx](auto values, size_t idx) -> int {
10✔
352
      if(idx >= values.size()) {
10✔
353
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
354
      } else {
355
         return invoke_view_callback(view_fn, ctx, values[idx]);
6✔
356
      }
357
   };
19✔
358

359
   auto enumerate_crl_distribution_points = [view_fn, ctx](const Botan::X509_Certificate& c, size_t idx) -> int {
25✔
360
      const auto* crl_dp_ext =
6✔
361
         c.v3_extensions().get_extension_object_as<Botan::Cert_Extension::CRL_Distribution_Points>();
12✔
362
      if(crl_dp_ext == nullptr) {
6✔
363
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;  // essentially an empty list
364
      }
365

366
      const auto& dps = crl_dp_ext->distribution_points();
5✔
367
      for(size_t i = idx; const auto& dp : dps) {
6✔
368
         const auto& uris = dp.point().uris();
5✔
369
         if(i >= uris.size()) {
5✔
370
            i -= uris.size();
1✔
371
            continue;
1✔
372
         }
373

374
         auto itr = uris.begin();
4✔
375
         std::advance(itr, i);
4✔
376
         return invoke_view_callback(view_fn, ctx, *itr);
8✔
377
      }
378

379
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
380
   };
19✔
381

382
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
38✔
383
      switch(value_type) {
384
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
385
            return enumerate_crl_distribution_points(c, index);
386
         case BOTAN_X509_OCSP_RESPONDER_URLS:
387
            return enumerate(c.ocsp_responders(), index);
388
         case BOTAN_X509_CA_ISSUERS_URLS:
389
            return enumerate(c.ca_issuers(), index);
390
         case BOTAN_X509_PEM_ENCODING:
391
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
392

393
         case BOTAN_X509_SERIAL_NUMBER:
394
         case BOTAN_X509_SUBJECT_DN_BITS:
395
         case BOTAN_X509_ISSUER_DN_BITS:
396
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
397
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
398
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
399
         case BOTAN_X509_TBS_DATA_BITS:
400
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
401
         case BOTAN_X509_SIGNATURE_BITS:
402
         case BOTAN_X509_DER_ENCODING:
403
            return BOTAN_FFI_ERROR_NO_VALUE;
404
      }
405

406
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
407
   });
408
#else
409
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
410
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
411
#endif
412
}
413

414
int botan_x509_cert_view_string_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
4✔
415
#if defined(BOTAN_HAS_X509_CERTIFICATES)
416
   return enumerator_count_values(count, [=](size_t index) {
4✔
417
      return botan_x509_cert_view_string_values(
10✔
418
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
419
   });
4✔
420
#else
421
   BOTAN_UNUSED(cert, value_type, count);
422
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
423
#endif
424
}
425

426
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
427
#if defined(BOTAN_HAS_X509_CERTIFICATES)
428
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? 1 : 0; });
4✔
429
#else
430
   BOTAN_UNUSED(cert);
431
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
432
#endif
433
}
434

435
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
436
#if defined(BOTAN_HAS_X509_CERTIFICATES)
437
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
438
      if(Botan::any_null_pointers(path_limit)) {
439
         return BOTAN_FFI_ERROR_NULL_POINTER;
440
      }
441

442
      if(const auto path_len = c.path_length_constraint()) {
443
         *path_limit = path_len.value();
444
         return BOTAN_FFI_SUCCESS;
445
      } else {
446
         return BOTAN_FFI_ERROR_NO_VALUE;
447
      }
448
   });
449
#else
450
   BOTAN_UNUSED(cert, path_limit);
451
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
452
#endif
453
}
454

455
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
456
   if(key == nullptr) {
2✔
457
      return BOTAN_FFI_ERROR_NULL_POINTER;
458
   }
459

460
   *key = nullptr;
2✔
461

462
#if defined(BOTAN_HAS_X509_CERTIFICATES)
463
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
464
      auto public_key = safe_get(cert).subject_public_key();
2✔
465
      return ffi_new_object(key, std::move(public_key));
2✔
466
   });
4✔
467
#else
468
   BOTAN_UNUSED(cert);
469
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
470
#endif
471
}
472

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

494
int botan_x509_cert_get_issuer_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
495
#if defined(BOTAN_HAS_X509_CERTIFICATES)
496
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
497
      if(Botan::any_null_pointers(count)) {
498
         return BOTAN_FFI_ERROR_NULL_POINTER;
499
      }
500

501
      *count = c.issuer_info(key).size();
502
      return BOTAN_FFI_SUCCESS;
503
   });
504
#else
505
   BOTAN_UNUSED(cert, key, count);
506
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
507
#endif
508
}
509

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

531
int botan_x509_cert_get_subject_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
532
#if defined(BOTAN_HAS_X509_CERTIFICATES)
533
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
534
      if(Botan::any_null_pointers(count)) {
535
         return BOTAN_FFI_ERROR_NULL_POINTER;
536
      }
537

538
      *count = c.subject_info(key).size();
539
      return BOTAN_FFI_SUCCESS;
540
   });
541
#else
542
   BOTAN_UNUSED(cert, key, count);
543
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
544
#endif
545
}
546

547
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
548
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
549
}
550

551
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
552
#if defined(BOTAN_HAS_X509_CERTIFICATES)
553
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
554
#else
555
   BOTAN_UNUSED(cert, ctx, view);
556
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
557
#endif
558
}
559

560
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
561
#if defined(BOTAN_HAS_X509_CERTIFICATES)
562
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
563
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
564
      if(c.allowed_usage(k)) {
565
         return BOTAN_FFI_SUCCESS;
566
      }
567
      return 1;
568
   });
569
#else
570
   BOTAN_UNUSED(cert, key_usage);
571
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
572
#endif
573
}
574

575
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
576
#if defined(BOTAN_HAS_X509_CERTIFICATES)
577
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
578
      if(Botan::any_null_pointers(oid)) {
579
         return BOTAN_FFI_ERROR_NULL_POINTER;
580
      }
581

582
      return c.has_ex_constraint(oid) ? 1 : 0;
583
   });
584
#else
585
   BOTAN_UNUSED(cert, oid);
586
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
587
#endif
588
}
589

590
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
591
#if defined(BOTAN_HAS_X509_CERTIFICATES)
592
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? 1 : 0; });
8✔
593
#else
594
   BOTAN_UNUSED(cert, oid);
595
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
596
#endif
597
}
598

599
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
38✔
600
#if defined(BOTAN_HAS_X509_CERTIFICATES)
601
   return BOTAN_FFI_CHECKED_DELETE(cert);
38✔
602
#else
603
   BOTAN_UNUSED(cert);
604
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
605
#endif
606
}
607

608
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
609
#if defined(BOTAN_HAS_X509_CERTIFICATES)
610
   return BOTAN_FFI_VISIT(cert,
6✔
611
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
612
#else
613
   BOTAN_UNUSED(cert, out, out_len);
614
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
615
#endif
616
}
617

618
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
619
#if defined(BOTAN_HAS_X509_CERTIFICATES)
620
   return BOTAN_FFI_VISIT(cert,
4✔
621
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
622
#else
623
   BOTAN_UNUSED(cert, out, out_len);
624
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
625
#endif
626
}
627

628
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
629
   if(time_since_epoch == nullptr) {
2✔
630
      return BOTAN_FFI_ERROR_NULL_POINTER;
631
   }
632
#if defined(BOTAN_HAS_X509_CERTIFICATES)
633
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
634
#else
635
   BOTAN_UNUSED(cert, time_since_epoch);
636
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
637
#endif
638
}
639

640
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
641
   if(time_since_epoch == nullptr) {
2✔
642
      return BOTAN_FFI_ERROR_NULL_POINTER;
643
   }
644
#if defined(BOTAN_HAS_X509_CERTIFICATES)
645
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
646
#else
647
   BOTAN_UNUSED(cert, time_since_epoch);
648
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
649
#endif
650
}
651

652
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
653
#if defined(BOTAN_HAS_X509_CERTIFICATES)
654
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
655
#else
656
   BOTAN_UNUSED(cert, out, out_len);
657
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
658
#endif
659
}
660

661
int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) {
1✔
662
#if defined(BOTAN_HAS_X509_CERTIFICATES)
663
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
2✔
664
      if(Botan::any_null_pointers(serial_number)) {
665
         return BOTAN_FFI_ERROR_NULL_POINTER;
666
      }
667

668
      auto serial_bn = Botan::BigInt::from_bytes(c.serial_number());
669
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
670
   });
671
#else
672
   BOTAN_UNUSED(cert, serial_number);
673
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
674
#endif
675
}
676

677
int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) {
3✔
678
   if(hash == nullptr) {
3✔
679
      return BOTAN_FFI_ERROR_NULL_POINTER;
680
   }
681
#if defined(BOTAN_HAS_X509_CERTIFICATES)
682
   // TODO(Botan4) change the type of out and remove this cast
683

684
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
685
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
686
   });
687
#else
688
   BOTAN_UNUSED(cert, hash, out, out_len);
689
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
690
#endif
691
}
692

693
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
694
#if defined(BOTAN_HAS_X509_CERTIFICATES)
695
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
696
#else
697
   BOTAN_UNUSED(cert, out, out_len);
698
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
699
#endif
700
}
701

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

711
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
712
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
713
}
714

715
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
716
#if defined(BOTAN_HAS_X509_CERTIFICATES)
717
   return BOTAN_FFI_VISIT(cert,
6✔
718
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
719
#else
720
   BOTAN_UNUSED(cert, ctx, view);
721
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
722
#endif
723
}
724

725
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
726
#if defined(BOTAN_HAS_X509_CERTIFICATES)
727
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
728
      if(Botan::any_null_pointers(type)) {
729
         return BOTAN_FFI_ERROR_NULL_POINTER;
730
      }
731

732
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
733
      if(!mapped_type.has_value()) {
734
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
735
      }
736

737
      *type = mapped_type.value();
738
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
739
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
740
      }
741

742
      return BOTAN_FFI_SUCCESS;
743
   });
744
#else
745
   BOTAN_UNUSED(name, type);
746
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
747
#endif
748
}
749

750
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
751
                                              botan_view_ctx ctx,
752
                                              botan_view_str_fn view) {
753
#if defined(BOTAN_HAS_X509_CERTIFICATES)
754
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
755
      const auto type = to_botan_x509_general_name_types(n.type_code());
756
      if(!type) {
757
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
758
      }
759

760
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
761
         type != BOTAN_X509_IP_ADDRESS) {
762
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
763
      }
764

765
      return invoke_view_callback(view, ctx, n.name());
766
   });
767
#else
768
   BOTAN_UNUSED(name, ctx, view);
769
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
770
#endif
771
}
772

773
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
774
                                              botan_view_ctx ctx,
775
                                              botan_view_bin_fn view) {
776
#if defined(BOTAN_HAS_X509_CERTIFICATES)
777
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
109✔
778
      const auto type = to_botan_x509_general_name_types(n.type_code());
779
      if(!type) {
780
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
781
      }
782

783
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
784
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
785
      }
786

787
      return invoke_view_callback(view, ctx, n.binary_name());
788
   });
789
#else
790
   BOTAN_UNUSED(name, ctx, view);
791
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
792
#endif
793
}
794

795
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
796
#if defined(BOTAN_HAS_X509_CERTIFICATES)
797
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
798
#else
799
   BOTAN_UNUSED(name);
800
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
801
#endif
802
}
803

804
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
805
                                               size_t index,
806
                                               botan_x509_general_name_t* constraint) {
807
#if defined(BOTAN_HAS_X509_CERTIFICATES)
808
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
809
      if(Botan::any_null_pointers(constraint)) {
810
         return BOTAN_FFI_ERROR_NULL_POINTER;
811
      }
812

813
      const auto& constraints = c.name_constraints().permitted();
814
      if(index >= constraints.size()) {
815
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
816
      }
817

818
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
819
   });
820
#else
821
   BOTAN_UNUSED(cert, index, constraint);
822
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
823
#endif
824
}
825

826
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
827
#if defined(BOTAN_HAS_X509_CERTIFICATES)
828
   if(Botan::any_null_pointers(count)) {
1✔
829
      return BOTAN_FFI_ERROR_NULL_POINTER;
830
   }
831

832
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
833
#else
834
   BOTAN_UNUSED(cert, count);
835
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
836
#endif
837
}
838

839
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
840
                                              size_t index,
841
                                              botan_x509_general_name_t* constraint) {
842
#if defined(BOTAN_HAS_X509_CERTIFICATES)
843
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
844
      if(Botan::any_null_pointers(constraint)) {
845
         return BOTAN_FFI_ERROR_NULL_POINTER;
846
      }
847

848
      const auto& constraints = c.name_constraints().excluded();
849
      if(index >= constraints.size()) {
850
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
851
      }
852

853
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
854
   });
855
#else
856
   BOTAN_UNUSED(cert, index, constraint);
857
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
858
#endif
859
}
860

861
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
862
#if defined(BOTAN_HAS_X509_CERTIFICATES)
863
   if(Botan::any_null_pointers(count)) {
1✔
864
      return BOTAN_FFI_ERROR_NULL_POINTER;
865
   }
866

867
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
868
#else
869
   BOTAN_UNUSED(cert, count);
870
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
871
#endif
872
}
873

874
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
875
                                              size_t index,
876
                                              botan_x509_general_name_t* alt_name) {
877
#if defined(BOTAN_HAS_X509_CERTIFICATES)
878
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
879
      if(Botan::any_null_pointers(alt_name)) {
880
         return BOTAN_FFI_ERROR_NULL_POINTER;
881
      }
882

883
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
884
         return BOTAN_FFI_ERROR_NO_VALUE;
885
      }
886

887
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
888
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
889
      }
890

891
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
892
   });
893
#else
894
   BOTAN_UNUSED(cert, index, alt_name);
895
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
896
#endif
897
}
898

899
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
900
#if defined(BOTAN_HAS_X509_CERTIFICATES)
901
   if(Botan::any_null_pointers(count)) {
6✔
902
      return BOTAN_FFI_ERROR_NULL_POINTER;
903
   }
904

905
   return BOTAN_FFI_VISIT(
12✔
906
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
907
#else
908
   BOTAN_UNUSED(cert, count);
909
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
910
#endif
911
}
912

913
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
914
                                             size_t index,
915
                                             botan_x509_general_name_t* alt_name) {
916
#if defined(BOTAN_HAS_X509_CERTIFICATES)
917
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
918
      if(Botan::any_null_pointers(alt_name)) {
919
         return BOTAN_FFI_ERROR_NULL_POINTER;
920
      }
921

922
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
923
         return BOTAN_FFI_ERROR_NO_VALUE;
924
      }
925

926
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
927
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
928
      }
929

930
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
931
   });
932
#else
933
   BOTAN_UNUSED(cert, index, alt_name);
934
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
935
#endif
936
}
937

938
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
939
#if defined(BOTAN_HAS_X509_CERTIFICATES)
940
   if(Botan::any_null_pointers(count)) {
6✔
941
      return BOTAN_FFI_ERROR_NULL_POINTER;
942
   }
943

944
   return BOTAN_FFI_VISIT(
12✔
945
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.issuer_alt_name()); });
946
#else
947
   BOTAN_UNUSED(cert, count);
948
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
949
#endif
950
}
951

952
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
953
   if(hostname == nullptr) {
6✔
954
      return BOTAN_FFI_ERROR_NULL_POINTER;
955
   }
956

957
#if defined(BOTAN_HAS_X509_CERTIFICATES)
958
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
959
#else
960
   BOTAN_UNUSED(cert);
961
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
962
#endif
963
}
964

965
int botan_x509_cert_verify(int* result_code,
4✔
966
                           botan_x509_cert_t cert,
967
                           const botan_x509_cert_t* intermediates,
968
                           size_t intermediates_len,
969
                           const botan_x509_cert_t* trusted,
970
                           size_t trusted_len,
971
                           const char* trusted_path,
972
                           size_t required_strength,
973
                           const char* hostname_cstr,
974
                           uint64_t reference_time) {
975
   if(required_strength == 0) {
4✔
976
      required_strength = 110;
3✔
977
   }
978

979
#if defined(BOTAN_HAS_X509_CERTIFICATES)
980
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
981
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
982
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
983
      const auto validation_time = reference_time == 0
4✔
984
                                      ? std::chrono::system_clock::now()
4✔
985
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
986

987
      std::vector<Botan::X509_Certificate> end_certs;
4✔
988
      end_certs.push_back(safe_get(cert));
4✔
989
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
990
         end_certs.push_back(safe_get(intermediates[i]));
5✔
991
      }
992

993
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
994
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
995
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
996

997
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
998
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
999
         trusted_roots.push_back(trusted_from_path.get());
×
1000
      }
1001

1002
      if(trusted_len > 0) {
4✔
1003
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
1004
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
1005
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
1006
         }
1007
         trusted_roots.push_back(trusted_extra.get());
4✔
1008
      }
1009

1010
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
1011

1012
      auto validation_result =
4✔
1013
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
1014

1015
      if(result_code != nullptr) {
4✔
1016
         *result_code = static_cast<int>(validation_result.result());
4✔
1017
      }
1018

1019
      if(validation_result.successful_validation()) {
4✔
1020
         return 0;
1021
      } else {
1022
         return 1;
3✔
1023
      }
1024
   });
4✔
1025
#else
1026
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1027
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
1028
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1029
#endif
1030
}
1031

1032
const char* botan_x509_cert_validation_status(int code) {
11✔
1033
   if(code < 0) {
11✔
1034
      return nullptr;
1035
   }
1036

1037
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1038
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
1039
   return Botan::to_string(sc);
11✔
1040
#else
1041
   return nullptr;
1042
#endif
1043
}
1044

1045
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
1046
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
1047
      return BOTAN_FFI_ERROR_NULL_POINTER;
1048
   }
1049

1050
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1051

1052
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
1053
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
1054
      return ffi_new_object(crl_obj, std::move(c));
14✔
1055
   });
14✔
1056

1057
#else
1058
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1059
#endif
1060
}
1061

1062
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
1063
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
1064
      return BOTAN_FFI_ERROR_NULL_POINTER;
1065
   }
1066

1067
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1068
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
1069
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
1070
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
1071
      return ffi_new_object(crl_obj, std::move(c));
1✔
1072
   });
3✔
1073
#else
1074
   BOTAN_UNUSED(crl_bits_len);
1075
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1076
#endif
1077
}
1078

1079
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
1080
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1081
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
1082
      if(Botan::any_null_pointers(time_since_epoch)) {
1083
         return BOTAN_FFI_ERROR_NULL_POINTER;
1084
      }
1085
      *time_since_epoch = c.this_update().time_since_epoch();
1086
      return BOTAN_FFI_SUCCESS;
1087
   });
1088
#else
1089
   BOTAN_UNUSED(crl, time_since_epoch);
1090
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1091
#endif
1092
}
1093

1094
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
5✔
1095
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1096
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
10✔
1097
      const auto& time = c.next_update();
1098
      if(!time.time_is_set()) {
1099
         return BOTAN_FFI_ERROR_NO_VALUE;
1100
      }
1101

1102
      if(Botan::any_null_pointers(time_since_epoch)) {
1103
         return BOTAN_FFI_ERROR_NULL_POINTER;
1104
      }
1105

1106
      *time_since_epoch = c.next_update().time_since_epoch();
1107
      return BOTAN_FFI_SUCCESS;
1108
   });
1109
#else
1110
   BOTAN_UNUSED(crl, time_since_epoch);
1111
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1112
#endif
1113
}
1114

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

1141
int botan_x509_crl_entry_create(botan_x509_crl_entry_t* entry, botan_x509_cert_t cert, int reason_code) {
2✔
1142
   if(Botan::any_null_pointers(entry)) {
2✔
1143
      return BOTAN_FFI_ERROR_NULL_POINTER;
1144
   }
1145
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1146
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
1147
      return ffi_new_object(
2✔
1148
         entry, std::make_unique<Botan::CRL_Entry>(safe_get(cert), static_cast<Botan::CRL_Code>(reason_code)));
4✔
1149
   });
2✔
1150
#else
1151
   BOTAN_UNUSED(cert, reason_code);
1152
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1153
#endif
1154
}
1155

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

1179
      std::vector<Botan::CRL_Entry> entries;
3✔
1180
      entries.reserve(new_entries_len);
3✔
1181
      for(size_t i = 0; i < new_entries_len; i++) {
5✔
1182
         entries.push_back(safe_get(new_entries[i]));
2✔
1183
      }
1184

1185
      auto crl = std::make_unique<Botan::X509_CRL>(ca.update_crl(
6✔
1186
         safe_get(last_crl), entries, rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
6✔
1187
      return ffi_new_object(crl_obj, std::move(crl));
6✔
1188
   });
6✔
1189
#else
1190
   BOTAN_UNUSED(
1191
      last_crl, rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update, new_entries, new_entries_len);
1192
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1193
#endif
1194
}
1195

1196
int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key) {
3✔
1197
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1198
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) -> int { return c.check_signature(safe_get(key)) ? 1 : 0; });
6✔
1199
#else
1200
   BOTAN_UNUSED(crl, key);
1201
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1202
#endif
1203
}
1204

1205
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
13✔
1206
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1207
   return BOTAN_FFI_CHECKED_DELETE(crl);
13✔
1208
#else
1209
   BOTAN_UNUSED(crl);
1210
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1211
#endif
1212
}
1213

1214
int botan_x509_crl_view_binary_values(botan_x509_crl_t crl_obj,
3✔
1215
                                      botan_x509_value_type value_type,
1216
                                      size_t index,
1217
                                      botan_view_ctx ctx,
1218
                                      botan_view_bin_fn view_fn) {
1219
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1220
   if(index != 0) {
3✔
1221
      // As of now there are no multi-value binary entries.
1222
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1223
   }
1224

1225
   auto view = [=](std::span<const uint8_t> value) -> int {
4✔
1226
      if(value.empty()) {
1✔
1227
         return BOTAN_FFI_ERROR_NO_VALUE;
1228
      } else {
1229
         return invoke_view_callback(view_fn, ctx, value);
1✔
1230
      }
1231
   };
3✔
1232

1233
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
12✔
1234
      switch(value_type) {
1235
         case BOTAN_X509_SERIAL_NUMBER:
1236
            return view(Botan::store_be(crl.crl_number()));
1237
         case BOTAN_X509_ISSUER_DN_BITS:
1238
            return view(Botan::ASN1::put_in_sequence(crl.issuer_dn().get_bits()));
1239
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1240
            return view(crl.authority_key_id());
1241

1242
         case BOTAN_X509_TBS_DATA_BITS:
1243
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1244
         case BOTAN_X509_SIGNATURE_BITS:
1245
         case BOTAN_X509_DER_ENCODING:
1246
            return botan_x509_object_view_value(crl, value_type, index, ctx, view_fn);
1247

1248
         case BOTAN_X509_SUBJECT_DN_BITS:
1249
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1250
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1251
         case BOTAN_X509_PEM_ENCODING:
1252
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1253
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1254
         case BOTAN_X509_CA_ISSUERS_URLS:
1255
            return BOTAN_FFI_ERROR_NO_VALUE;
1256
      }
1257

1258
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1259
   });
1260
#else
1261
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view_fn);
1262
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1263
#endif
1264
}
1265

1266
int botan_x509_crl_view_binary_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1267
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1268
   return enumerator_count_values(count, [=](size_t index) {
1✔
1269
      return botan_x509_crl_view_binary_values(
1✔
1270
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1271
   });
1✔
1272
#else
1273
   BOTAN_UNUSED(crl_obj, value_type, count);
1274
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1275
#endif
1276
}
1277

1278
int botan_x509_crl_view_string_values(botan_x509_crl_t crl_obj,
3✔
1279
                                      botan_x509_value_type value_type,
1280
                                      size_t index,
1281
                                      botan_view_ctx ctx,
1282
                                      botan_view_str_fn view) {
1283
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1284
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
6✔
1285
      switch(value_type) {
1286
         case BOTAN_X509_PEM_ENCODING:
1287
            return botan_x509_object_view_value(crl, value_type, index, ctx, view);
1288

1289
         case BOTAN_X509_SERIAL_NUMBER:
1290
         case BOTAN_X509_SUBJECT_DN_BITS:
1291
         case BOTAN_X509_ISSUER_DN_BITS:
1292
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1293
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1294
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1295
         case BOTAN_X509_TBS_DATA_BITS:
1296
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1297
         case BOTAN_X509_SIGNATURE_BITS:
1298
         case BOTAN_X509_DER_ENCODING:
1299
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1300
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1301
         case BOTAN_X509_CA_ISSUERS_URLS:
1302
            return BOTAN_FFI_ERROR_NO_VALUE;
1303
      }
1304

1305
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1306
   });
1307
#else
1308
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view);
1309
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1310
#endif
1311
}
1312

1313
int botan_x509_crl_view_string_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1314
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1315
   return enumerator_count_values(count, [=](size_t index) {
1✔
1316
      return botan_x509_crl_view_string_values(
2✔
1317
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1318
   });
1✔
1319
#else
1320
   BOTAN_UNUSED(crl_obj, value_type, count);
1321
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1322
#endif
1323
}
1324

1325
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
1326
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1327
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
1328
#else
1329
   BOTAN_UNUSED(cert);
1330
   BOTAN_UNUSED(crl);
1331
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1332
#endif
1333
}
1334

1335
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
8✔
1336
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1337
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
16✔
1338
      const auto& entries = c.get_revoked();
1339
      if(index >= entries.size()) {
1340
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1341
      }
1342

1343
      if(Botan::any_null_pointers(entry)) {
1344
         return BOTAN_FFI_ERROR_NULL_POINTER;
1345
      }
1346

1347
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
1348
   });
1349
#else
1350
   BOTAN_UNUSED(crl, index, entry);
1351
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1352
#endif
1353
}
1354

1355
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
4✔
1356
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1357
   if(Botan::any_null_pointers(count)) {
4✔
1358
      return BOTAN_FFI_ERROR_NULL_POINTER;
1359
   }
1360

1361
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
8✔
1362
#else
1363
   BOTAN_UNUSED(crl, count);
1364
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1365
#endif
1366
}
1367

1368
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
6✔
1369
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1370
   return BOTAN_FFI_CHECKED_DELETE(entry);
6✔
1371
#else
1372
   BOTAN_UNUSED(entry);
1373
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1374
#endif
1375
}
1376

1377
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
3✔
1378
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1379
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1380
      if(Botan::any_null_pointers(reason_code)) {
1381
         return BOTAN_FFI_ERROR_NULL_POINTER;
1382
      }
1383

1384
      *reason_code = static_cast<int>(e.reason_code());
1385
      return BOTAN_FFI_SUCCESS;
1386
   });
1387
#else
1388
   BOTAN_UNUSED(entry, reason_code);
1389
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1390
#endif
1391
}
1392

1393
int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) {
3✔
1394
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1395
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1396
      if(Botan::any_null_pointers(serial_number)) {
1397
         return BOTAN_FFI_ERROR_NULL_POINTER;
1398
      }
1399

1400
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
1401
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
1402
   });
1403
#else
1404
   BOTAN_UNUSED(entry, serial_number);
1405
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1406
#endif
1407
}
1408

1409
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
1410
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1411
   return BOTAN_FFI_VISIT(
2✔
1412
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
1413
#else
1414
   BOTAN_UNUSED(entry, ctx, view);
1415
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1416
#endif
1417
}
1418

1419
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
3✔
1420
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1421
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1422
      if(Botan::any_null_pointers(time_since_epoch)) {
1423
         return BOTAN_FFI_ERROR_NULL_POINTER;
1424
      }
1425

1426
      *time_since_epoch = e.expire_time().time_since_epoch();
1427
      return BOTAN_FFI_SUCCESS;
1428
   });
1429
#else
1430
   BOTAN_UNUSED(entry, time_since_epoch);
1431
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1432
#endif
1433
}
1434

1435
int botan_x509_cert_verify_with_crl(int* result_code,
20✔
1436
                                    botan_x509_cert_t cert,
1437
                                    const botan_x509_cert_t* intermediates,
1438
                                    size_t intermediates_len,
1439
                                    const botan_x509_cert_t* trusted,
1440
                                    size_t trusted_len,
1441
                                    const botan_x509_crl_t* crls,
1442
                                    size_t crls_len,
1443
                                    const char* trusted_path,
1444
                                    size_t required_strength,
1445
                                    const char* hostname_cstr,
1446
                                    uint64_t reference_time) {
1447
   if(required_strength == 0) {
20✔
1448
      required_strength = 110;
10✔
1449
   }
1450

1451
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1452
   return ffi_guard_thunk(__func__, [=]() -> int {
20✔
1453
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
22✔
1454
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
20✔
1455
      const auto validation_time = reference_time == 0
20✔
1456
                                      ? std::chrono::system_clock::now()
20✔
1457
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1458

1459
      std::vector<Botan::X509_Certificate> end_certs;
20✔
1460
      end_certs.push_back(safe_get(cert));
20✔
1461
      for(size_t i = 0; i != intermediates_len; ++i) {
38✔
1462
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1463
      }
1464

1465
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
20✔
1466
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
20✔
1467
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
20✔
1468
      std::vector<Botan::Certificate_Store*> trusted_roots;
20✔
1469

1470
      if(trusted_path != nullptr && *trusted_path != 0) {
20✔
1471
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1472
         trusted_roots.push_back(trusted_from_path.get());
2✔
1473
      }
1474

1475
      if(trusted_len > 0) {
20✔
1476
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
34✔
1477
         for(size_t i = 0; i != trusted_len; ++i) {
34✔
1478
            trusted_extra->add_certificate(safe_get(trusted[i]));
17✔
1479
         }
1480
         trusted_roots.push_back(trusted_extra.get());
17✔
1481
      }
1482

1483
      if(crls_len > 0) {
20✔
1484
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
26✔
1485
         for(size_t i = 0; i != crls_len; ++i) {
29✔
1486
            trusted_crls->add_crl(safe_get(crls[i]));
16✔
1487
         }
1488
         trusted_roots.push_back(trusted_crls.get());
13✔
1489
      }
1490

1491
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
40✔
1492

1493
      auto validation_result =
20✔
1494
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
20✔
1495

1496
      if(result_code != nullptr) {
20✔
1497
         *result_code = static_cast<int>(validation_result.result());
20✔
1498
      }
1499

1500
      if(validation_result.successful_validation()) {
20✔
1501
         return 0;
1502
      } else {
1503
         return 1;
10✔
1504
      }
1505
   });
22✔
1506
#else
1507
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1508
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1509
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1510
#endif
1511
}
1512
}
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