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

randombit / botan / 26864473078

02 Jun 2026 07:58PM UTC coverage: 89.389% (+0.02%) from 89.37%
26864473078

push

github

web-flow
Merge pull request #5639 from randombit/jack/sm4-hwaes-ks

Add hwaes hook for SM4 key schedule

110434 of 123543 relevant lines covered (89.39%)

11152828.24 hits per line

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

93.95
/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_addresses().size()) {
132✔
45
      auto itr = altnames.email_addresses().begin();
12✔
46
      std::advance(itr, index);
12✔
47
      return Botan::GeneralName::email(itr->to_string());
36✔
48
   }
49
   index -= altnames.email_addresses().size();
120✔
50

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

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

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

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

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

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

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

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

120
   BOTAN_ASSERT_UNREACHABLE();
×
121
}
122

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

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

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

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

167
}  // namespace
168

169
}  // namespace Botan_FFI
170

171
#endif
172

173
extern "C" {
174

175
using namespace Botan_FFI;
176

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

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

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

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

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

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

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

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

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

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

230
namespace {
231

232
#if defined(BOTAN_HAS_X509_CERTIFICATES)
233

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

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

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

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

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

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

280
#endif
281

282
}  // namespace
283

284
extern "C" {
285

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

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

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

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

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

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

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

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

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

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

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

387
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
388
   };
19✔
389

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

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

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

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

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

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

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

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

468
   *key = nullptr;
2✔
469

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

995
      if(intermediates_len > 0 && intermediates == nullptr) {
4✔
996
         return BOTAN_FFI_ERROR_NULL_POINTER;
997
      }
998
      if(trusted_len > 0 && trusted == nullptr) {
4✔
999
         return BOTAN_FFI_ERROR_NULL_POINTER;
1000
      }
1001

1002
      std::vector<Botan::X509_Certificate> end_certs;
4✔
1003
      end_certs.push_back(safe_get(cert));
4✔
1004
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
1005
         end_certs.push_back(safe_get(intermediates[i]));
5✔
1006
      }
1007

1008
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
1009
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
1010
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
1011

1012
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
1013
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
1014
         trusted_roots.push_back(trusted_from_path.get());
×
1015
      }
1016

1017
      if(trusted_len > 0) {
4✔
1018
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
4✔
1019
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
1020
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
1021
         }
1022
         trusted_roots.push_back(trusted_extra.get());
4✔
1023
      }
1024

1025
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
4✔
1026

1027
      auto validation_result =
4✔
1028
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
1029

1030
      if(result_code != nullptr) {
4✔
1031
         *result_code = static_cast<int>(validation_result.result());
4✔
1032
      }
1033

1034
      if(validation_result.successful_validation()) {
4✔
1035
         return 0;
1036
      } else {
1037
         return 1;
3✔
1038
      }
1039
   });
12✔
1040
#else
1041
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1042
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
1043
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1044
#endif
1045
}
1046

1047
const char* botan_x509_cert_validation_status(int code) {
11✔
1048
   if(code < 0) {
11✔
1049
      return nullptr;
1050
   }
1051

1052
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1053
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
1054
   return Botan::to_string(sc);
11✔
1055
#else
1056
   return nullptr;
1057
#endif
1058
}
1059

1060
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
1061
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
1062
      return BOTAN_FFI_ERROR_NULL_POINTER;
1063
   }
1064

1065
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1066

1067
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
1068
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
1069
      return ffi_new_object(crl_obj, std::move(c));
14✔
1070
   });
14✔
1071

1072
#else
1073
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1074
#endif
1075
}
1076

1077
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
1078
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
1079
      return BOTAN_FFI_ERROR_NULL_POINTER;
1080
   }
1081

1082
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1083
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
1084
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
1085
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
1086
      return ffi_new_object(crl_obj, std::move(c));
1✔
1087
   });
3✔
1088
#else
1089
   BOTAN_UNUSED(crl_bits_len);
1090
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1091
#endif
1092
}
1093

1094
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
1095
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1096
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
1097
      if(Botan::any_null_pointers(time_since_epoch)) {
1098
         return BOTAN_FFI_ERROR_NULL_POINTER;
1099
      }
1100
      *time_since_epoch = c.this_update().time_since_epoch();
1101
      return BOTAN_FFI_SUCCESS;
1102
   });
1103
#else
1104
   BOTAN_UNUSED(crl, time_since_epoch);
1105
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1106
#endif
1107
}
1108

1109
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
5✔
1110
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1111
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
10✔
1112
      const auto& time = c.next_update();
1113
      if(!time.time_is_set()) {
1114
         return BOTAN_FFI_ERROR_NO_VALUE;
1115
      }
1116

1117
      if(Botan::any_null_pointers(time_since_epoch)) {
1118
         return BOTAN_FFI_ERROR_NULL_POINTER;
1119
      }
1120

1121
      *time_since_epoch = c.next_update().time_since_epoch();
1122
      return BOTAN_FFI_SUCCESS;
1123
   });
1124
#else
1125
   BOTAN_UNUSED(crl, time_since_epoch);
1126
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1127
#endif
1128
}
1129

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

1156
int botan_x509_crl_entry_create(botan_x509_crl_entry_t* entry, botan_x509_cert_t cert, int reason_code) {
2✔
1157
   if(Botan::any_null_pointers(entry)) {
2✔
1158
      return BOTAN_FFI_ERROR_NULL_POINTER;
1159
   }
1160
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1161
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
1162
      return ffi_new_object(
4✔
1163
         entry, std::make_unique<Botan::CRL_Entry>(safe_get(cert), static_cast<Botan::CRL_Code>(reason_code)));
4✔
1164
   });
2✔
1165
#else
1166
   BOTAN_UNUSED(cert, reason_code);
1167
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1168
#endif
1169
}
1170

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

1194
      std::vector<Botan::CRL_Entry> entries;
3✔
1195
      entries.reserve(new_entries_len);
3✔
1196
      for(size_t i = 0; i < new_entries_len; i++) {
5✔
1197
         entries.push_back(safe_get(new_entries[i]));
2✔
1198
      }
1199

1200
      auto crl = std::make_unique<Botan::X509_CRL>(ca.update_crl(
6✔
1201
         safe_get(last_crl), entries, rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
6✔
1202
      return ffi_new_object(crl_obj, std::move(crl));
6✔
1203
   });
6✔
1204
#else
1205
   BOTAN_UNUSED(
1206
      last_crl, rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update, new_entries, new_entries_len);
1207
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1208
#endif
1209
}
1210

1211
int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key) {
3✔
1212
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1213
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) -> int { return c.check_signature(safe_get(key)) ? 1 : 0; });
6✔
1214
#else
1215
   BOTAN_UNUSED(crl, key);
1216
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1217
#endif
1218
}
1219

1220
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
13✔
1221
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1222
   return BOTAN_FFI_CHECKED_DELETE(crl);
13✔
1223
#else
1224
   BOTAN_UNUSED(crl);
1225
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1226
#endif
1227
}
1228

1229
int botan_x509_crl_view_binary_values(botan_x509_crl_t crl_obj,
3✔
1230
                                      botan_x509_value_type value_type,
1231
                                      size_t index,
1232
                                      botan_view_ctx ctx,
1233
                                      botan_view_bin_fn view_fn) {
1234
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1235
   if(index != 0) {
3✔
1236
      // As of now there are no multi-value binary entries.
1237
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1238
   }
1239

1240
   auto view = [=](std::span<const uint8_t> value) -> int {
4✔
1241
      if(value.empty()) {
1✔
1242
         return BOTAN_FFI_ERROR_NO_VALUE;
1243
      } else {
1244
         return invoke_view_callback(view_fn, ctx, value);
1✔
1245
      }
1246
   };
3✔
1247

1248
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
12✔
1249
      switch(value_type) {
1250
         case BOTAN_X509_SERIAL_NUMBER:
1251
            return view(Botan::store_be(crl.crl_number()));
1252
         case BOTAN_X509_ISSUER_DN_BITS:
1253
            return view(Botan::ASN1::put_in_sequence(crl.issuer_dn().get_bits()));
1254
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1255
            return view(crl.authority_key_id());
1256

1257
         case BOTAN_X509_TBS_DATA_BITS:
1258
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1259
         case BOTAN_X509_SIGNATURE_BITS:
1260
         case BOTAN_X509_DER_ENCODING:
1261
            return botan_x509_object_view_value(crl, value_type, index, ctx, view_fn);
1262

1263
         case BOTAN_X509_SUBJECT_DN_BITS:
1264
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1265
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1266
         case BOTAN_X509_PEM_ENCODING:
1267
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1268
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1269
         case BOTAN_X509_CA_ISSUERS_URLS:
1270
            return BOTAN_FFI_ERROR_NO_VALUE;
1271
      }
1272

1273
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1274
   });
1275
#else
1276
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view_fn);
1277
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1278
#endif
1279
}
1280

1281
int botan_x509_crl_view_binary_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1282
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1283
   return enumerator_count_values(count, [=](size_t index) {
1✔
1284
      return botan_x509_crl_view_binary_values(
1✔
1285
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1286
   });
1✔
1287
#else
1288
   BOTAN_UNUSED(crl_obj, value_type, count);
1289
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1290
#endif
1291
}
1292

1293
int botan_x509_crl_view_string_values(botan_x509_crl_t crl_obj,
3✔
1294
                                      botan_x509_value_type value_type,
1295
                                      size_t index,
1296
                                      botan_view_ctx ctx,
1297
                                      botan_view_str_fn view) {
1298
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1299
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
6✔
1300
      switch(value_type) {
1301
         case BOTAN_X509_PEM_ENCODING:
1302
            return botan_x509_object_view_value(crl, value_type, index, ctx, view);
1303

1304
         case BOTAN_X509_SERIAL_NUMBER:
1305
         case BOTAN_X509_SUBJECT_DN_BITS:
1306
         case BOTAN_X509_ISSUER_DN_BITS:
1307
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1308
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1309
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1310
         case BOTAN_X509_TBS_DATA_BITS:
1311
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1312
         case BOTAN_X509_SIGNATURE_BITS:
1313
         case BOTAN_X509_DER_ENCODING:
1314
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1315
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1316
         case BOTAN_X509_CA_ISSUERS_URLS:
1317
            return BOTAN_FFI_ERROR_NO_VALUE;
1318
      }
1319

1320
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1321
   });
1322
#else
1323
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view);
1324
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1325
#endif
1326
}
1327

1328
int botan_x509_crl_view_string_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1329
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1330
   return enumerator_count_values(count, [=](size_t index) {
1✔
1331
      return botan_x509_crl_view_string_values(
2✔
1332
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1333
   });
1✔
1334
#else
1335
   BOTAN_UNUSED(crl_obj, value_type, count);
1336
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1337
#endif
1338
}
1339

1340
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
1341
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1342
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
1343
#else
1344
   BOTAN_UNUSED(cert);
1345
   BOTAN_UNUSED(crl);
1346
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1347
#endif
1348
}
1349

1350
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
8✔
1351
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1352
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
20✔
1353
      const auto& entries = c.get_revoked();
1354
      if(index >= entries.size()) {
1355
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1356
      }
1357

1358
      if(Botan::any_null_pointers(entry)) {
1359
         return BOTAN_FFI_ERROR_NULL_POINTER;
1360
      }
1361

1362
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
1363
   });
1364
#else
1365
   BOTAN_UNUSED(crl, index, entry);
1366
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1367
#endif
1368
}
1369

1370
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
4✔
1371
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1372
   if(Botan::any_null_pointers(count)) {
4✔
1373
      return BOTAN_FFI_ERROR_NULL_POINTER;
1374
   }
1375

1376
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
8✔
1377
#else
1378
   BOTAN_UNUSED(crl, count);
1379
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1380
#endif
1381
}
1382

1383
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
6✔
1384
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1385
   return BOTAN_FFI_CHECKED_DELETE(entry);
6✔
1386
#else
1387
   BOTAN_UNUSED(entry);
1388
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1389
#endif
1390
}
1391

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

1399
      *reason_code = static_cast<int>(e.reason_code());
1400
      return BOTAN_FFI_SUCCESS;
1401
   });
1402
#else
1403
   BOTAN_UNUSED(entry, reason_code);
1404
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1405
#endif
1406
}
1407

1408
int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) {
3✔
1409
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1410
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1411
      if(Botan::any_null_pointers(serial_number)) {
1412
         return BOTAN_FFI_ERROR_NULL_POINTER;
1413
      }
1414

1415
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
1416
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
1417
   });
1418
#else
1419
   BOTAN_UNUSED(entry, serial_number);
1420
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1421
#endif
1422
}
1423

1424
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
1425
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1426
   return BOTAN_FFI_VISIT(
2✔
1427
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
1428
#else
1429
   BOTAN_UNUSED(entry, ctx, view);
1430
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1431
#endif
1432
}
1433

1434
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
3✔
1435
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1436
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1437
      if(Botan::any_null_pointers(time_since_epoch)) {
1438
         return BOTAN_FFI_ERROR_NULL_POINTER;
1439
      }
1440

1441
      *time_since_epoch = e.expire_time().time_since_epoch();
1442
      return BOTAN_FFI_SUCCESS;
1443
   });
1444
#else
1445
   BOTAN_UNUSED(entry, time_since_epoch);
1446
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1447
#endif
1448
}
1449

1450
int botan_x509_cert_verify_with_crl(int* result_code,
20✔
1451
                                    botan_x509_cert_t cert,
1452
                                    const botan_x509_cert_t* intermediates,
1453
                                    size_t intermediates_len,
1454
                                    const botan_x509_cert_t* trusted,
1455
                                    size_t trusted_len,
1456
                                    const botan_x509_crl_t* crls,
1457
                                    size_t crls_len,
1458
                                    const char* trusted_path,
1459
                                    size_t required_strength,
1460
                                    const char* hostname_cstr,
1461
                                    uint64_t reference_time) {
1462
   if(required_strength == 0) {
20✔
1463
      required_strength = 110;
10✔
1464
   }
1465

1466
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1467
   return ffi_guard_thunk(__func__, [=]() -> int {
20✔
1468
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
22✔
1469
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
20✔
1470
      const auto validation_time = reference_time == 0
20✔
1471
                                      ? std::chrono::system_clock::now()
20✔
1472
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1473

1474
      if(intermediates_len > 0 && intermediates == nullptr) {
20✔
1475
         return BOTAN_FFI_ERROR_NULL_POINTER;
1476
      }
1477
      if(trusted_len > 0 && trusted == nullptr) {
20✔
1478
         return BOTAN_FFI_ERROR_NULL_POINTER;
1479
      }
1480
      if(crls_len > 0 && crls == nullptr) {
20✔
1481
         return BOTAN_FFI_ERROR_NULL_POINTER;
1482
      }
1483

1484
      std::vector<Botan::X509_Certificate> end_certs;
20✔
1485
      end_certs.push_back(safe_get(cert));
20✔
1486
      for(size_t i = 0; i != intermediates_len; ++i) {
38✔
1487
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1488
      }
1489

1490
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
20✔
1491
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
20✔
1492
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
20✔
1493
      std::vector<Botan::Certificate_Store*> trusted_roots;
20✔
1494

1495
      if(trusted_path != nullptr && *trusted_path != 0) {
20✔
1496
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1497
         trusted_roots.push_back(trusted_from_path.get());
2✔
1498
      }
1499

1500
      if(trusted_len > 0) {
20✔
1501
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
17✔
1502
         for(size_t i = 0; i != trusted_len; ++i) {
34✔
1503
            trusted_extra->add_certificate(safe_get(trusted[i]));
17✔
1504
         }
1505
         trusted_roots.push_back(trusted_extra.get());
17✔
1506
      }
1507

1508
      if(crls_len > 0) {
20✔
1509
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
13✔
1510
         for(size_t i = 0; i != crls_len; ++i) {
29✔
1511
            trusted_crls->add_crl(safe_get(crls[i]));
16✔
1512
         }
1513
         trusted_roots.push_back(trusted_crls.get());
13✔
1514
      }
1515

1516
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
20✔
1517

1518
      auto validation_result =
20✔
1519
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
20✔
1520

1521
      if(result_code != nullptr) {
20✔
1522
         *result_code = static_cast<int>(validation_result.result());
20✔
1523
      }
1524

1525
      if(validation_result.successful_validation()) {
20✔
1526
         return 0;
1527
      } else {
1528
         return 1;
10✔
1529
      }
1530
   });
72✔
1531
#else
1532
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1533
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1534
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1535
#endif
1536
}
1537
}
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