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

randombit / botan / 20957595341

13 Jan 2026 12:58PM UTC coverage: 90.472% (+0.02%) from 90.455%
20957595341

Pull #5231

github

web-flow
Merge 40273b6a1 into 8c072d7ea
Pull Request #5231: X509: Multiple OCSP Responders

102359 of 113139 relevant lines covered (90.47%)

12872144.28 hits per line

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

96.11
/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/internal/ffi_pkey.h>
10
#include <botan/internal/ffi_util.h>
11
#include <memory>
12

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

25
namespace {
26

27
/**
28
 * Given some enumerator-style function @p fn, count how many values it can
29
 * produce before returning BOTAN_FFI_ERROR_OUT_OF_RANGE. If the first call to
30
 * @p fn returns BOTAN_FFI_ERROR_NO_VALUE, zero is written to @p count.
31
 *
32
 * If this function returns BOTAN_FFI_SUCCESS, @p count contains the number of
33
 * values that can be enumerated. Otherwise, the value of @p count is undefined.
34
 */
35
template <std::invocable<size_t> EnumeratorT>
36
int enumerator_count_values(size_t* count, EnumeratorT fn) {
11✔
37
   if(Botan::any_null_pointers(count)) {
11✔
38
      return BOTAN_FFI_ERROR_NULL_POINTER;
39
   }
40

41
   *count = 0;
11✔
42
   for(;; ++(*count)) {
12✔
43
      const auto rc = fn(*count);
46✔
44
      switch(rc) {
23✔
45
         case BOTAN_FFI_ERROR_NO_VALUE:
46
         case BOTAN_FFI_ERROR_OUT_OF_RANGE:
47
            // hit the end of the enumeration
48
            return BOTAN_FFI_SUCCESS;
49
         case BOTAN_FFI_SUCCESS:
50
            // got a value, continue counting
51
            break;
52
         default:
53
            // unexpected error from enumerator function
54
            return rc;
55
      }
56
   }
57
}
58

59
}  // namespace
60

61
extern "C" {
62

63
using namespace Botan_FFI;
64

65
#if defined(BOTAN_HAS_X509_CERTIFICATES)
66

67
BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
32✔
68
BOTAN_FFI_DECLARE_STRUCT(botan_x509_general_name_struct, Botan::GeneralName, 0x563654FD);
198✔
69

70
#endif
71

72
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
31✔
73
   if(cert_obj == nullptr || cert_path == nullptr) {
31✔
74
      return BOTAN_FFI_ERROR_NULL_POINTER;
75
   }
76

77
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
78

79
   return ffi_guard_thunk(__func__, [=]() -> int {
31✔
80
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
31✔
81
      return ffi_new_object(cert_obj, std::move(c));
31✔
82
   });
62✔
83

84
#else
85
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
86
#endif
87
}
88

89
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
90
   if(cert_obj == nullptr) {
1✔
91
      return BOTAN_FFI_ERROR_NULL_POINTER;
92
   }
93

94
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
95

96
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
97
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
98
      return ffi_new_object(cert_obj, std::move(c));
1✔
99
   });
2✔
100

101
#else
102
   BOTAN_UNUSED(cert);
103
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
104
#endif
105
}
106

107
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
108
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
109
      return BOTAN_FFI_ERROR_NULL_POINTER;
110
   }
111

112
#if defined(BOTAN_HAS_X509_CERTIFICATES)
113
   return ffi_guard_thunk(__func__, [=]() -> int {
×
114
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
115
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
116
      return ffi_new_object(cert_obj, std::move(c));
×
117
   });
×
118
#else
119
   BOTAN_UNUSED(cert_bits_len);
120
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
121
#endif
122
}
123
}
124

125
namespace {
126

127
int botan_x509_object_view_value(const Botan::X509_Object& object,
6✔
128
                                 botan_x509_value_type value_type,
129
                                 size_t index,
130
                                 botan_view_ctx ctx,
131
                                 botan_view_str_fn view_fn) {
132
   if(index != 0) {
6✔
133
      // As of now there are no multi-value generic string entries.
134
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
135
   }
136

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

139
   switch(value_type) {
4✔
140
      case BOTAN_X509_PEM_ENCODING:
4✔
141
         return view(object.PEM_encode());
8✔
142
      default:
143
         return BOTAN_FFI_ERROR_INTERNAL_ERROR; /* called with unexpected (non-generic) value_type */
144
   }
145
}
146

147
int botan_x509_object_view_value(const Botan::X509_Object& object,
8✔
148
                                 botan_x509_value_type value_type,
149
                                 size_t index,
150
                                 botan_view_ctx ctx,
151
                                 botan_view_bin_fn view_fn) {
152
   if(index != 0) {
8✔
153
      // As of now there are no multi-value generic binary entries.
154
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
155
   }
156

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

159
   switch(value_type) {
8✔
160
      case BOTAN_X509_TBS_DATA_BITS:
2✔
161
         return view(object.tbs_data());
6✔
162
      case BOTAN_X509_SIGNATURE_SCHEME_BITS:
2✔
163
         return view(object.signature_algorithm().BER_encode());
6✔
164
      case BOTAN_X509_SIGNATURE_BITS:
2✔
165
         return view(object.signature());
10✔
166
      case BOTAN_X509_DER_ENCODING:
2✔
167
         return view(object.BER_encode());
6✔
168
      default:
169
         return BOTAN_FFI_ERROR_INTERNAL_ERROR; /* called with unexpected (non-generic) value_type */
170
   }
171
}
172

173
}  // namespace
174

