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

randombit / botan / 22570762269

02 Mar 2026 07:15AM UTC coverage: 90.317% (+0.009%) from 90.308%
22570762269

push

github

web-flow
Merge pull request #5231 from Rohde-Schwarz/feature/multiple_ocsp_responders

X509: Multiple OCSP Responders

103503 of 114600 relevant lines covered (90.32%)

11810303.81 hits per line

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

95.06
/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_pkey.h>
11
#include <botan/internal/ffi_util.h>
12
#include <memory>
13

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

26
#if defined(BOTAN_HAS_X509_CERTIFICATES)
27

28
namespace Botan_FFI {
29

30
namespace {
31

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

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

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

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

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

76
   return std::nullopt;
12✔
77
}
78

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

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

110
   BOTAN_ASSERT_UNREACHABLE();
×
111
}
112

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

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

145
}  // namespace
146

147
}  // namespace Botan_FFI
148

149
#endif
150

151
extern "C" {
152

153
using namespace Botan_FFI;
154

155
#if defined(BOTAN_HAS_X509_CERTIFICATES)
156

157
BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
32✔
158
BOTAN_FFI_DECLARE_STRUCT(botan_x509_general_name_struct, Botan::GeneralName, 0x563654FD);
198✔
159

160
#endif
161

162
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
31✔
163
   if(cert_obj == nullptr || cert_path == nullptr) {
31✔
164
      return BOTAN_FFI_ERROR_NULL_POINTER;
165
   }
166

167
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
168

169
   return ffi_guard_thunk(__func__, [=]() -> int {
31✔
170
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
31✔
171
      return ffi_new_object(cert_obj, std::move(c));
31✔
172
   });
62✔
173

174
#else
175
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
176
#endif
177
}
178

179
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
180
   if(cert_obj == nullptr) {
1✔
181
      return BOTAN_FFI_ERROR_NULL_POINTER;
182
   }
183

184
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
185

186
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
187
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
188
      return ffi_new_object(cert_obj, std::move(c));
1✔
189
   });
2✔
190

191
#else
192
   BOTAN_UNUSED(cert);
193
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
194
#endif
195
}
196

197
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
198
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
199
      return BOTAN_FFI_ERROR_NULL_POINTER;
200
   }
201

202
#if defined(BOTAN_HAS_X509_CERTIFICATES)
203
   return ffi_guard_thunk(__func__, [=]() -> int {
×
204
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
205
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
206
      return ffi_new_object(cert_obj, std::move(c));
×
207
   });
×
208
#else
209
   BOTAN_UNUSED(cert_bits_len);
210
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
211
#endif
212
}
213
}
214

215
namespace {
216

217
#if defined(BOTAN_HAS_X509_CERTIFICATES)
218

219
int botan_x509_object_view_value(const Botan::X509_Object& object,
6✔
220
                                 botan_x509_value_type value_type,
221
                                 size_t index,
222
                                 botan_view_ctx ctx,
223
                                 botan_view_str_fn view_fn) {
224
   if(index != 0) {
6✔
225
      // As of now there are no multi-value generic string entries.
226
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
227
   }
228

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

231
   switch(value_type) {
4✔
232
      case BOTAN_X509_PEM_ENCODING:
4✔
233
         return view(object.PEM_encode());
8✔
234
      default:
×
235
         BOTAN_ASSERT_UNREACHABLE(); /* called with unexpected (non-generic) value_type */
×
236
   }
237
}
238

239
int botan_x509_object_view_value(const Botan::X509_Object& object,
8✔
240
                                 botan_x509_value_type value_type,
241
                                 size_t index,
242
                                 botan_view_ctx ctx,
243
                                 botan_view_bin_fn view_fn) {
244
   if(index != 0) {
8✔
245
      // As of now there are no multi-value generic binary entries.
246
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
247
   }
248

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

251
   switch(value_type) {
8✔
252
      case BOTAN_X509_TBS_DATA_BITS:
2✔
253
         return view(object.tbs_data());
6✔
254
      case BOTAN_X509_SIGNATURE_SCHEME_BITS:
2✔
255
         return view(object.signature_algorithm().BER_encode());
6✔
256
      case BOTAN_X509_SIGNATURE_BITS:
2✔
257
         return view(object.signature());
10✔
258
      case BOTAN_X509_DER_ENCODING:
2✔
259
         return view(object.BER_encode());
6✔
260
      default:
×
261
         BOTAN_ASSERT_UNREACHABLE(); /* called with unexpected (non-generic) value_type */
×
262
   }
263
}
264

265
#endif
266

267
}  // namespace
268

