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

randombit / botan / 28217640675

26 Jun 2026 03:19AM UTC coverage: 89.354% (-0.001%) from 89.355%
28217640675

push

github

web-flow
Merge pull request #5699 from randombit/jack/faster-iso9796-test

Reduce runtime for the ISO 9796 padding test

112053 of 125404 relevant lines covered (89.35%)

10896923.85 hits per line

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

93.73
/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/stl_util.h>
25
#endif
26

27
#if defined(BOTAN_HAS_X509_CERTIFICATES)
28

29
namespace Botan_FFI {
30

31
namespace {
32

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

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

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

64
   if(index < altnames.uri_names().size()) {
48✔
65
      auto itr = altnames.uri_names().begin();
24✔
66
      std::advance(itr, index);
24✔
67
      return Botan::GeneralName::_uri_san_value(itr->original_input());
72✔
68
   }
69
   index -= altnames.uri_names().size();
24✔
70

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

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

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

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

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

119
   BOTAN_ASSERT_UNREACHABLE();
×
120
}
121

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

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

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

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

166
}  // namespace
167

168
}  // namespace Botan_FFI
169

170
#endif
171

172
extern "C" {
173

174
using namespace Botan_FFI;
175

176
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
37✔
177
   if(Botan::any_null_pointers(cert_obj, cert_path)) {
37✔
178
      return BOTAN_FFI_ERROR_NULL_POINTER;
179
   }
180

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

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

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

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

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

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

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

211
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
212
   if(Botan::any_null_pointers(cert_obj, cert_bits)) {
×
213
      return BOTAN_FFI_ERROR_NULL_POINTER;
214
   }
215

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

229
namespace {
230

231
#if defined(BOTAN_HAS_X509_CERTIFICATES)
232

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

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

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

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

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

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

279
#endif
280

281
}  // namespace
282

283
extern "C" {
284

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

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

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

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

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

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

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

352
int botan_x509_cert_view_string_values(botan_x509_cert_t cert,
19✔
353
                                       botan_x509_value_type value_type,
354
                                       size_t index,
355
                                       botan_view_ctx ctx,
356
                                       botan_view_str_fn view_fn) {
357
#if defined(BOTAN_HAS_X509_CERTIFICATES)
358
   auto enumerate_uris = [view_fn, ctx](const std::vector<Botan::URI>& values, size_t idx) -> int {
35✔
359
      if(idx >= values.size()) {
16✔
360
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
361
      } else {
362
         return invoke_view_callback(view_fn, ctx, values[idx].original_input());
10✔
363
      }
364
   };
19✔
365

366
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
38✔
367
      switch(value_type) {
368
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
369
            return enumerate_uris(c.crl_distribution_point_uris(), index);
370
         case BOTAN_X509_OCSP_RESPONDER_URLS:
371
            return enumerate_uris(c.ocsp_responder_uris(), index);
372
         case BOTAN_X509_CA_ISSUERS_URLS:
373
            return enumerate_uris(c.ca_issuer_uris(), index);
374
         case BOTAN_X509_PEM_ENCODING:
375
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
376

377
         case BOTAN_X509_SERIAL_NUMBER:
378
         case BOTAN_X509_SUBJECT_DN_BITS:
379
         case BOTAN_X509_ISSUER_DN_BITS:
380
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
381
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
382
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
383
         case BOTAN_X509_TBS_DATA_BITS:
384
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
385
         case BOTAN_X509_SIGNATURE_BITS:
386
         case BOTAN_X509_DER_ENCODING:
387
            return BOTAN_FFI_ERROR_NO_VALUE;
388
      }
389

390
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
391
   });
392
#else
393
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
394
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
395
#endif
396
}
397

398
int botan_x509_cert_view_string_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
4✔
399
#if defined(BOTAN_HAS_X509_CERTIFICATES)
400
   return enumerator_count_values(count, [=](size_t index) {
4✔
401
      return botan_x509_cert_view_string_values(
10✔
402
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
403
   });
4✔
404
#else
405
   BOTAN_UNUSED(cert, value_type, count);
406
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
407
#endif
408
}
409

410
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
411
#if defined(BOTAN_HAS_X509_CERTIFICATES)
412
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? 1 : 0; });
4✔
413
#else
414
   BOTAN_UNUSED(cert);
415
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
416
#endif
417
}
418

419
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
420
#if defined(BOTAN_HAS_X509_CERTIFICATES)
421
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
422
      if(Botan::any_null_pointers(path_limit)) {
423
         return BOTAN_FFI_ERROR_NULL_POINTER;
424
      }