175
extern "C" {
176

177
int botan_x509_cert_view_binary_values(botan_x509_cert_t cert,
22✔
178
                                       botan_x509_value_type value_type,
179
                                       size_t index,
180
                                       botan_view_ctx ctx,
181
                                       botan_view_bin_fn view_fn) {
182
#if defined(BOTAN_HAS_X509_CERTIFICATES)
183
   if(index != 0) {
22✔
184
      // As of now there are no multi-value binary entries.
185
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
186
   }
187

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

190
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
39✔
191
      switch(value_type) {
192
         case BOTAN_X509_SERIAL_NUMBER:
193
            return view(c.serial_number());
194
         case BOTAN_X509_SUBJECT_DN_BITS:
195
            return view(c.raw_subject_dn());
196
         case BOTAN_X509_ISSUER_DN_BITS:
197
            return view(c.raw_issuer_dn());
198
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
199
            return c.subject_key_id().empty() ? BOTAN_FFI_ERROR_NO_VALUE : view(c.subject_key_id());
200
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
201
            return c.authority_key_id().empty() ? BOTAN_FFI_ERROR_NO_VALUE : view(c.authority_key_id());
202
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
203
            return view(c.subject_public_key_info());
204

205
         case BOTAN_X509_TBS_DATA_BITS:
206
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
207
         case BOTAN_X509_SIGNATURE_BITS:
208
         case BOTAN_X509_DER_ENCODING:
209
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
210

211
         case BOTAN_X509_PEM_ENCODING:
212
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
213
         case BOTAN_X509_OCSP_RESPONDER_URLS:
214
         case BOTAN_X509_CA_ISSUERS_URLS:
215
            return BOTAN_FFI_ERROR_NO_VALUE;
216
      }
217

218
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
219
   });
220
#else
221
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
222
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
223
#endif
224
}
225

226
int botan_x509_cert_view_binary_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
5✔
227
   return enumerator_count_values(count, [=](size_t index) {
5✔
228
      return botan_x509_cert_view_binary_values(
10✔
229
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
230
   });
5✔
231
}
232

233
int botan_x509_cert_view_string_values(botan_x509_cert_t cert,
19✔
234
                                       botan_x509_value_type value_type,
235
                                       size_t index,
236
                                       botan_view_ctx ctx,
237
                                       botan_view_str_fn view_fn) {
238
#if defined(BOTAN_HAS_X509_CERTIFICATES)
239
   auto enumerate = [view_fn, ctx](auto values, size_t idx) -> int {
10✔
240
      if(idx >= values.size()) {
10✔
241
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
242
      } else {
243
         return invoke_view_callback(view_fn, ctx, values[idx]);
6✔
244
      }
245
   };
19✔
246

247
   auto enumerate_crl_distribution_points = [view_fn, ctx](const Botan::X509_Certificate& c, size_t idx) -> int {
25✔
248
      const auto* crl_dp_ext =
6✔
249
         c.v3_extensions().get_extension_object_as<Botan::Cert_Extension::CRL_Distribution_Points>();
12✔
250
      if(crl_dp_ext == nullptr) {
6✔
251
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;  // essentially an empty list
252
      }
253

254
      const auto& dps = crl_dp_ext->distribution_points();
5✔
255
      for(size_t i = idx; const auto& dp : dps) {
6✔
256
         const auto& uris = dp.point().uris();
5✔
257
         if(i >= uris.size()) {
5✔
258
            i -= uris.size();
1✔
259
            continue;
1✔
260
         }
261

262
         auto itr = uris.begin();
4✔
263
         std::advance(itr, i);
4✔
264
         return invoke_view_callback(view_fn, ctx, *itr);
8✔
265
      }
266

267
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
268
   };
19✔
269

270
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
38✔
271
      switch(value_type) {
272
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
273
            return enumerate_crl_distribution_points(c, index);
274
         case BOTAN_X509_OCSP_RESPONDER_URLS:
275
            return enumerate(c.ocsp_responders(), index);
276
         case BOTAN_X509_CA_ISSUERS_URLS:
277
            return enumerate(c.ca_issuers(), index);
278
         case BOTAN_X509_PEM_ENCODING:
279
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
280

281
         case BOTAN_X509_SERIAL_NUMBER:
282
         case BOTAN_X509_SUBJECT_DN_BITS:
283
         case BOTAN_X509_ISSUER_DN_BITS:
284
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
285
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
286
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
287
         case BOTAN_X509_TBS_DATA_BITS:
288
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
289
         case BOTAN_X509_SIGNATURE_BITS:
290
         case BOTAN_X509_DER_ENCODING:
291
            return BOTAN_FFI_ERROR_NO_VALUE;
292
      }
293

294
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
295
   });
296
#else
297
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
298
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
299
#endif
300
}
301