269
extern "C" {
270

271
int botan_x509_cert_view_binary_values(botan_x509_cert_t cert,
22✔
272
                                       botan_x509_value_type value_type,
273
                                       size_t index,
274
                                       botan_view_ctx ctx,
275
                                       botan_view_bin_fn view_fn) {
276
#if defined(BOTAN_HAS_X509_CERTIFICATES)
277
   if(index != 0) {
22✔
278
      // As of now there are no multi-value binary entries.
279
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
280
   }
281

282
   auto view = [=](std::span<const uint8_t> value) -> int {
18✔
283
      if(value.empty()) {
5✔
284
         return BOTAN_FFI_ERROR_NO_VALUE;
285
      } else {
286
         return invoke_view_callback(view_fn, ctx, value);
4✔
287
      }
288
   };
13✔
289

290
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
39✔
291
      switch(value_type) {
292
         case BOTAN_X509_SERIAL_NUMBER:
293
            return view(c.serial_number());
294
         case BOTAN_X509_SUBJECT_DN_BITS:
295
            return view(c.raw_subject_dn());
296
         case BOTAN_X509_ISSUER_DN_BITS:
297
            return view(c.raw_issuer_dn());
298
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
299
            return view(c.subject_key_id());
300
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
301
            return view(c.authority_key_id());
302
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
303
            return view(c.subject_public_key_info());
304

305
         case BOTAN_X509_TBS_DATA_BITS:
306
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
307
         case BOTAN_X509_SIGNATURE_BITS:
308
         case BOTAN_X509_DER_ENCODING:
309
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
310

311
         case BOTAN_X509_PEM_ENCODING:
312
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
313
         case BOTAN_X509_OCSP_RESPONDER_URLS:
314
         case BOTAN_X509_CA_ISSUERS_URLS:
315
            return BOTAN_FFI_ERROR_NO_VALUE;
316
      }
317

318
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
319
   });
320
#else
321
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
322
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
323
#endif
324
}
325

326
int botan_x509_cert_view_binary_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
5✔
327
#if defined(BOTAN_HAS_X509_CERTIFICATES)
328
   return enumerator_count_values(count, [=](size_t index) {
5✔
329
      return botan_x509_cert_view_binary_values(
10✔
330
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
331
   });
5✔
332
#else
333
   BOTAN_UNUSED(cert, value_type, count);
334
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
335
#endif
336
}
337