425

426
      if(const auto path_len = c.path_length_constraint()) {
427
         *path_limit = path_len.value();
428
         return BOTAN_FFI_SUCCESS;
429
      } else {
430
         return BOTAN_FFI_ERROR_NO_VALUE;
431
      }
432
   });
433
#else
434
   BOTAN_UNUSED(cert, path_limit);
435
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
436
#endif
437
}
438

439
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
440
   if(key == nullptr) {
2✔
441
      return BOTAN_FFI_ERROR_NULL_POINTER;
442
   }
443

444
   *key = nullptr;
2✔
445

446
#if defined(BOTAN_HAS_X509_CERTIFICATES)
447
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
448
      auto public_key = safe_get(cert).subject_public_key();
2✔
449
      return ffi_new_object(key, std::move(public_key));
4✔
450
   });
4✔
451
#else
452
   BOTAN_UNUSED(cert);
453
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
454
#endif
455
}
456

457
int botan_x509_cert_get_issuer_dn(
8✔
458
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
459
   if(key == nullptr) {
8✔
460
      return BOTAN_FFI_ERROR_NULL_POINTER;
461
   }
462
#if defined(BOTAN_HAS_X509_CERTIFICATES)
463
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
464
      auto issuer_info = c.issuer_info(key);
465
      if(index < issuer_info.size()) {
466
         // TODO(Botan4) change the type of out and remove this cast
467
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
468
      } else {
469
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
470
      }
471
   });
472
#else
473
   BOTAN_UNUSED(cert, key, index, out, out_len);
474
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
475
#endif
476
}
477

478
int botan_x509_cert_get_issuer_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
479
#if defined(BOTAN_HAS_X509_CERTIFICATES)
480
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
481
      if(Botan::any_null_pointers(key, count)) {
482
         return BOTAN_FFI_ERROR_NULL_POINTER;
483
      }
484

485
      *count = c.issuer_info(key).size();
486
      return BOTAN_FFI_SUCCESS;
487
   });
488
#else
489
   BOTAN_UNUSED(cert, key, count);
490
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
491
#endif
492
}
493

494
int botan_x509_cert_get_subject_dn(
8✔
495
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
496
   if(key == nullptr) {
8✔
497
      return BOTAN_FFI_ERROR_NULL_POINTER;
498
   }
499
#if defined(BOTAN_HAS_X509_CERTIFICATES)
500
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
501
      auto subject_info = c.subject_info(key);
502
      if(index < subject_info.size()) {
503
         // TODO(Botan4) change the type of out and remove this cast
504
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
505
      } else {
506
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
507
      }
508
   });
509
#else
510
   BOTAN_UNUSED(cert, key, index, out, out_len);
511
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
512
#endif
513
}
514

515
int botan_x509_cert_get_subject_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
516
#if defined(BOTAN_HAS_X509_CERTIFICATES)
517
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
518
      if(Botan::any_null_pointers(key, count)) {
519
         return BOTAN_FFI_ERROR_NULL_POINTER;
520
      }
521

522
      *count = c.subject_info(key).size();
523
      return BOTAN_FFI_SUCCESS;
524
   });
525
#else
526
   BOTAN_UNUSED(cert, key, count);
527
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
528
#endif
529
}
530

531
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
532
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
533
}
534

535
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
536
#if defined(BOTAN_HAS_X509_CERTIFICATES)
537
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
538
#else
539
   BOTAN_UNUSED(cert, ctx, view);
540
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
541
#endif
542
}
543

544
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
545
#if defined(BOTAN_HAS_X509_CERTIFICATES)
546
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
547
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
548
      if(c.allowed_usage(k)) {
549
         return BOTAN_FFI_SUCCESS;
550
      }
551
      return 1;
552
   });
553
#else
554
   BOTAN_UNUSED(cert, key_usage);
555
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
556
#endif
557
}
558

559
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
560
#if defined(BOTAN_HAS_X509_CERTIFICATES)
561
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
562
      if(Botan::any_null_pointers(oid)) {
563
         return BOTAN_FFI_ERROR_NULL_POINTER;
564
      }
565

566
      return c.has_ex_constraint(oid) ? 1 : 0;
567
   });
568
#else
569
   BOTAN_UNUSED(cert, oid);
570
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
571
#endif
572
}
573

574
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
575
#if defined(BOTAN_HAS_X509_CERTIFICATES)
576
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? 1 : 0; });
8✔
577
#else
578
   BOTAN_UNUSED(cert, oid);