302
int botan_x509_cert_view_string_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
4✔
303
   return enumerator_count_values(count, [=](size_t index) {
4✔
304
      return botan_x509_cert_view_string_values(
10✔
305
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
306
   });
4✔
307
}
308

309
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
310
#if defined(BOTAN_HAS_X509_CERTIFICATES)
311
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? BOTAN_FFI_SUCCESS : 1; });
4✔
312
#else
313
   BOTAN_UNUSED(cert);
314
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
315
#endif
316
}
317

318
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
319
#if defined(BOTAN_HAS_X509_CERTIFICATES)
320
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
321
      if(Botan::any_null_pointers(path_limit)) {
322
         return BOTAN_FFI_ERROR_NULL_POINTER;
323
      }
324

325
      if(const auto path_len = c.path_length_constraint()) {
326
         *path_limit = path_len.value();
327
         return BOTAN_FFI_SUCCESS;
328
      } else {
329
         return BOTAN_FFI_ERROR_NO_VALUE;
330
      }
331
   });
332
#else
333
   BOTAN_UNUSED(cert, path_limit);
334
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
335
#endif
336
}
337

338
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
339
   if(key == nullptr) {
2✔
340
      return BOTAN_FFI_ERROR_NULL_POINTER;
341
   }
342

343
   *key = nullptr;
2✔
344

345
#if defined(BOTAN_HAS_X509_CERTIFICATES)
346
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
347
      auto public_key = safe_get(cert).subject_public_key();
2✔
348
      return ffi_new_object(key, std::move(public_key));
2✔
349
   });
4✔
350
#else
351
   BOTAN_UNUSED(cert);
352
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
353
#endif
354
}
355

356
int botan_x509_cert_get_issuer_dn(
8✔
357
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
358
#if defined(BOTAN_HAS_X509_CERTIFICATES)
359
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
360
      auto issuer_info = c.issuer_info(key);
361
      if(index < issuer_info.size()) {
362
         // TODO(Botan4) change the type of out and remove this cast
363
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
364
      } else {
365
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
366
      }
367
   });
368
#else
369
   BOTAN_UNUSED(cert, key, index, out, out_len);
370
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
371
#endif
372
}
373

374
int botan_x509_cert_get_issuer_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
375
#if defined(BOTAN_HAS_X509_CERTIFICATES)
376
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
377
      if(Botan::any_null_pointers(count)) {
378
         return BOTAN_FFI_ERROR_NULL_POINTER;
379
      }
380

381
      *count = c.issuer_info(key).size();
382
      return BOTAN_FFI_SUCCESS;
383
   });
384
#else
385
   BOTAN_UNUSED(cert, key, count);
386
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
387
#endif
388
}
389

390
int botan_x509_cert_get_subject_dn(
8✔
391
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
392
#if defined(BOTAN_HAS_X509_CERTIFICATES)
393
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
394
      auto subject_info = c.subject_info(key);
395
      if(index < subject_info.size()) {
396
         // TODO(Botan4) change the type of out and remove this cast
397
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
398
      } else {
399
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
400
      }
401
   });
402
#else
403
   BOTAN_UNUSED(cert, key, index, out, out_len);
404
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
405
#endif
406
}
407

408
int botan_x509_cert_get_subject_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
409
#if defined(BOTAN_HAS_X509_CERTIFICATES)
410
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
411
      if(Botan::any_null_pointers(count)) {
412
         return BOTAN_FFI_ERROR_NULL_POINTER;
413
      }
414

415
      *count = c.subject_info(key).size();
416
      return BOTAN_FFI_SUCCESS;
417
   });
418
#else
419
   BOTAN_UNUSED(cert, key, count);
420
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
421
#endif
422
}
423

424
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
425
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
426
}
427

428
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
429
#if defined(BOTAN_HAS_X509_CERTIFICATES)
430
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
431
#else
432
   BOTAN_UNUSED(cert, ctx, view);
433
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
434
#endif
435
}
436

437
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
438
#if defined(BOTAN_HAS_X509_CERTIFICATES)
439
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
440
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
441
      if(c.allowed_usage(k)) {
442
         return BOTAN_FFI_SUCCESS;
443
      }
444
      return 1;
445
   });
446
#else
447
   BOTAN_UNUSED(cert, key_usage);
448
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
449
#endif
450
}
451

452
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
453
#if defined(BOTAN_HAS_X509_CERTIFICATES)
454
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
455
      if(Botan::any_null_pointers(oid)) {
456
         return BOTAN_FFI_ERROR_NULL_POINTER;
457
      }
458

459
      return c.has_ex_constraint(oid) ? BOTAN_FFI_SUCCESS : 1;
460
   });
461
#else
462
   BOTAN_UNUSED(cert, oid);
463
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
464
#endif
465
}
466

467
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
468
#if defined(BOTAN_HAS_X509_CERTIFICATES)
469
   return BOTAN_FFI_VISIT(
8✔
470
      cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? BOTAN_FFI_SUCCESS : 1; });
471
#else
472
   BOTAN_UNUSED(cert, oid);
473
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
474
#endif
475
}
476

477
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
32✔
478
#if defined(BOTAN_HAS_X509_CERTIFICATES)
479
   return BOTAN_FFI_CHECKED_DELETE(cert);