338
int botan_x509_cert_view_string_values(botan_x509_cert_t cert,
19✔
339
                                       botan_x509_value_type value_type,
340
                                       size_t index,
341
                                       botan_view_ctx ctx,
342
                                       botan_view_str_fn view_fn) {
343
#if defined(BOTAN_HAS_X509_CERTIFICATES)
344
   auto enumerate = [view_fn, ctx](auto values, size_t idx) -> int {
10✔
345
      if(idx >= values.size()) {
10✔
346
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
347
      } else {
348
         return invoke_view_callback(view_fn, ctx, values[idx]);
6✔
349
      }
350
   };
19✔
351

352
   auto enumerate_crl_distribution_points = [view_fn, ctx](const Botan::X509_Certificate& c, size_t idx) -> int {
25✔
353
      const auto* crl_dp_ext =
6✔
354
         c.v3_extensions().get_extension_object_as<Botan::Cert_Extension::CRL_Distribution_Points>();
12✔
355
      if(crl_dp_ext == nullptr) {
6✔
356
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;  // essentially an empty list
357
      }
358

359
      const auto& dps = crl_dp_ext->distribution_points();
5✔
360
      for(size_t i = idx; const auto& dp : dps) {
6✔
361
         const auto& uris = dp.point().uris();
5✔
362
         if(i >= uris.size()) {
5✔
363
            i -= uris.size();
1✔
364
            continue;
1✔
365
         }
366

367
         auto itr = uris.begin();
4✔
368
         std::advance(itr, i);
4✔
369
         return invoke_view_callback(view_fn, ctx, *itr);
8✔
370
      }
371

372
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
373
   };
19✔
374

375
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
38✔
376
      switch(value_type) {
377
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
378
            return enumerate_crl_distribution_points(c, index);
379
         case BOTAN_X509_OCSP_RESPONDER_URLS:
380
            return enumerate(c.ocsp_responders(), index);
381
         case BOTAN_X509_CA_ISSUERS_URLS:
382
            return enumerate(c.ca_issuers(), index);
383
         case BOTAN_X509_PEM_ENCODING:
384
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
385

386
         case BOTAN_X509_SERIAL_NUMBER:
387
         case BOTAN_X509_SUBJECT_DN_BITS:
388
         case BOTAN_X509_ISSUER_DN_BITS:
389
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
390
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
391
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
392
         case BOTAN_X509_TBS_DATA_BITS:
393
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
394
         case BOTAN_X509_SIGNATURE_BITS:
395
         case BOTAN_X509_DER_ENCODING:
396
            return BOTAN_FFI_ERROR_NO_VALUE;
397
      }
398

399
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
400
   });
401
#else
402
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
403
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
404
#endif
405
}
406

407
int botan_x509_cert_view_string_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
4✔
408
#if defined(BOTAN_HAS_X509_CERTIFICATES)
409
   return enumerator_count_values(count, [=](size_t index) {
4✔
410
      return botan_x509_cert_view_string_values(
10✔
411
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
412
   });
4✔
413
#else
414
   BOTAN_UNUSED(cert, value_type, count);
415
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
416
#endif
417
}
418

419
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
420
#if defined(BOTAN_HAS_X509_CERTIFICATES)
421
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? 1 : 0; });
4✔
422
#else
423
   BOTAN_UNUSED(cert);
424
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
425
#endif
426
}
427

428
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
429
#if defined(BOTAN_HAS_X509_CERTIFICATES)
430
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
431
      if(Botan::any_null_pointers(path_limit)) {
432
         return BOTAN_FFI_ERROR_NULL_POINTER;
433
      }
434

435
      if(const auto path_len = c.path_length_constraint()) {
436
         *path_limit = path_len.value();
437
         return BOTAN_FFI_SUCCESS;
438
      } else {
439
         return BOTAN_FFI_ERROR_NO_VALUE;
440
      }
441
   });
442
#else
443
   BOTAN_UNUSED(cert, path_limit);
444
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
445
#endif
446
}
447

448
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
449
   if(key == nullptr) {
2✔
450
      return BOTAN_FFI_ERROR_NULL_POINTER;
451
   }
452

453
   *key = nullptr;
2✔
454

455
#if defined(BOTAN_HAS_X509_CERTIFICATES)
456
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
457
      auto public_key = safe_get(cert).subject_public_key();
2✔
458
      return ffi_new_object(key, std::move(public_key));
2✔
459
   });
4✔
460
#else
461
   BOTAN_UNUSED(cert);
462
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
463
#endif
464
}
465

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

484
int botan_x509_cert_get_issuer_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
485
#if defined(BOTAN_HAS_X509_CERTIFICATES)
486
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
487
      if(Botan::any_null_pointers(count)) {
488
         return BOTAN_FFI_ERROR_NULL_POINTER;
489
      }
490

491
      *count = c.issuer_info(key).size();
