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

randombit / botan / 22573628590

02 Mar 2026 11:18AM UTC coverage: 91.955% (+1.6%) from 90.312%
22573628590

push

github

web-flow
Merge pull request #5166 from arckoor/x509-crl-ffi

Add CRL creation to FFI

105473 of 114701 relevant lines covered (91.95%)

11366424.23 hits per line

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

95.01
/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);
108✔
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());
6✔
261
      case BOTAN_X509_SIGNATURE_SCHEME_BITS:
2✔
262
         return view(object.signature_algorithm().BER_encode());
6✔
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());
6✔
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 defined(BOTAN_HAS_X509_CERTIFICATES)
476
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
477
      auto issuer_info = c.issuer_info(key);
478
      if(index < issuer_info.size()) {
479
         // TODO(Botan4) change the type of out and remove this cast
480
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
481
      } else {
482
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
483
      }
484
   });
485
#else
486
   BOTAN_UNUSED(cert, key, index, out, out_len);
487
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
488
#endif
489
}
490

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

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

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

525
int botan_x509_cert_get_subject_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
526
#if defined(BOTAN_HAS_X509_CERTIFICATES)
527
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
528
      if(Botan::any_null_pointers(count)) {
529
         return BOTAN_FFI_ERROR_NULL_POINTER;
530
      }
531

532
      *count = c.subject_info(key).size();
533
      return BOTAN_FFI_SUCCESS;
534
   });
535
#else
536
   BOTAN_UNUSED(cert, key, count);
537
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
538
#endif
539
}
540

541
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
542
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
543
}
544

545
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
546
#if defined(BOTAN_HAS_X509_CERTIFICATES)
547
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
548
#else
549
   BOTAN_UNUSED(cert, ctx, view);
550
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
551
#endif
552
}
553

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

569
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
570
#if defined(BOTAN_HAS_X509_CERTIFICATES)
571
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
572
      if(Botan::any_null_pointers(oid)) {
573
         return BOTAN_FFI_ERROR_NULL_POINTER;
574
      }
575

576
      return c.has_ex_constraint(oid) ? 1 : 0;
577
   });
578
#else
579
   BOTAN_UNUSED(cert, oid);
580
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
581
#endif
582
}
583

584
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
585
#if defined(BOTAN_HAS_X509_CERTIFICATES)
586
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? 1 : 0; });
8✔
587
#else
588
   BOTAN_UNUSED(cert, oid);
589
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
590
#endif
591
}
592

593
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
38✔
594
#if defined(BOTAN_HAS_X509_CERTIFICATES)
595
   return BOTAN_FFI_CHECKED_DELETE(cert);
38✔
596
#else
597
   BOTAN_UNUSED(cert);
598
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
599
#endif
600
}
601

602
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
603
#if defined(BOTAN_HAS_X509_CERTIFICATES)
604
   return BOTAN_FFI_VISIT(cert,
6✔
605
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
606
#else
607
   BOTAN_UNUSED(cert, out, out_len);
608
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
609
#endif
610
}
611

612
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
613
#if defined(BOTAN_HAS_X509_CERTIFICATES)
614
   return BOTAN_FFI_VISIT(cert,
4✔
615
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
616
#else
617
   BOTAN_UNUSED(cert, out, out_len);
618
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
619
#endif
620
}
621

622
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
623
#if defined(BOTAN_HAS_X509_CERTIFICATES)
624
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
625
#else
626
   BOTAN_UNUSED(cert, time_since_epoch);
627
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
628
#endif
629
}
630

631
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
632
#if defined(BOTAN_HAS_X509_CERTIFICATES)
633
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().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_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
641
#if defined(BOTAN_HAS_X509_CERTIFICATES)
642
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
643
#else
644
   BOTAN_UNUSED(cert, out, out_len);
645
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
646
#endif
647
}
648

649
int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) {
1✔
650
#if defined(BOTAN_HAS_X509_CERTIFICATES)
651
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
2✔
652
      if(Botan::any_null_pointers(serial_number)) {
653
         return BOTAN_FFI_ERROR_NULL_POINTER;
654
      }
655

656
      auto serial_bn = Botan::BigInt::from_bytes(c.serial_number());
657
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
658
   });