32✔
480
#else
481
   BOTAN_UNUSED(cert);
482
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
483
#endif
484
}
485

486
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
487
#if defined(BOTAN_HAS_X509_CERTIFICATES)
488
   return BOTAN_FFI_VISIT(cert,
6✔
489
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
490
#else
491
   BOTAN_UNUSED(cert, out, out_len);
492
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
493
#endif
494
}
495

496
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
497
#if defined(BOTAN_HAS_X509_CERTIFICATES)
498
   return BOTAN_FFI_VISIT(cert,
4✔
499
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
500
#else
501
   BOTAN_UNUSED(cert, out, out_len);
502
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
503
#endif
504
}
505

506
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
507
#if defined(BOTAN_HAS_X509_CERTIFICATES)
508
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
509
#else
510
   BOTAN_UNUSED(cert, time_since_epoch);
511
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
512
#endif
513
}
514

515
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
516
#if defined(BOTAN_HAS_X509_CERTIFICATES)
517
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
518
#else
519
   BOTAN_UNUSED(cert, time_since_epoch);
520
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
521
#endif
522
}
523

524
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
525
#if defined(BOTAN_HAS_X509_CERTIFICATES)
526
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
527
#else
528
   BOTAN_UNUSED(cert, out, out_len);
529
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
530
#endif
531
}
532

533
int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) {
1✔
534
#if defined(BOTAN_HAS_X509_CERTIFICATES)
535
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
2✔
536
      if(Botan::any_null_pointers(serial_number)) {
537
         return BOTAN_FFI_ERROR_NULL_POINTER;
538
      }
539

540
      auto serial_bn = Botan::BigInt::from_bytes(c.serial_number());
541
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
542
   });
543
#else
544
   BOTAN_UNUSED(cert, serial_number);
545
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
546
#endif
547
}
548

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

553
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
554
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
555
   });
556
#else
557
   BOTAN_UNUSED(cert, hash, out, out_len);
558
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
559
#endif
560
}
561

562
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
563
#if defined(BOTAN_HAS_X509_CERTIFICATES)
564
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
565
#else
566
   BOTAN_UNUSED(cert, out, out_len);
567
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
568
#endif
569
}
570

571
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
572
#if defined(BOTAN_HAS_X509_CERTIFICATES)
573
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
574
#else
575
   BOTAN_UNUSED(cert, out, out_len);
576
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
577
#endif
578
}
579

580
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
581
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
582
}
583

584
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
585
#if defined(BOTAN_HAS_X509_CERTIFICATES)
586
   return BOTAN_FFI_VISIT(cert,
6✔
587
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
588
#else
589
   BOTAN_UNUSED(cert, ctx, view);
590
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
591
#endif
592
}
593
}
594

595
namespace {
596

597
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
301✔
598
   using Type = Botan::GeneralName::NameType;
301✔
599
   switch(gn_type) {
301✔
600
      case Type::Unknown:
1✔
601
         return std::nullopt;
1✔
602
      case Type::RFC822:
83✔
603
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
604
      case Type::DNS:
73✔
605
         return BOTAN_X509_DNS_NAME;
73✔
606
      case Type::URI:
28✔
607
         return BOTAN_X509_URI;
28✔
608
      case Type::DN:
95✔
609
         return BOTAN_X509_DIRECTORY_NAME;
95✔
610
      case Type::IPv4:
21✔
611
         return BOTAN_X509_IP_ADDRESS;
21✔
612
      case Type::Other:
×
613
         return BOTAN_X509_OTHER_NAME;
×
614
   }
615

616
   BOTAN_ASSERT_UNREACHABLE();
×
617
}
618

619
}  // namespace
620

621
extern "C" {
622

623
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
624
#if defined(BOTAN_HAS_X509_CERTIFICATES)
625
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
626
      if(Botan::any_null_pointers(type)) {
627
         return BOTAN_FFI_ERROR_NULL_POINTER;
628
      }
629

630
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
631
      if(!mapped_type.has_value()) {
632
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
633
      }
634

635
      *type = mapped_type.value();
636
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
637
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
638
      }
639

640
      return BOTAN_FFI_SUCCESS;
641
   });
642
#else
643
   BOTAN_UNUSED(name, type);
644
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
645
#endif
646
}
647

648
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
649
                                              botan_view_ctx ctx,
650
                                              botan_view_str_fn view) {
651
#if defined(BOTAN_HAS_X509_CERTIFICATES)
652
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
653
      const auto type = to_botan_x509_general_name_types(n.type_code());
654
      if(!type) {
655
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
656
      }
657

658
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
659
         type != BOTAN_X509_IP_ADDRESS) {
660
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
661
      }
662

663
      return invoke_view_callback(view, ctx, n.name());
664
   });
665
#else
666
   BOTAN_UNUSED(name, ctx, view);
667
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
668
#endif
669
}
670

671
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
672
                                              botan_view_ctx ctx,
673
                                              botan_view_bin_fn view) {
674
#if defined(BOTAN_HAS_X509_CERTIFICATES)
675
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
676
      const auto type = to_botan_x509_general_name_types(n.type_code());
677
      if(!type) {
678
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
679
      }
680

681
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
682
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
683
      }