492
      return BOTAN_FFI_SUCCESS;
493
   });
494
#else
495
   BOTAN_UNUSED(cert, key, count);
496
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
497
#endif
498
}
499

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

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

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

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

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

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

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

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

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

586
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
32✔
587
#if defined(BOTAN_HAS_X509_CERTIFICATES)
588
   return BOTAN_FFI_CHECKED_DELETE(cert);
32✔
589
#else
590
   BOTAN_UNUSED(cert);
591
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
592
#endif
593
}
594

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

605
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
606
#if defined(BOTAN_HAS_X509_CERTIFICATES)
607
   return BOTAN_FFI_VISIT(cert,
4✔
608
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
609
#else
610
   BOTAN_UNUSED(cert, out, out_len);
611
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
612
#endif
613
}
614

615
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
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 defined(BOTAN_HAS_X509_CERTIFICATES)
626
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
627
#else
628
   BOTAN_UNUSED(cert, time_since_epoch);
629
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
630
#endif
631
}
632

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

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

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

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

662
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
663
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
664
   });
665
#else
666
   BOTAN_UNUSED(cert, hash, out, out_len);
667
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
668
#endif
669
}
670

671
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
672
#if defined(BOTAN_HAS_X509_CERTIFICATES)
673
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
674
#else
675
   BOTAN_UNUSED(cert, out, out_len);
676
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
677
#endif
678
}
679

680
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
681
#if defined(BOTAN_HAS_X509_CERTIFICATES)
682
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
683
#else
684
   BOTAN_UNUSED(cert, out, out_len);
685
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
686
#endif
687
}
688

689
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
690
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
691
}
692

693
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
694
#if defined(BOTAN_HAS_X509_CERTIFICATES)
695
   return BOTAN_FFI_VISIT(cert,
6✔
696
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
697
#else
698
   BOTAN_UNUSED(cert, ctx, view);
699
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
700
#endif
701
}
702

703
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
704
#if defined(BOTAN_HAS_X509_CERTIFICATES)
705
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
706
      if(Botan::any_null_pointers(type)) {
707
         return BOTAN_FFI_ERROR_NULL_POINTER;
708
      }
709

710
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
711
      if(!mapped_type.has_value()) {
712
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
713
      }
714

715
      *type = mapped_type.value();
716
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
717
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
718
      }
719

720
      return BOTAN_FFI_SUCCESS;
721
   });
722
#else
723
   BOTAN_UNUSED(name, type);
724
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
725
#endif
726
}
727

728
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
729
                                              botan_view_ctx ctx,
730
                                              botan_view_str_fn view) {
731
#if defined(BOTAN_HAS_X509_CERTIFICATES)
732
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
733
      const auto type = to_botan_x509_general_name_types(n.type_code());
734
      if(!type) {
735
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
736
      }
737

738
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
739
         type != BOTAN_X509_IP_ADDRESS) {
740
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
741
      }
742

743
      return invoke_view_callback(view, ctx, n.name());
744
   });
745
#else
746
   BOTAN_UNUSED(name, ctx, view);
747
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
748
#endif
749
}
750

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

761
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
762
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
763
      }
764

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

773
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
774
#if defined(BOTAN_HAS_X509_CERTIFICATES)
775
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
776
#else
777
   BOTAN_UNUSED(name);
778
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
779
#endif
780
}
781

782
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
783
                                               size_t index,
784
                                               botan_x509_general_name_t* constraint) {
785
#if defined(BOTAN_HAS_X509_CERTIFICATES)
786
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
787
      if(Botan::any_null_pointers(constraint)) {
788
         return BOTAN_FFI_ERROR_NULL_POINTER;
789
      }
790

791
      const auto& constraints = c.name_constraints().permitted();
792
      if(index >= constraints.size()) {
793
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
794
      }
795

796
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
797
   });
798
#else
799
   BOTAN_UNUSED(cert, index, constraint);
800
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
801
#endif
802
}
803

804
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
805
#if defined(BOTAN_HAS_X509_CERTIFICATES)
806
   if(Botan::any_null_pointers(count)) {
1✔
807
      return BOTAN_FFI_ERROR_NULL_POINTER;
808
   }
809

810
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
811
#else
812
   BOTAN_UNUSED(cert, count);
813
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
814
#endif
815
}
816

817
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
818
                                              size_t index,
819
                                              botan_x509_general_name_t* constraint) {
820
#if defined(BOTAN_HAS_X509_CERTIFICATES)
821
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
822
      if(Botan::any_null_pointers(constraint)) {
823
         return BOTAN_FFI_ERROR_NULL_POINTER;
824
      }
825

826
      const auto& constraints = c.name_constraints().excluded();
827
      if(index >= constraints.size()) {
828
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
829
      }
830

831
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
832
   });
833
#else
834
   BOTAN_UNUSED(cert, index, constraint);
835
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
836
#endif
837
}
838

839
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
840
#if defined(BOTAN_HAS_X509_CERTIFICATES)
841
   if(Botan::any_null_pointers(count)) {
1✔
842
      return BOTAN_FFI_ERROR_NULL_POINTER;
843
   }
844

845
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
846
#else
847
   BOTAN_UNUSED(cert, count);
848
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
849
#endif
850
}
851

852
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
853
                                              size_t index,
854
                                              botan_x509_general_name_t* alt_name) {
855
#if defined(BOTAN_HAS_X509_CERTIFICATES)
856
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
857
      if(Botan::any_null_pointers(alt_name)) {
858
         return BOTAN_FFI_ERROR_NULL_POINTER;
859
      }
860

861
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
862
         return BOTAN_FFI_ERROR_NO_VALUE;
863
      }
864

865
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
866
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
867
      }
868

869
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
870
   });
871
#else
872
   BOTAN_UNUSED(cert, index, alt_name);
873
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
874
#endif
875
}
876

877
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
878
#if defined(BOTAN_HAS_X509_CERTIFICATES)
879
   if(Botan::any_null_pointers(count)) {
6✔
880
      return BOTAN_FFI_ERROR_NULL_POINTER;
881
   }
882

883
   return BOTAN_FFI_VISIT(
12✔
884
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
885
#else
886
   BOTAN_UNUSED(cert, count);
887
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
888
#endif
889
}
890

891
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
892
                                             size_t index,
893
                                             botan_x509_general_name_t* alt_name) {
894
#if defined(BOTAN_HAS_X509_CERTIFICATES)
895
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
896
      if(Botan::any_null_pointers(alt_name)) {
897
         return BOTAN_FFI_ERROR_NULL_POINTER;
898
      }
899

900
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
901
         return BOTAN_FFI_ERROR_NO_VALUE;
902
      }
903

904
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
905
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
906
      }
907

908
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
909
   });
910
#else
911
   BOTAN_UNUSED(cert, index, alt_name);
912
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
913
#endif
914
}
915

916
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
917
#if defined(BOTAN_HAS_X509_CERTIFICATES)
918
   if(Botan::any_null_pointers(count)) {
6✔
919
      return BOTAN_FFI_ERROR_NULL_POINTER;
920
   }
921

922
   return BOTAN_FFI_VISIT(
12✔
923
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.issuer_alt_name()); });
924
#else
925
   BOTAN_UNUSED(cert, count);
926
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
927
#endif
928
}
929

930
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
931
   if(hostname == nullptr) {
6✔
932
      return BOTAN_FFI_ERROR_NULL_POINTER;
933
   }
934

935
#if defined(BOTAN_HAS_X509_CERTIFICATES)
936
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
937
#else
938
   BOTAN_UNUSED(cert);
939
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
940
#endif
941
}
942

943
int botan_x509_cert_verify(int* result_code,
4✔
944
                           botan_x509_cert_t cert,
945
                           const botan_x509_cert_t* intermediates,
946
                           size_t intermediates_len,
947
                           const botan_x509_cert_t* trusted,
948
                           size_t trusted_len,
949
                           const char* trusted_path,
950
                           size_t required_strength,
951
                           const char* hostname_cstr,
952
                           uint64_t reference_time) {
953
   if(required_strength == 0) {
4✔
954
      required_strength = 110;
3✔
955
   }
956

957
#if defined(BOTAN_HAS_X509_CERTIFICATES)
958
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
959
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
960
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
961
      const auto validation_time = reference_time == 0
4✔
962
                                      ? std::chrono::system_clock::now()
4✔
963
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
964

965
      std::vector<Botan::X509_Certificate> end_certs;
4✔
966
      end_certs.push_back(safe_get(cert));
4✔
967
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
968
         end_certs.push_back(safe_get(intermediates[i]));
5✔
969
      }
970

971
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
972
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
973
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
974

975
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
976
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
977
         trusted_roots.push_back(trusted_from_path.get());
×
978
      }
979

980
      if(trusted_len > 0) {
4✔
981
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
982
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
983
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
984
         }
985
         trusted_roots.push_back(trusted_extra.get());
4✔
986
      }
987

988
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
989

990
      auto validation_result =
4✔
991
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
992

993
      if(result_code != nullptr) {
4✔
994
         *result_code = static_cast<int>(validation_result.result());
4✔
995
      }
996

997
      if(validation_result.successful_validation()) {
4✔
998
         return 0;
999
      } else {
1000
         return 1;
3✔
1001
      }
1002
   });
4✔
1003
#else
1004
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1005
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
1006
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1007
#endif
1008
}
1009

1010
const char* botan_x509_cert_validation_status(int code) {
11✔
1011
   if(code < 0) {
11✔
1012
      return nullptr;
1013
   }
1014

1015
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1016
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
1017
   return Botan::to_string(sc);
11✔
1018
#else
1019
   return nullptr;
1020
#endif
1021
}
1022

1023
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1024

1025
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
8✔
1026
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_entry_struct, Botan::CRL_Entry, 0x4EAA5346);
1✔
1027

1028
#endif
1029

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

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

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

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

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

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

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

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

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

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

1100
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
8✔
1101
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1102
   return BOTAN_FFI_CHECKED_DELETE(crl);
8✔
1103
#else
1104
   BOTAN_UNUSED(crl);
1105
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1106
#endif
1107
}
1108

1109
int botan_x509_crl_view_binary_values(botan_x509_crl_t crl_obj,
3✔
1110
                                      botan_x509_value_type value_type,
1111
                                      size_t index,
1112
                                      botan_view_ctx ctx,
1113
                                      botan_view_bin_fn view_fn) {
1114
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1115
   if(index != 0) {
3✔
1116
      // As of now there are no multi-value binary entries.
1117
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1118
   }
1119

1120
   auto view = [=](std::span<const uint8_t> value) -> int {
4✔
1121
      if(value.empty()) {
1✔
1122
         return BOTAN_FFI_ERROR_NO_VALUE;
1123
      } else {
1124
         return invoke_view_callback(view_fn, ctx, value);
1✔
1125
      }
1126
   };
3✔
1127

1128
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
12✔
1129
      switch(value_type) {
1130
         case BOTAN_X509_SERIAL_NUMBER:
1131
            return view(Botan::store_be(crl.crl_number()));
1132
         case BOTAN_X509_ISSUER_DN_BITS:
1133
            return view(Botan::ASN1::put_in_sequence(crl.issuer_dn().get_bits()));
1134
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1135
            return view(crl.authority_key_id());
1136

1137
         case BOTAN_X509_TBS_DATA_BITS:
1138
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1139
         case BOTAN_X509_SIGNATURE_BITS:
1140
         case BOTAN_X509_DER_ENCODING:
1141
            return botan_x509_object_view_value(crl, value_type, index, ctx, view_fn);
1142

1143
         case BOTAN_X509_SUBJECT_DN_BITS:
1144
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1145
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1146
         case BOTAN_X509_PEM_ENCODING:
1147
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1148
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1149
         case BOTAN_X509_CA_ISSUERS_URLS:
1150
            return BOTAN_FFI_ERROR_NO_VALUE;
1151
      }
1152

1153
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1154
   });
1155
#else
1156
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view_fn);
1157
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1158
#endif
1159
}
1160

1161
int botan_x509_crl_view_binary_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1162
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1163
   return enumerator_count_values(count, [=](size_t index) {
1✔
1164
      return botan_x509_crl_view_binary_values(
1✔
1165
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1166
   });
1✔
1167
#else
1168
   BOTAN_UNUSED(crl_obj, value_type, count);
1169
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1170
#endif
1171
}
1172

1173
int botan_x509_crl_view_string_values(botan_x509_crl_t crl_obj,
3✔
1174
                                      botan_x509_value_type value_type,
1175
                                      size_t index,
1176
                                      botan_view_ctx ctx,
1177
                                      botan_view_str_fn view) {
1178
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1179
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
6✔
1180
      switch(value_type) {
1181
         case BOTAN_X509_PEM_ENCODING:
1182
            return botan_x509_object_view_value(crl, value_type, index, ctx, view);
1183

1184
         case BOTAN_X509_SERIAL_NUMBER:
1185
         case BOTAN_X509_SUBJECT_DN_BITS:
1186
         case BOTAN_X509_ISSUER_DN_BITS:
1187
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1188
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1189
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1190
         case BOTAN_X509_TBS_DATA_BITS:
1191
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1192
         case BOTAN_X509_SIGNATURE_BITS:
1193
         case BOTAN_X509_DER_ENCODING:
1194
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1195
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1196
         case BOTAN_X509_CA_ISSUERS_URLS:
1197
            return BOTAN_FFI_ERROR_NO_VALUE;
1198
      }
1199

1200
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1201
   });
1202
#else
1203
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view);
1204
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1205
#endif
1206
}
1207

1208
int botan_x509_crl_view_string_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1209
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1210
   return enumerator_count_values(count, [=](size_t index) {
1✔
1211
      return botan_x509_crl_view_string_values(
2✔
1212
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1213
   });
1✔
1214
#else
1215
   BOTAN_UNUSED(crl_obj, value_type, count);
1216
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1217
#endif
1218
}
1219

1220
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
1221
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1222
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
1223
#else
1224
   BOTAN_UNUSED(cert);
1225
   BOTAN_UNUSED(crl);
1226
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1227
#endif
1228
}
1229

1230
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
3✔
1231
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1232
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
6✔
1233
      const auto& entries = c.get_revoked();
1234
      if(index >= entries.size()) {
1235
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1236
      }
1237

1238
      if(Botan::any_null_pointers(entry)) {
1239
         return BOTAN_FFI_ERROR_NULL_POINTER;
1240
      }
1241

1242
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
1243
   });
1244
#else
1245
   BOTAN_UNUSED(crl, index, entry);
1246
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1247
#endif
1248
}
1249

1250
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
2✔
1251
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1252
   if(Botan::any_null_pointers(count)) {
2✔
1253
      return BOTAN_FFI_ERROR_NULL_POINTER;
1254
   }
1255

1256
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
4✔
1257
#else
1258
   BOTAN_UNUSED(crl, count);
1259
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1260
#endif
1261
}
1262

1263
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
1✔
1264
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1265
   return BOTAN_FFI_CHECKED_DELETE(entry);
1✔
1266
#else
1267
   BOTAN_UNUSED(entry);
1268
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1269
#endif
1270
}
1271

1272
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
1✔
1273
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1274
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
1275
      if(Botan::any_null_pointers(reason_code)) {
1276
         return BOTAN_FFI_ERROR_NULL_POINTER;
1277
      }
1278

1279
      *reason_code = static_cast<int>(e.reason_code());
1280
      return BOTAN_FFI_SUCCESS;
1281
   });
1282
#else
1283
   BOTAN_UNUSED(entry, reason_code);
1284
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1285
#endif
1286
}
1287

1288
int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) {
1✔
1289
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1290
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
1291
      if(Botan::any_null_pointers(serial_number)) {
1292
         return BOTAN_FFI_ERROR_NULL_POINTER;
1293
      }
1294

1295
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
1296
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
1297
   });
1298
#else
1299
   BOTAN_UNUSED(entry, serial_number);
1300
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1301
#endif
1302
}
1303

1304
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
1305
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1306
   return BOTAN_FFI_VISIT(
2✔
1307
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
1308
#else
1309
   BOTAN_UNUSED(entry, ctx, view);
1310
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1311
#endif
1312
}
1313

1314
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
1✔
1315
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1316
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
1317
      if(Botan::any_null_pointers(time_since_epoch)) {
1318
         return BOTAN_FFI_ERROR_NULL_POINTER;
1319
      }
1320

1321
      *time_since_epoch = e.expire_time().time_since_epoch();
1322
      return BOTAN_FFI_SUCCESS;
1323
   });
1324
#else
1325
   BOTAN_UNUSED(entry, time_since_epoch);
1326
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1327
#endif
1328
}
1329

1330
int botan_x509_cert_verify_with_crl(int* result_code,
12✔
1331
                                    botan_x509_cert_t cert,
1332
                                    const botan_x509_cert_t* intermediates,
1333
                                    size_t intermediates_len,
1334
                                    const botan_x509_cert_t* trusted,
1335
                                    size_t trusted_len,
1336
                                    const botan_x509_crl_t* crls,
1337
                                    size_t crls_len,
1338
                                    const char* trusted_path,
1339
                                    size_t required_strength,
1340
                                    const char* hostname_cstr,
1341
                                    uint64_t reference_time) {
1342
   if(required_strength == 0) {
12✔
1343
      required_strength = 110;
2✔
1344
   }
1345

1346
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1347
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
1348
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
14✔
1349
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
12✔
1350
      const auto validation_time = reference_time == 0
12✔
1351
                                      ? std::chrono::system_clock::now()
12✔
1352
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1353

1354
      std::vector<Botan::X509_Certificate> end_certs;
12✔
1355
      end_certs.push_back(safe_get(cert));
12✔
1356
      for(size_t i = 0; i != intermediates_len; ++i) {
30✔
1357
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1358
      }
1359

1360
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
12✔
1361
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
12✔
1362
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
12✔
1363
      std::vector<Botan::Certificate_Store*> trusted_roots;
12✔
1364

1365
      if(trusted_path != nullptr && *trusted_path != 0) {
12✔
1366
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1367
         trusted_roots.push_back(trusted_from_path.get());
2✔
1368
      }
1369

1370
      if(trusted_len > 0) {
12✔
1371
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
18✔
1372
         for(size_t i = 0; i != trusted_len; ++i) {
18✔
1373
            trusted_extra->add_certificate(safe_get(trusted[i]));
9✔
1374
         }
1375
         trusted_roots.push_back(trusted_extra.get());
9✔
1376
      }
1377

1378
      if(crls_len > 0) {
12✔
1379
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
1380
         for(size_t i = 0; i != crls_len; ++i) {
13✔
1381
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
1382
         }
1383
         trusted_roots.push_back(trusted_crls.get());
5✔
1384
      }
1385

1386
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
24✔
1387

1388
      auto validation_result =
12✔
1389
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
12✔
1390

1391
      if(result_code != nullptr) {
12✔
1392
         *result_code = static_cast<int>(validation_result.result());
12✔
1393
      }
1394

1395
      if(validation_result.successful_validation()) {
12✔
1396
         return 0;
1397
      } else {
1398
         return 1;
8✔
1399
      }
1400
   });
14✔
1401
#else
1402
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1403
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1404
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1405
#endif
1406
}
1407
}
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