579
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
580
#endif
581
}
582

583
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
38✔
584
#if defined(BOTAN_HAS_X509_CERTIFICATES)
585
   return BOTAN_FFI_CHECKED_DELETE(cert);
38✔
586
#else
587
   BOTAN_UNUSED(cert);
588
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
589
#endif
590
}
591

592
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
593
#if defined(BOTAN_HAS_X509_CERTIFICATES)
594
   return BOTAN_FFI_VISIT(cert,
6✔
595
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
596
#else
597
   BOTAN_UNUSED(cert, out, out_len);
598
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
599
#endif
600
}
601

602
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
603
#if defined(BOTAN_HAS_X509_CERTIFICATES)
604
   return BOTAN_FFI_VISIT(cert,
4✔
605
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().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_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
613
   if(time_since_epoch == nullptr) {
2✔
614
      return BOTAN_FFI_ERROR_NULL_POINTER;
615
   }
616
#if defined(BOTAN_HAS_X509_CERTIFICATES)
617
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
618
#else
619
   BOTAN_UNUSED(cert, time_since_epoch);
620
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
621
#endif
622
}
623

624
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
625
   if(time_since_epoch == nullptr) {
2✔
626
      return BOTAN_FFI_ERROR_NULL_POINTER;
627
   }
628
#if defined(BOTAN_HAS_X509_CERTIFICATES)
629
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
630
#else
631
   BOTAN_UNUSED(cert, time_since_epoch);
632
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
633
#endif
634
}
635

636
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
637
#if defined(BOTAN_HAS_X509_CERTIFICATES)
638
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
639
#else
640
   BOTAN_UNUSED(cert, out, out_len);
641
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
642
#endif
643
}
644

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

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

661
int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) {
3✔
662
   if(hash == nullptr) {
3✔
663
      return BOTAN_FFI_ERROR_NULL_POINTER;
664
   }
665
#if defined(BOTAN_HAS_X509_CERTIFICATES)
666
   // TODO(Botan4) change the type of out and remove this cast
667

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

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

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

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

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

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

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

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

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

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

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

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

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

767
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
768
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
769
      }
770

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

971
      if(intermediates_len > 0 && intermediates == nullptr) {
4✔
972
         return BOTAN_FFI_ERROR_NULL_POINTER;
973
      }
974
      if(trusted_len > 0 && trusted == nullptr) {
4✔
975
         return BOTAN_FFI_ERROR_NULL_POINTER;
976
      }
977

978
      std::vector<Botan::X509_Certificate> end_certs;
4✔
979
      end_certs.push_back(safe_get(cert));
4✔
980
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
981
         end_certs.push_back(safe_get(intermediates[i]));
5✔
982
      }
983

984
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
985
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
986
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
987

988
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
989
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
990
         trusted_roots.push_back(trusted_from_path.get());
×
991
      }
992

993
      if(trusted_len > 0) {
4✔
994
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
4✔
995
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
996
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
997
         }
998
         trusted_roots.push_back(trusted_extra.get());
4✔
999
      }
1000

1001
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
4✔
1002

1003
      auto validation_result =
4✔
1004
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
1005

1006
      if(result_code != nullptr) {
4✔
1007
         *result_code = static_cast<int>(validation_result.result());
4✔
1008
      }
1009

1010
      if(validation_result.successful_validation()) {
4✔
1011
         return 0;
1012
      } else {
1013
         return 1;
3✔
1014
      }
1015
   });
12✔
1016
#else
1017
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1018
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
1019
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1020
#endif
1021
}
1022

1023
const char* botan_x509_cert_validation_status(int code) {
11✔
1024
   if(code < 0) {
11✔
1025
      return nullptr;
1026
   }
1027

1028
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1029
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
1030
   return Botan::to_string(sc);
11✔
1031
#else
1032
   return nullptr;
1033
#endif
1034
}
1035

1036
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
1037
   if(Botan::any_null_pointers(crl_obj, crl_path)) {
7✔
1038
      return BOTAN_FFI_ERROR_NULL_POINTER;
1039
   }
1040

1041
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1042

1043
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
1044
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
1045
      return ffi_new_object(crl_obj, std::move(c));
14✔
1046
   });
14✔
1047

1048
#else
1049
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1050
#endif
1051
}
1052

1053
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
1054
   if(Botan::any_null_pointers(crl_obj, crl_bits)) {
1✔
1055
      return BOTAN_FFI_ERROR_NULL_POINTER;
1056
   }