684

685
      return invoke_view_callback(view, ctx, n.binary_name());
686
   });
687
#else
688
   BOTAN_UNUSED(name, ctx, view);
689
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
690
#endif
691
}
692

693
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
694
#if defined(BOTAN_HAS_X509_CERTIFICATES)
695
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
696
#else
697
   BOTAN_UNUSED(name);
698
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
699
#endif
700
}
701

702
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
703
                                               size_t index,
704
                                               botan_x509_general_name_t* constraint) {
705
#if defined(BOTAN_HAS_X509_CERTIFICATES)
706
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
707
      if(Botan::any_null_pointers(constraint)) {
708
         return BOTAN_FFI_ERROR_NULL_POINTER;
709
      }
710

711
      const auto& constraints = c.name_constraints().permitted();
712
      if(index >= constraints.size()) {
713
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
714
      }
715

716
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
717
   });
718
#else
719
   BOTAN_UNUSED(cert, index, constraint);
720
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
721
#endif
722
}
723

724
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
725
#if defined(BOTAN_HAS_X509_CERTIFICATES)
726
   if(Botan::any_null_pointers(count)) {
1✔
727
      return BOTAN_FFI_ERROR_NULL_POINTER;
728
   }
729

730
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
731
#else
732
   BOTAN_UNUSED(cert, count);
733
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
734
#endif
735
}
736

737
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
738
                                              size_t index,
739
                                              botan_x509_general_name_t* constraint) {
740
#if defined(BOTAN_HAS_X509_CERTIFICATES)
741
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
742
      if(Botan::any_null_pointers(constraint)) {
743
         return BOTAN_FFI_ERROR_NULL_POINTER;
744
      }
745

746
      const auto& constraints = c.name_constraints().excluded();
747
      if(index >= constraints.size()) {
748
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
749
      }
750

751
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
752
   });
753
#else
754
   BOTAN_UNUSED(cert, index, constraint);
755
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
756
#endif
757
}
758

759
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
760
#if defined(BOTAN_HAS_X509_CERTIFICATES)
761
   if(Botan::any_null_pointers(count)) {
1✔
762
      return BOTAN_FFI_ERROR_NULL_POINTER;
763
   }
764

765
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
766
#else
767
   BOTAN_UNUSED(cert, count);
768
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
769
#endif
770
}
771
}
772

773
namespace {
774

775
/**
776
 * As specified in RFC 5280 Section 4.2.1.6. alternative names essentially are a
777
 * collection of GeneralNames. This allows mapping a single entry of @p altnames
778
 * to a GeneralName by its @p index. If the index is out of range, std::nullopt
779
 * is returned.
780
 *
781
 * NOTE: if the set of alternative name types handled here is extended,
782
 *       count_general_names_in() must be updated accordingly!
783
 */
784
std::optional<Botan::GeneralName> extract_general_name_at(const Botan::AlternativeName& altnames, size_t index) {
132✔
785
   if(index < altnames.email().size()) {
132✔
786
      auto itr = altnames.email().begin();
12✔
787
      std::advance(itr, index);
12✔
788
      return Botan::GeneralName::email(*itr);
36✔
789
   }
790
   index -= altnames.email().size();
120✔
791

792
   if(index < altnames.dns().size()) {
120✔
793
      auto itr = altnames.dns().begin();
36✔
794
      std::advance(itr, index);
36✔
795
      return Botan::GeneralName::dns(*itr);
108✔
796
   }
797
   index -= altnames.dns().size();
84✔
798

799
   if(index < altnames.directory_names().size()) {
84✔
800
      auto itr = altnames.directory_names().begin();
36✔
801
      std::advance(itr, index);
36✔
802
      return Botan::GeneralName::directory_name(*itr);
108✔
803
   }
804
   index -= altnames.directory_names().size();
48✔
805

806
   if(index < altnames.uris().size()) {
48✔
807
      auto itr = altnames.uris().begin();
24✔
808
      std::advance(itr, index);
24✔
809
      return Botan::GeneralName::uri(*itr);
72✔
810
   }
811
   index -= altnames.uris().size();
24✔
812

813
   if(index < altnames.ipv4_address().size()) {
24✔
814
      auto itr = altnames.ipv4_address().begin();
12✔
815
      std::advance(itr, index);
12✔
816
      return Botan::GeneralName::ipv4_address(*itr);
36✔
817
   }
818

819
   return std::nullopt;
12✔
820
}
821

822
/**
823
 * Counts the total number of GeneralNames contained in the given
824
 * AlternativeName @p alt_names.
825
 *
826
 * NOTE: if the set of alternative name types handled here is extended,
827
 *       extract_general_name_at() must be updated accordingly!
828
 */
829
size_t count_general_names_in(const Botan::AlternativeName& alt_names) {
12✔
830
   return alt_names.email().size() + alt_names.dns().size() + alt_names.directory_names().size() +
12✔
831
          alt_names.uris().size() + alt_names.ipv4_address().size();
12✔
832
}
833

834
}  // namespace
835

836
extern "C" {
837

838
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
839
                                              size_t index,
840
                                              botan_x509_general_name_t* alt_name) {
841
#if defined(BOTAN_HAS_X509_CERTIFICATES)
842
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
843
      if(Botan::any_null_pointers(alt_name)) {
844
         return BOTAN_FFI_ERROR_NULL_POINTER;
845
      }
846

847
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
848
         return BOTAN_FFI_ERROR_NO_VALUE;
849
      }
850

851
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
852
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
853
      }
854

855
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
856
   });
857
#else
858
   BOTAN_UNUSED(cert, index, alt_name);
859
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
860
#endif
861
}
862

863
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
864
#if defined(BOTAN_HAS_X509_CERTIFICATES)
865
   if(Botan::any_null_pointers(count)) {
6✔
866
      return BOTAN_FFI_ERROR_NULL_POINTER;
867
   }
868

869
   return BOTAN_FFI_VISIT(
12✔
870
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
871
#else
872
   BOTAN_UNUSED(cert, count);
873
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
874
#endif
875
}
876

877
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
878
                                             size_t index,
879
                                             botan_x509_general_name_t* alt_name) {
880
#if defined(BOTAN_HAS_X509_CERTIFICATES)
881
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
882
      if(Botan::any_null_pointers(alt_name)) {
883
         return BOTAN_FFI_ERROR_NULL_POINTER;
884
      }
885

886
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
887
         return BOTAN_FFI_ERROR_NO_VALUE;
888
      }
889

890
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
891
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
892
      }
893

894
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
895
   });
896
#else
897
   BOTAN_UNUSED(cert, index, alt_name);
898
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
899
#endif
900
}
901

902
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
903
#if defined(BOTAN_HAS_X509_CERTIFICATES)
904
   if(Botan::any_null_pointers(count)) {
6✔
905
      return BOTAN_FFI_ERROR_NULL_POINTER;
906
   }
907

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

916
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
917
   if(hostname == nullptr) {
6✔
918
      return BOTAN_FFI_ERROR_NULL_POINTER;
919
   }
920

921
#if defined(BOTAN_HAS_X509_CERTIFICATES)
922
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
923
#else
924
   BOTAN_UNUSED(cert);
925
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
926
#endif
927
}
928

929
int botan_x509_cert_verify(int* result_code,
4✔
930
                           botan_x509_cert_t cert,
931
                           const botan_x509_cert_t* intermediates,
932
                           size_t intermediates_len,
933
                           const botan_x509_cert_t* trusted,
934
                           size_t trusted_len,
935
                           const char* trusted_path,
936
                           size_t required_strength,
937
                           const char* hostname_cstr,
938
                           uint64_t reference_time) {
939
   if(required_strength == 0) {
4✔
940
      required_strength = 110;
3✔
941
   }
942

943
#if defined(BOTAN_HAS_X509_CERTIFICATES)
944
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
945
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
946
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
947
      const auto validation_time = reference_time == 0
4✔
948
                                      ? std::chrono::system_clock::now()
4✔
949
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
950

951
      std::vector<Botan::X509_Certificate> end_certs;
4✔
952
      end_certs.push_back(safe_get(cert));
4✔
953
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
954
         end_certs.push_back(safe_get(intermediates[i]));
5✔
955
      }
956

957
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
958
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
959
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
960

961
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
962
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
963
         trusted_roots.push_back(trusted_from_path.get());
×
964
      }
965

966
      if(trusted_len > 0) {
4✔
967
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
968
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
969
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
970
         }
971
         trusted_roots.push_back(trusted_extra.get());
4✔
972
      }
973

974
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
975

976
      auto validation_result =
4✔
977
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
978

979
      if(result_code != nullptr) {
4✔
980
         *result_code = static_cast<int>(validation_result.result());
4✔
981
      }
982

983
      if(validation_result.successful_validation()) {
4✔
984
         return 0;
985
      } else {
986
         return 1;
3✔
987
      }
988
   });
4✔
989
#else
990
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
991
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
992
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
993
#endif
994
}
995

996
const char* botan_x509_cert_validation_status(int code) {
11✔
997
   if(code < 0) {
11✔
998
      return nullptr;
999
   }
1000

1001
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1002
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
1003
   return Botan::to_string(sc);
11✔
1004
#else
1005
   return nullptr;
1006
#endif
1007
}
1008

1009
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1010

1011
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
8✔
1012
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_entry_struct, Botan::CRL_Entry, 0x4EAA5346);
1✔
1013

1014
#endif
1015

1016
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
1017
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
1018
      return BOTAN_FFI_ERROR_NULL_POINTER;
1019
   }
1020

1021
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
1022

1023
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
1024
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
1025
      return ffi_new_object(crl_obj, std::move(c));
14✔
1026
   });
14✔
1027

1028
#else
1029
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1030
#endif
1031
}
1032

1033
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
1034
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
1035
      return BOTAN_FFI_ERROR_NULL_POINTER;
1036
   }
1037

1038
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1039
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
1040
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
1041
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
1042
      return ffi_new_object(crl_obj, std::move(c));
1✔
1043
   });
3✔
1044
#else
1045
   BOTAN_UNUSED(crl_bits_len);
1046
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1047
#endif
1048
}
1049

1050
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
1051
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1052
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
1053
      if(Botan::any_null_pointers(time_since_epoch)) {
1054
         return BOTAN_FFI_ERROR_NULL_POINTER;
1055
      }
1056
      *time_since_epoch = c.this_update().time_since_epoch();
1057
      return BOTAN_FFI_SUCCESS;
1058
   });
1059
#else
1060
   BOTAN_UNUSED(crl, time_since_epoch);
1061
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1062
#endif
1063
}
1064

1065
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
4✔
1066
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1067
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
8✔
1068
      const auto& time = c.next_update();
1069
      if(!time.time_is_set()) {
1070
         return BOTAN_FFI_ERROR_NO_VALUE;
1071
      }
1072

1073
      if(Botan::any_null_pointers(time_since_epoch)) {
1074
         return BOTAN_FFI_ERROR_NULL_POINTER;
1075
      }
1076

1077
      *time_since_epoch = c.next_update().time_since_epoch();
1078
      return BOTAN_FFI_SUCCESS;
1079
   });
1080
#else
1081
   BOTAN_UNUSED(crl, time_since_epoch);
1082
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1083
#endif
1084
}
1085

1086
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
8✔
1087
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1088
   return BOTAN_FFI_CHECKED_DELETE(crl);
8✔
1089
#else
1090
   BOTAN_UNUSED(crl);
1091
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1092
#endif
1093
}
1094

1095
int botan_x509_crl_view_binary_values(botan_x509_crl_t crl_obj,
3✔
1096
                                      botan_x509_value_type value_type,
1097
                                      size_t index,
1098
                                      botan_view_ctx ctx,
1099
                                      botan_view_bin_fn view_fn) {
1100
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1101
   if(index != 0) {
3✔
1102
      // As of now there are no multi-value binary entries.
1103
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1104
   }
1105

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

1108
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
12✔
1109
      switch(value_type) {
1110
         case BOTAN_X509_SERIAL_NUMBER:
1111
            return view(Botan::store_be(crl.crl_number()));
1112
         case BOTAN_X509_ISSUER_DN_BITS:
1113
            return view(Botan::ASN1::put_in_sequence(crl.issuer_dn().get_bits()));
1114
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1115
            return crl.authority_key_id().empty() ? BOTAN_FFI_ERROR_NO_VALUE : view(crl.authority_key_id());
1116

1117
         case BOTAN_X509_TBS_DATA_BITS:
1118
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1119
         case BOTAN_X509_SIGNATURE_BITS:
1120
         case BOTAN_X509_DER_ENCODING:
1121
            return botan_x509_object_view_value(crl, value_type, index, ctx, view_fn);
1122

1123
         case BOTAN_X509_SUBJECT_DN_BITS:
1124
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1125
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1126
         case BOTAN_X509_PEM_ENCODING:
1127
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1128
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1129
         case BOTAN_X509_CA_ISSUERS_URLS:
1130
            return BOTAN_FFI_ERROR_NO_VALUE;
1131
      }
1132

1133
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1134
   });
1135
#else
1136
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view_fn);
1137
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1138
#endif
1139
}
1140

1141
int botan_x509_crl_view_binary_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1142
   return enumerator_count_values(count, [=](size_t index) {
1✔
1143
      return botan_x509_crl_view_binary_values(
1✔
1144
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1145
   });
1✔
1146
}
1147

1148
int botan_x509_crl_view_string_values(botan_x509_crl_t crl_obj,
3✔
1149
                                      botan_x509_value_type value_type,
1150
                                      size_t index,
1151
                                      botan_view_ctx ctx,
1152
                                      botan_view_str_fn view) {
1153
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1154
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
6✔
1155
      switch(value_type) {
1156
         case BOTAN_X509_PEM_ENCODING:
1157
            return botan_x509_object_view_value(crl, value_type, index, ctx, view);
1158

1159
         case BOTAN_X509_SERIAL_NUMBER:
1160
         case BOTAN_X509_SUBJECT_DN_BITS:
1161
         case BOTAN_X509_ISSUER_DN_BITS:
1162
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1163
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1164
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1165
         case BOTAN_X509_TBS_DATA_BITS:
1166
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1167
         case BOTAN_X509_SIGNATURE_BITS:
1168
         case BOTAN_X509_DER_ENCODING:
1169
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1170
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1171
         case BOTAN_X509_CA_ISSUERS_URLS:
1172
            return BOTAN_FFI_ERROR_NO_VALUE;
1173
      }
1174

1175
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1176
   });
1177
#else
1178
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view);
1179
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1180
#endif
1181
}
1182

1183
int botan_x509_crl_view_string_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1184
   return enumerator_count_values(count, [=](size_t index) {
1✔
1185
      return botan_x509_crl_view_string_values(
2✔
1186
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1187
   });
1✔
1188
}
1189

1190
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
1191
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1192
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
1193
#else
1194
   BOTAN_UNUSED(cert);
1195
   BOTAN_UNUSED(crl);
1196
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1197
#endif
1198
}
1199

1200
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
3✔
1201
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1202
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
6✔
1203
      const auto& entries = c.get_revoked();
1204
      if(index >= entries.size()) {
1205
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1206
      }
1207

1208
      if(Botan::any_null_pointers(entry)) {
1209
         return BOTAN_FFI_ERROR_NULL_POINTER;
1210
      }
1211

1212
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
1213
   });
1214
#else
1215
   BOTAN_UNUSED(crl, index, entry);
1216
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1217
#endif
1218
}
1219

1220
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
2✔
1221
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1222
   if(Botan::any_null_pointers(count)) {
2✔
1223
      return BOTAN_FFI_ERROR_NULL_POINTER;
1224
   }
1225

1226
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
4✔
1227
#else
1228
   BOTAN_UNUSED(crl, count);
1229
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1230
#endif
1231
}
1232

1233
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
1✔
1234
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1235
   return BOTAN_FFI_CHECKED_DELETE(entry);
1✔
1236
#else
1237
   BOTAN_UNUSED(entry);
1238
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1239
#endif
1240
}
1241

1242
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
1✔
1243
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1244
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
1245
      if(Botan::any_null_pointers(reason_code)) {
1246
         return BOTAN_FFI_ERROR_NULL_POINTER;
1247
      }
1248

1249
      *reason_code = static_cast<int>(e.reason_code());
1250
      return BOTAN_FFI_SUCCESS;
1251
   });
1252
#else
1253
   BOTAN_UNUSED(entry, reason_code);
1254
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1255
#endif
1256
}
1257

1258
int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) {
1✔
1259
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1260
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
1261
      if(Botan::any_null_pointers(serial_number)) {
1262
         return BOTAN_FFI_ERROR_NULL_POINTER;
1263
      }
1264

1265
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
1266
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
1267
   });
1268
#else
1269
   BOTAN_UNUSED(entry, serial_number);
1270
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1271
#endif
1272
}
1273

1274
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
1275
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1276
   return BOTAN_FFI_VISIT(
2✔
1277
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
1278
#else
1279
   BOTAN_UNUSED(entry, ctx, view);
1280
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1281
#endif
1282
}
1283

1284
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
1✔
1285
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1286
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
1287
      if(Botan::any_null_pointers(time_since_epoch)) {
1288
         return BOTAN_FFI_ERROR_NULL_POINTER;
1289
      }
1290

1291
      *time_since_epoch = e.expire_time().time_since_epoch();
1292
      return BOTAN_FFI_SUCCESS;
1293
   });
1294
#else
1295
   BOTAN_UNUSED(entry, time_since_epoch);
1296
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1297
#endif
1298
}
1299

1300
int botan_x509_cert_verify_with_crl(int* result_code,
12✔
1301
                                    botan_x509_cert_t cert,
1302
                                    const botan_x509_cert_t* intermediates,
1303
                                    size_t intermediates_len,
1304
                                    const botan_x509_cert_t* trusted,
1305
                                    size_t trusted_len,
1306
                                    const botan_x509_crl_t* crls,
1307
                                    size_t crls_len,
1308
                                    const char* trusted_path,
1309
                                    size_t required_strength,
1310
                                    const char* hostname_cstr,
1311
                                    uint64_t reference_time) {
1312
   if(required_strength == 0) {
12✔
1313
      required_strength = 110;
2✔
1314
   }
1315

1316
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1317
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
1318
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
14✔
1319
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
12✔
1320
      const auto validation_time = reference_time == 0
12✔
1321
                                      ? std::chrono::system_clock::now()
12✔
1322
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1323

1324
      std::vector<Botan::X509_Certificate> end_certs;
12✔
1325
      end_certs.push_back(safe_get(cert));
12✔
1326
      for(size_t i = 0; i != intermediates_len; ++i) {
30✔
1327
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1328
      }
1329

1330
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
12✔
1331
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
12✔
1332
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
12✔
1333
      std::vector<Botan::Certificate_Store*> trusted_roots;
12✔
1334

1335
      if(trusted_path != nullptr && *trusted_path != 0) {
12✔
1336
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1337
         trusted_roots.push_back(trusted_from_path.get());
2✔
1338
      }
1339

1340
      if(trusted_len > 0) {
12✔
1341
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
18✔
1342
         for(size_t i = 0; i != trusted_len; ++i) {
18✔
1343
            trusted_extra->add_certificate(safe_get(trusted[i]));
9✔
1344
         }
1345
         trusted_roots.push_back(trusted_extra.get());
9✔
1346
      }
1347

1348
      if(crls_len > 0) {
12✔
1349
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
1350
         for(size_t i = 0; i != crls_len; ++i) {
13✔
1351
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
1352
         }
1353
         trusted_roots.push_back(trusted_crls.get());
5✔
1354
      }
1355

1356
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
24✔
1357

1358
      auto validation_result =
12✔
1359
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
12✔
1360

1361
      if(result_code != nullptr) {
12✔
1362
         *result_code = static_cast<int>(validation_result.result());
12✔
1363
      }
1364

1365
      if(validation_result.successful_validation()) {
12✔
1366
         return 0;
1367
      } else {
1368
         return 1;
8✔
1369
      }
1370
   });
14✔
1371
#else
1372
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1373
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1374
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1375
#endif
1376
}
1377
}
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