659
#else
660
   BOTAN_UNUSED(cert, serial_number);
661
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
662
#endif
663
}
664

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

669
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
670
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
671
   });
672
#else
673
   BOTAN_UNUSED(cert, hash, out, out_len);
674
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
675
#endif
676
}
677

678
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
679
#if defined(BOTAN_HAS_X509_CERTIFICATES)
680
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
681
#else
682
   BOTAN_UNUSED(cert, out, out_len);
683
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
684
#endif
685
}
686

687
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
688
#if defined(BOTAN_HAS_X509_CERTIFICATES)
689
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
690
#else
691
   BOTAN_UNUSED(cert, out, out_len);
692
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
693
#endif
694
}
695

696
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
697
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
698
}
699

700
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
701
#if defined(BOTAN_HAS_X509_CERTIFICATES)
702
   return BOTAN_FFI_VISIT(cert,
6✔
703
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
704
#else
705
   BOTAN_UNUSED(cert, ctx, view);
706
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
707
#endif
708
}
709

710
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
711
#if defined(BOTAN_HAS_X509_CERTIFICATES)
712
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
713
      if(Botan::any_null_pointers(type)) {
714
         return BOTAN_FFI_ERROR_NULL_POINTER;
715
      }
716

717
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
718
      if(!mapped_type.has_value()) {
719
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
720
      }
721

722
      *type = mapped_type.value();
723
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
724
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
725
      }
726

727
      return BOTAN_FFI_SUCCESS;
728
   });
729
#else
730
   BOTAN_UNUSED(name, type);
731
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
732
#endif
733
}
734

735
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
736
                                              botan_view_ctx ctx,
737
                                              botan_view_str_fn view) {
738
#if defined(BOTAN_HAS_X509_CERTIFICATES)
739
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
740
      const auto type = to_botan_x509_general_name_types(n.type_code());
741
      if(!type) {
742
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
743
      }
744

745
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
746
         type != BOTAN_X509_IP_ADDRESS) {
747
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
748
      }
749

750
      return invoke_view_callback(view, ctx, n.name());
751
   });
752
#else
753
   BOTAN_UNUSED(name, ctx, view);
754
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
755
#endif
756
}
757

758
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
759
                                              botan_view_ctx ctx,
760
                                              botan_view_bin_fn view) {
761
#if defined(BOTAN_HAS_X509_CERTIFICATES)
762
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
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_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
769
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
770
      }
771

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

780
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
781
#if defined(BOTAN_HAS_X509_CERTIFICATES)
782
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
783
#else
784
   BOTAN_UNUSED(name);
785
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
786
#endif
787
}
788

789
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
790
                                               size_t index,
791
                                               botan_x509_general_name_t* constraint) {
792
#if defined(BOTAN_HAS_X509_CERTIFICATES)
793
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
794
      if(Botan::any_null_pointers(constraint)) {
795
         return BOTAN_FFI_ERROR_NULL_POINTER;
796
      }
797

798
      const auto& constraints = c.name_constraints().permitted();
799
      if(index >= constraints.size()) {
800
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
801
      }
802

803
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
804
   });
805
#else
806
   BOTAN_UNUSED(cert, index, constraint);
807
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
808
#endif
809
}
810

811
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
812
#if defined(BOTAN_HAS_X509_CERTIFICATES)
813
   if(Botan::any_null_pointers(count)) {
1✔
814
      return BOTAN_FFI_ERROR_NULL_POINTER;
815
   }
816

817
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
818
#else
819
   BOTAN_UNUSED(cert, count);
820
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
821
#endif
822
}
823

824
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
825
                                              size_t index,
826
                                              botan_x509_general_name_t* constraint) {
827
#if defined(BOTAN_HAS_X509_CERTIFICATES)
828
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
829
      if(Botan::any_null_pointers(constraint)) {
830
         return BOTAN_FFI_ERROR_NULL_POINTER;
831
      }
832

833
      const auto& constraints = c.name_constraints().excluded();
834
      if(index >= constraints.size()) {
835
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
836
      }
837

838
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
839
   });
840
#else
841
   BOTAN_UNUSED(cert, index, constraint);
842
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
843
#endif
844
}
845

846
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
847
#if defined(BOTAN_HAS_X509_CERTIFICATES)
848
   if(Botan::any_null_pointers(count)) {
1✔
849
      return BOTAN_FFI_ERROR_NULL_POINTER;
850
   }
851

852
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
853
#else
854
   BOTAN_UNUSED(cert, count);
855
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
856
#endif
857
}
858

859
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
860
                                              size_t index,
861
                                              botan_x509_general_name_t* alt_name) {
862
#if defined(BOTAN_HAS_X509_CERTIFICATES)
863
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
864
      if(Botan::any_null_pointers(alt_name)) {
865
         return BOTAN_FFI_ERROR_NULL_POINTER;
866
      }
867

868
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
869
         return BOTAN_FFI_ERROR_NO_VALUE;
870
      }
871

872
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
873
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
874
      }
875

876
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
877
   });
878
#else
879
   BOTAN_UNUSED(cert, index, alt_name);
880
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
881
#endif
882
}
883

884
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
885
#if defined(BOTAN_HAS_X509_CERTIFICATES)
886
   if(Botan::any_null_pointers(count)) {
6✔
887
      return BOTAN_FFI_ERROR_NULL_POINTER;
888
   }
889

890
   return BOTAN_FFI_VISIT(
12✔
891
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
892
#else
893
   BOTAN_UNUSED(cert, count);
894
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
895
#endif
896
}
897

898
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
899
                                             size_t index,
900
                                             botan_x509_general_name_t* alt_name) {
901
#if defined(BOTAN_HAS_X509_CERTIFICATES)
902
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
903
      if(Botan::any_null_pointers(alt_name)) {
904
         return BOTAN_FFI_ERROR_NULL_POINTER;
905
      }
906

907
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
908
         return BOTAN_FFI_ERROR_NO_VALUE;
909
      }
910

911
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
912
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
913
      }
914

915
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
916
   });
917
#else
918
   BOTAN_UNUSED(cert, index, alt_name);
919
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
920
#endif
921
}
922

923
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
924
#if defined(BOTAN_HAS_X509_CERTIFICATES)
925
   if(Botan::any_null_pointers(count)) {
6✔
926
      return BOTAN_FFI_ERROR_NULL_POINTER;
927
   }
928

929
   return BOTAN_FFI_VISIT(
12✔
930
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.issuer_alt_name()); });
931
#else
932
   BOTAN_UNUSED(cert, count);
933
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
934
#endif
935
}
936

937
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
938
   if(hostname == nullptr) {
6✔
939
      return BOTAN_FFI_ERROR_NULL_POINTER;
940
   }
941

942
#if defined(BOTAN_HAS_X509_CERTIFICATES)
943
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
944
#else
945
   BOTAN_UNUSED(cert);
946
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
947
#endif
948
}
949

950
int botan_x509_cert_verify(int* result_code,
4✔
951
                           botan_x509_cert_t cert,
952
                           const botan_x509_cert_t* intermediates,
953
                           size_t intermediates_len,
954
                           const botan_x509_cert_t* trusted,
955
                           size_t trusted_len,
956
                           const char* trusted_path,
957
                           size_t required_strength,
958
                           const char* hostname_cstr,
959
                           uint64_t reference_time) {
960
   if(required_strength == 0) {
4✔
961
      required_strength = 110;
3✔
962
   }
963

964
#if defined(BOTAN_HAS_X509_CERTIFICATES)
965
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
966
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
967
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
968
      const auto validation_time = reference_time == 0
4✔
969
                                      ? std::chrono::system_clock::now()
4✔
970
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
971

972
      std::vector<Botan::X509_Certificate> end_certs;
4✔
973
      end_certs.push_back(safe_get(cert));
4✔
974
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
975
         end_certs.push_back(safe_get(intermediates[i]));
5✔
976
      }
977

978
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
979
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
980
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
981

982
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
983
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
984
         trusted_roots.push_back(trusted_from_path.get());
×
985
      }
986

987
      if(trusted_len > 0) {
4✔
988
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
989
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
990
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
991
         }
992
         trusted_roots.push_back(trusted_extra.get());
4✔
993
      }
994

995
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
996

997
      auto validation_result =
4✔
998
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
999

1000
      if(result_code != nullptr) {
4✔
1001
         *result_code = static_cast<int>(validation_result.result());
4✔
1002
      }
1003

1004
      if(validation_result.successful_validation()) {
4✔
1005
         return 0;
1006
      } else {
1007
         return 1;
3✔
1008
      }
1009
   });
4✔
1010
#else
1011
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1012
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
1013
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1014
#endif
1015
}
1016

1017
const char* botan_x509_cert_validation_status(int code) {
11✔
1018
   if(code < 0) {
11✔
1019
      return nullptr;
1020
   }
1021

1022
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1023
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
1024
   return Botan::to_string(sc);
11✔
1025
#else
1026
   return nullptr;
1027
#endif
1028
}
1029

1030
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
1031
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
1032
      return BOTAN_FFI_ERROR_NULL_POINTER;
1033
   }
1034

1035
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1036

1037
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
1038
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
1039
      return ffi_new_object(crl_obj, std::move(c));
14✔
1040
   });
14✔
1041

1042
#else
1043
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1044
#endif
1045
}
1046

1047
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
1048
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
1049
      return BOTAN_FFI_ERROR_NULL_POINTER;
1050
   }
1051

1052
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1053
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
1054
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
1055
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
1056
      return ffi_new_object(crl_obj, std::move(c));
1✔
1057
   });
3✔
1058
#else
1059
   BOTAN_UNUSED(crl_bits_len);
1060
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1061
#endif
1062
}
1063

1064
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
1065
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1066
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
1067
      if(Botan::any_null_pointers(time_since_epoch)) {
1068
         return BOTAN_FFI_ERROR_NULL_POINTER;
1069
      }
1070
      *time_since_epoch = c.this_update().time_since_epoch();
1071
      return BOTAN_FFI_SUCCESS;
1072
   });
1073
#else
1074
   BOTAN_UNUSED(crl, time_since_epoch);
1075
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1076
#endif
1077
}
1078

1079
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
5✔
1080
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1081
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
10✔
1082
      const auto& time = c.next_update();
1083
      if(!time.time_is_set()) {
1084
         return BOTAN_FFI_ERROR_NO_VALUE;
1085
      }
1086

1087
      if(Botan::any_null_pointers(time_since_epoch)) {
1088
         return BOTAN_FFI_ERROR_NULL_POINTER;
1089
      }
1090

1091
      *time_since_epoch = c.next_update().time_since_epoch();
1092
      return BOTAN_FFI_SUCCESS;
1093
   });
1094
#else
1095
   BOTAN_UNUSED(crl, time_since_epoch);
1096
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1097
#endif
1098
}
1099

1100
int botan_x509_crl_create(botan_x509_crl_t* crl_obj,
2✔
1101
                          botan_rng_t rng,
1102
                          botan_x509_cert_t ca_cert,
1103
                          botan_privkey_t ca_key,
1104
                          uint64_t issue_time,
1105
                          uint32_t next_update,
1106
                          const char* hash_fn,
1107
                          const char* padding) {
1108
   if(Botan::any_null_pointers(crl_obj)) {
2✔
1109
      return BOTAN_FFI_ERROR_NULL_POINTER;
1110
   }
1111
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1112
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
1113
      auto& rng_ = safe_get(rng);
2✔
1114
      auto ca = Botan::X509_CA(
2✔
1115
         safe_get(ca_cert), safe_get(ca_key), default_from_ptr(hash_fn), default_from_ptr(padding), rng_);
4✔
1116
      auto crl = std::make_unique<Botan::X509_CRL>(
2✔
1117
         ca.new_crl(rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
2✔
1118
      return ffi_new_object(crl_obj, std::move(crl));
4✔
1119
   });
4✔
1120
#else
1121
   BOTAN_UNUSED(rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update);
1122
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1123
#endif
1124
}
1125

1126
int botan_x509_crl_entry_create(botan_x509_crl_entry_t* entry, botan_x509_cert_t cert, int reason_code) {
2✔
1127
   if(Botan::any_null_pointers(entry)) {
2✔
1128
      return BOTAN_FFI_ERROR_NULL_POINTER;
1129
   }
1130
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1131
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
1132
      return ffi_new_object(
2✔
1133
         entry, std::make_unique<Botan::CRL_Entry>(safe_get(cert), static_cast<Botan::CRL_Code>(reason_code)));
4✔
1134
   });
2✔
1135
#else
1136
   BOTAN_UNUSED(cert, reason_code);
1137
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1138
#endif
1139
}
1140

1141
int botan_x509_crl_update(botan_x509_crl_t* crl_obj,
4✔
1142
                          botan_x509_crl_t last_crl,
1143
                          botan_rng_t rng,
1144
                          botan_x509_cert_t ca_cert,
1145
                          botan_privkey_t ca_key,
1146
                          uint64_t issue_time,
1147
                          uint32_t next_update,
1148
                          const botan_x509_crl_entry_t* new_entries,
1149
                          size_t new_entries_len,
1150
                          const char* hash_fn,
1151
                          const char* padding) {
1152
   if(Botan::any_null_pointers(crl_obj)) {
4✔
1153
      return BOTAN_FFI_ERROR_NULL_POINTER;
1154
   }
1155
   if(new_entries_len > 0 && Botan::any_null_pointers(new_entries)) {
4✔
1156
      return BOTAN_FFI_ERROR_NULL_POINTER;
1157
   }
1158
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1159
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
1160
      auto& rng_ = safe_get(rng);
3✔
1161
      auto ca = Botan::X509_CA(
3✔
1162
         safe_get(ca_cert), safe_get(ca_key), default_from_ptr(hash_fn), default_from_ptr(padding), rng_);
6✔
1163

1164
      std::vector<Botan::CRL_Entry> entries;
3✔
1165
      entries.reserve(new_entries_len);
3✔
1166
      for(size_t i = 0; i < new_entries_len; i++) {
5✔
1167
         entries.push_back(safe_get(new_entries[i]));
2✔
1168
      }
1169

1170
      auto crl = std::make_unique<Botan::X509_CRL>(ca.update_crl(
6✔
1171
         safe_get(last_crl), entries, rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
6✔
1172
      return ffi_new_object(crl_obj, std::move(crl));
6✔
1173
   });
6✔
1174
#else
1175
   BOTAN_UNUSED(
1176
      last_crl, rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update, new_entries, new_entries_len);
1177
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1178
#endif
1179
}
1180

1181
int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key) {
3✔
1182
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1183
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) -> int { return c.check_signature(safe_get(key)) ? 1 : 0; });
6✔
1184
#else
1185
   BOTAN_UNUSED(crl, key);
1186
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1187
#endif
1188
}
1189

1190
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
13✔
1191
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1192
   return BOTAN_FFI_CHECKED_DELETE(crl);
13✔
1193
#else
1194
   BOTAN_UNUSED(crl);
1195
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1196
#endif
1197
}
1198

1199
int botan_x509_crl_view_binary_values(botan_x509_crl_t crl_obj,
3✔
1200
                                      botan_x509_value_type value_type,
1201
                                      size_t index,
1202
                                      botan_view_ctx ctx,
1203
                                      botan_view_bin_fn view_fn) {
1204
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1205
   if(index != 0) {
3✔
1206
      // As of now there are no multi-value binary entries.
1207
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1208
   }
1209

1210
   auto view = [=](std::span<const uint8_t> value) -> int {
4✔
1211
      if(value.empty()) {
1✔
1212
         return BOTAN_FFI_ERROR_NO_VALUE;
1213
      } else {
1214
         return invoke_view_callback(view_fn, ctx, value);
1✔
1215
      }
1216
   };
3✔
1217

1218
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
12✔
1219
      switch(value_type) {
1220
         case BOTAN_X509_SERIAL_NUMBER:
1221
            return view(Botan::store_be(crl.crl_number()));
1222
         case BOTAN_X509_ISSUER_DN_BITS:
1223
            return view(Botan::ASN1::put_in_sequence(crl.issuer_dn().get_bits()));
1224
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1225
            return view(crl.authority_key_id());
1226

1227
         case BOTAN_X509_TBS_DATA_BITS:
1228
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1229
         case BOTAN_X509_SIGNATURE_BITS:
1230
         case BOTAN_X509_DER_ENCODING:
1231
            return botan_x509_object_view_value(crl, value_type, index, ctx, view_fn);
1232

1233
         case BOTAN_X509_SUBJECT_DN_BITS:
1234
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1235
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1236
         case BOTAN_X509_PEM_ENCODING:
1237
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1238
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1239
         case BOTAN_X509_CA_ISSUERS_URLS:
1240
            return BOTAN_FFI_ERROR_NO_VALUE;
1241
      }
1242

1243
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1244
   });
1245
#else
1246
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view_fn);
1247
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1248
#endif
1249
}
1250

1251
int botan_x509_crl_view_binary_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1252
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1253
   return enumerator_count_values(count, [=](size_t index) {
1✔
1254
      return botan_x509_crl_view_binary_values(
1✔
1255
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1256
   });
1✔
1257
#else
1258
   BOTAN_UNUSED(crl_obj, value_type, count);
1259
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1260
#endif
1261
}
1262

1263
int botan_x509_crl_view_string_values(botan_x509_crl_t crl_obj,
3✔
1264
                                      botan_x509_value_type value_type,
1265
                                      size_t index,
1266
                                      botan_view_ctx ctx,
1267
                                      botan_view_str_fn view) {
1268
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1269
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
6✔
1270
      switch(value_type) {
1271
         case BOTAN_X509_PEM_ENCODING:
1272
            return botan_x509_object_view_value(crl, value_type, index, ctx, view);
1273

1274
         case BOTAN_X509_SERIAL_NUMBER:
1275
         case BOTAN_X509_SUBJECT_DN_BITS:
1276
         case BOTAN_X509_ISSUER_DN_BITS:
1277
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1278
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1279
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1280
         case BOTAN_X509_TBS_DATA_BITS:
1281
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1282
         case BOTAN_X509_SIGNATURE_BITS:
1283
         case BOTAN_X509_DER_ENCODING:
1284
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1285
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1286
         case BOTAN_X509_CA_ISSUERS_URLS:
1287
            return BOTAN_FFI_ERROR_NO_VALUE;
1288
      }
1289

1290
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1291
   });
1292
#else
1293
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view);
1294
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1295
#endif
1296
}
1297

1298
int botan_x509_crl_view_string_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1299
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1300
   return enumerator_count_values(count, [=](size_t index) {
1✔
1301
      return botan_x509_crl_view_string_values(
2✔
1302
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1303
   });
1✔
1304
#else
1305
   BOTAN_UNUSED(crl_obj, value_type, count);
1306
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1307
#endif
1308
}
1309

1310
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
1311
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1312
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
1313
#else
1314
   BOTAN_UNUSED(cert);
1315
   BOTAN_UNUSED(crl);
1316
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1317
#endif
1318
}
1319

1320
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
8✔
1321
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1322
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
16✔
1323
      const auto& entries = c.get_revoked();
1324
      if(index >= entries.size()) {
1325
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1326
      }
1327

1328
      if(Botan::any_null_pointers(entry)) {
1329
         return BOTAN_FFI_ERROR_NULL_POINTER;
1330
      }
1331

1332
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
1333
   });
1334
#else
1335
   BOTAN_UNUSED(crl, index, entry);
1336
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1337
#endif
1338
}
1339

1340
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
4✔
1341
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1342
   if(Botan::any_null_pointers(count)) {
4✔
1343
      return BOTAN_FFI_ERROR_NULL_POINTER;
1344
   }
1345

1346
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
8✔
1347
#else
1348
   BOTAN_UNUSED(crl, count);
1349
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1350
#endif
1351
}
1352

1353
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
6✔
1354
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1355
   return BOTAN_FFI_CHECKED_DELETE(entry);
6✔
1356
#else
1357
   BOTAN_UNUSED(entry);
1358
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1359
#endif
1360
}
1361

1362
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
3✔
1363
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1364
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1365
      if(Botan::any_null_pointers(reason_code)) {
1366
         return BOTAN_FFI_ERROR_NULL_POINTER;
1367
      }
1368

1369
      *reason_code = static_cast<int>(e.reason_code());
1370
      return BOTAN_FFI_SUCCESS;
1371
   });
1372
#else
1373
   BOTAN_UNUSED(entry, reason_code);
1374
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1375
#endif
1376
}
1377

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

1385
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
1386
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
1387
   });
1388
#else
1389
   BOTAN_UNUSED(entry, serial_number);
1390
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1391
#endif
1392
}
1393

1394
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
1395
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1396
   return BOTAN_FFI_VISIT(
2✔
1397
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
1398
#else
1399
   BOTAN_UNUSED(entry, ctx, view);
1400
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1401
#endif
1402
}
1403

1404
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
3✔
1405
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1406
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1407
      if(Botan::any_null_pointers(time_since_epoch)) {
1408
         return BOTAN_FFI_ERROR_NULL_POINTER;
1409
      }
1410

1411
      *time_since_epoch = e.expire_time().time_since_epoch();
1412
      return BOTAN_FFI_SUCCESS;
1413
   });
1414
#else
1415
   BOTAN_UNUSED(entry, time_since_epoch);
1416
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1417
#endif
1418
}
1419

1420
int botan_x509_cert_verify_with_crl(int* result_code,
20✔
1421
                                    botan_x509_cert_t cert,
1422
                                    const botan_x509_cert_t* intermediates,
1423
                                    size_t intermediates_len,
1424
                                    const botan_x509_cert_t* trusted,
1425
                                    size_t trusted_len,
1426
                                    const botan_x509_crl_t* crls,
1427
                                    size_t crls_len,
1428
                                    const char* trusted_path,
1429
                                    size_t required_strength,
1430
                                    const char* hostname_cstr,
1431
                                    uint64_t reference_time) {
1432
   if(required_strength == 0) {
20✔
1433
      required_strength = 110;
10✔
1434
   }
1435

1436
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1437
   return ffi_guard_thunk(__func__, [=]() -> int {
20✔
1438
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
22✔
1439
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
20✔
1440
      const auto validation_time = reference_time == 0
20✔
1441
                                      ? std::chrono::system_clock::now()
20✔
1442
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1443

1444
      std::vector<Botan::X509_Certificate> end_certs;
20✔
1445
      end_certs.push_back(safe_get(cert));
20✔
1446
      for(size_t i = 0; i != intermediates_len; ++i) {
38✔
1447
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1448
      }
1449

1450
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
20✔
1451
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
20✔
1452
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
20✔
1453
      std::vector<Botan::Certificate_Store*> trusted_roots;
20✔
1454

1455
      if(trusted_path != nullptr && *trusted_path != 0) {
20✔
1456
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1457
         trusted_roots.push_back(trusted_from_path.get());
2✔
1458
      }
1459

1460
      if(trusted_len > 0) {
20✔
1461
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
34✔
1462
         for(size_t i = 0; i != trusted_len; ++i) {
34✔
1463
            trusted_extra->add_certificate(safe_get(trusted[i]));
17✔
1464
         }
1465
         trusted_roots.push_back(trusted_extra.get());
17✔
1466
      }
1467

1468
      if(crls_len > 0) {
20✔
1469
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
26✔
1470
         for(size_t i = 0; i != crls_len; ++i) {
29✔
1471
            trusted_crls->add_crl(safe_get(crls[i]));
16✔
1472
         }
1473
         trusted_roots.push_back(trusted_crls.get());
13✔
1474
      }
1475

1476
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
40✔
1477

1478
      auto validation_result =
20✔
1479
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
20✔
1480

1481
      if(result_code != nullptr) {
20✔
1482
         *result_code = static_cast<int>(validation_result.result());
20✔
1483
      }
1484

1485
      if(validation_result.successful_validation()) {
20✔
1486
         return 0;
1487
      } else {
1488
         return 1;
10✔
1489
      }
1490
   });
22✔
1491
#else
1492
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1493
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1494
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1495
#endif
1496
}
1497
}
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