1057

1058
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1059
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
1060
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
1061
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
1062
      return ffi_new_object(crl_obj, std::move(c));
1✔
1063
   });
3✔
1064
#else
1065
   BOTAN_UNUSED(crl_bits_len);
1066
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1067
#endif
1068
}
1069

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

1085
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
5✔
1086
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1087
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
10✔
1088
      const auto& time = c.next_update();
1089
      if(!time.time_is_set()) {
1090
         return BOTAN_FFI_ERROR_NO_VALUE;
1091
      }
1092

1093
      if(Botan::any_null_pointers(time_since_epoch)) {
1094
         return BOTAN_FFI_ERROR_NULL_POINTER;
1095
      }
1096

1097
      *time_since_epoch = c.next_update().time_since_epoch();
1098
      return BOTAN_FFI_SUCCESS;
1099
   });
1100
#else
1101
   BOTAN_UNUSED(crl, time_since_epoch);
1102
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1103
#endif
1104
}
1105

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

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

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

1170
      std::vector<Botan::CRL_Entry> entries;
3✔
1171
      entries.reserve(new_entries_len);
3✔
1172
      for(size_t i = 0; i < new_entries_len; i++) {
5✔
1173
         entries.push_back(safe_get(new_entries[i]));
2✔
1174
      }
1175

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

1187
int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key) {
3✔
1188
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1189
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) -> int { return c.check_signature(safe_get(key)) ? 1 : 0; });
6✔
1190
#else
1191
   BOTAN_UNUSED(crl, key);
1192
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1193
#endif
1194
}
1195

1196
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
13✔
1197
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1198
   return BOTAN_FFI_CHECKED_DELETE(crl);
13✔
1199
#else
1200
   BOTAN_UNUSED(crl);
1201
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1202
#endif
1203
}
1204

1205
int botan_x509_crl_view_binary_values(botan_x509_crl_t crl_obj,
3✔
1206
                                      botan_x509_value_type value_type,
1207
                                      size_t index,
1208
                                      botan_view_ctx ctx,
1209
                                      botan_view_bin_fn view_fn) {
1210
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1211
   if(index != 0) {
3✔
1212
      // As of now there are no multi-value binary entries.
1213
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1214
   }
1215

1216
   auto view = [=](std::span<const uint8_t> value) -> int {
4✔
1217
      if(value.empty()) {
1✔
1218
         return BOTAN_FFI_ERROR_NO_VALUE;
1219
      } else {
1220
         return invoke_view_callback(view_fn, ctx, value);
1✔
1221
      }
1222
   };
3✔
1223

1224
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
12✔
1225
      switch(value_type) {
1226
         case BOTAN_X509_SERIAL_NUMBER: {
1227
            if(const auto& crln = crl.crl_number_bigint()) {
1228
               // Previously CRL number was a fixed 4 byte value, continue this for small CRL numbers
1229
               const size_t view_bytes = std::min<size_t>(crln->bytes(), 4);
1230
               return view(crln->serialize<std::vector<uint8_t>>(view_bytes));
1231
            } else {
1232
               return BOTAN_FFI_ERROR_NO_VALUE;
1233
            }
1234
         }
1235
         case BOTAN_X509_ISSUER_DN_BITS:
1236
            return view(Botan::ASN1::put_in_sequence(crl.issuer_dn().get_bits()));
1237
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1238
            return view(crl.authority_key_id());
1239

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

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

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

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

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

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

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

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

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

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

1341
      if(Botan::any_null_pointers(entry)) {
1342
         return BOTAN_FFI_ERROR_NULL_POINTER;
1343
      }
1344

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

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

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

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

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

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

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

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

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

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

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

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

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

1457
      if(intermediates_len > 0 && intermediates == nullptr) {
20✔
1458
         return BOTAN_FFI_ERROR_NULL_POINTER;
1459
      }
1460
      if(trusted_len > 0 && trusted == nullptr) {
20✔
1461
         return BOTAN_FFI_ERROR_NULL_POINTER;
1462
      }
1463
      if(crls_len > 0 && crls == nullptr) {
20✔
1464
         return BOTAN_FFI_ERROR_NULL_POINTER;
1465
      }
1466

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

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

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

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

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

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

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

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

1508
      if(validation_result.successful_validation()) {
20✔
1509
         return 0;
1510
      } else {
1511
         return 1;
10✔
1512
      }
1513
   });
72✔
1514
#else
1515
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1516
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1517
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1518
#endif
1519
}
1520
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc