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

randombit / botan / 20948751799

13 Jan 2026 07:43AM UTC coverage: 90.46% (+0.009%) from 90.451%
20948751799

Pull #5188

github

web-flow
Merge 496a357ef into 832565b87
Pull Request #5188: FFI: Generic getter(s) for X.509 objects

102260 of 113044 relevant lines covered (90.46%)

13098587.69 hits per line

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

95.85
/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_oid.h>
20
   #include <botan/internal/loadstor.h>
21
   #include <botan/internal/stl_util.h>
22
#endif
23

24
namespace {
25

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

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

58
}  // namespace
59

60
extern "C" {
61

62
using namespace Botan_FFI;
63

64
#if defined(BOTAN_HAS_X509_CERTIFICATES)
65

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

69
#endif
70

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

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

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

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

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

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

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

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

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

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

124
namespace {
125

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

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

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

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

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

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

172
}  // namespace
173

174
extern "C" {
175

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

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

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

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

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

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

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

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

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

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

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

266
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
267
   };
19✔
268

269
   auto wrap_or_empty = [](std::string str) -> std::vector<std::string> {
23✔
270
      if(str.empty()) {
4✔
271
         return {};
1✔
272
      } else {
273
         return {std::move(str)};
6✔
274
      }
275
   };
3✔
276

277
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
38✔
278
      switch(value_type) {
279
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
280
            return enumerate_crl_distribution_points(c, index);
281
         case BOTAN_X509_OCSP_RESPONDER_URLS:
282
            return enumerate(wrap_or_empty(c.ocsp_responder()), index);
283
         case BOTAN_X509_CA_ISSUERS_URLS:
284
            return enumerate(c.ca_issuers(), index);
285
         case BOTAN_X509_PEM_ENCODING:
286
            return botan_x509_object_view_value(c, value_type, index, ctx, view_fn);
287

288
         case BOTAN_X509_SERIAL_NUMBER:
289
         case BOTAN_X509_SUBJECT_DN_BITS:
290
         case BOTAN_X509_ISSUER_DN_BITS:
291
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
292
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
293
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
294
         case BOTAN_X509_TBS_DATA_BITS:
295
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
296
         case BOTAN_X509_SIGNATURE_BITS:
297
         case BOTAN_X509_DER_ENCODING:
298
            return BOTAN_FFI_ERROR_NO_VALUE;
299
      }
300

301
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
302
   });
303
#else
304
   BOTAN_UNUSED(cert, value_type, index, ctx, view_fn);
305
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
306
#endif
307
}
308

309
int botan_x509_cert_view_string_values_count(botan_x509_cert_t cert, botan_x509_value_type value_type, size_t* count) {
4✔
310
   return enumerator_count_values(count, [=](size_t index) {
4✔
311
      return botan_x509_cert_view_string_values(
10✔
312
         cert, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
313
   });
4✔
314
}
315

316
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
317
#if defined(BOTAN_HAS_X509_CERTIFICATES)
318
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? BOTAN_FFI_SUCCESS : 1; });
4✔
319
#else
320
   BOTAN_UNUSED(cert);
321
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
322
#endif
323
}
324

325
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
326
#if defined(BOTAN_HAS_X509_CERTIFICATES)
327
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
328
      if(Botan::any_null_pointers(path_limit)) {
329
         return BOTAN_FFI_ERROR_NULL_POINTER;
330
      }
331

332
      if(const auto path_len = c.path_length_constraint()) {
333
         *path_limit = path_len.value();
334
         return BOTAN_FFI_SUCCESS;
335
      } else {
336
         return BOTAN_FFI_ERROR_NO_VALUE;
337
      }
338
   });
339
#else
340
   BOTAN_UNUSED(cert, path_limit);
341
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
342
#endif
343
}
344

345
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
346
   if(key == nullptr) {
2✔
347
      return BOTAN_FFI_ERROR_NULL_POINTER;
348
   }
349

350
   *key = nullptr;
2✔
351

352
#if defined(BOTAN_HAS_X509_CERTIFICATES)
353
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
354
      auto public_key = safe_get(cert).subject_public_key();
2✔
355
      return ffi_new_object(key, std::move(public_key));
2✔
356
   });
4✔
357
#else
358
   BOTAN_UNUSED(cert);
359
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
360
#endif
361
}
362

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

381
int botan_x509_cert_get_subject_dn(
8✔
382
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
383
#if defined(BOTAN_HAS_X509_CERTIFICATES)
384
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
385
      auto subject_info = c.subject_info(key);
386
      if(index < subject_info.size()) {
387
         // TODO(Botan4) change the type of out and remove this cast
388
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
389
      } else {
390
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
391
      }
392
   });
393
#else
394
   BOTAN_UNUSED(cert, key, index, out, out_len);
395
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
396
#endif
397
}
398

399
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
400
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
401
}
402

403
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
404
#if defined(BOTAN_HAS_X509_CERTIFICATES)
405
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
406
#else
407
   BOTAN_UNUSED(cert, ctx, view);
408
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
409
#endif
410
}
411

412
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
413
#if defined(BOTAN_HAS_X509_CERTIFICATES)
414
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
415
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
416
      if(c.allowed_usage(k)) {
417
         return BOTAN_FFI_SUCCESS;
418
      }
419
      return 1;
420
   });
421
#else
422
   BOTAN_UNUSED(cert, key_usage);
423
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
424
#endif
425
}
426

427
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
428
#if defined(BOTAN_HAS_X509_CERTIFICATES)
429
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
430
      if(Botan::any_null_pointers(oid)) {
431
         return BOTAN_FFI_ERROR_NULL_POINTER;
432
      }
433

434
      return c.has_ex_constraint(oid) ? BOTAN_FFI_SUCCESS : 1;
435
   });
436
#else
437
   BOTAN_UNUSED(cert, oid);
438
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
439
#endif
440
}
441

442
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
443
#if defined(BOTAN_HAS_X509_CERTIFICATES)
444
   return BOTAN_FFI_VISIT(
8✔
445
      cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? BOTAN_FFI_SUCCESS : 1; });
446
#else
447
   BOTAN_UNUSED(cert, oid);
448
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
449
#endif
450
}
451

452
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
32✔
453
#if defined(BOTAN_HAS_X509_CERTIFICATES)
454
   return BOTAN_FFI_CHECKED_DELETE(cert);
32✔
455
#else
456
   BOTAN_UNUSED(cert);
457
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
458
#endif
459
}
460

461
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
462
#if defined(BOTAN_HAS_X509_CERTIFICATES)
463
   return BOTAN_FFI_VISIT(cert,
6✔
464
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
465
#else
466
   BOTAN_UNUSED(cert, out, out_len);
467
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
468
#endif
469
}
470

471
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
472
#if defined(BOTAN_HAS_X509_CERTIFICATES)
473
   return BOTAN_FFI_VISIT(cert,
4✔
474
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
475
#else
476
   BOTAN_UNUSED(cert, out, out_len);
477
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
478
#endif
479
}
480

481
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
482
#if defined(BOTAN_HAS_X509_CERTIFICATES)
483
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
484
#else
485
   BOTAN_UNUSED(cert, time_since_epoch);
486
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
487
#endif
488
}
489

490
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
491
#if defined(BOTAN_HAS_X509_CERTIFICATES)
492
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
493
#else
494
   BOTAN_UNUSED(cert, time_since_epoch);
495
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
496
#endif
497
}
498

499
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
500
#if defined(BOTAN_HAS_X509_CERTIFICATES)
501
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
502
#else
503
   BOTAN_UNUSED(cert, out, out_len);
504
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
505
#endif
506
}
507

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

512
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
513
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
514
   });
515
#else
516
   BOTAN_UNUSED(cert, hash, out, out_len);
517
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
518
#endif
519
}
520

521
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
522
#if defined(BOTAN_HAS_X509_CERTIFICATES)
523
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
524
#else
525
   BOTAN_UNUSED(cert, out, out_len);
526
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
527
#endif
528
}
529

530
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
531
#if defined(BOTAN_HAS_X509_CERTIFICATES)
532
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
533
#else
534
   BOTAN_UNUSED(cert, out, out_len);
535
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
536
#endif
537
}
538

539
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
540
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
541
}
542

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

554
namespace {
555

556
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
301✔
557
   using Type = Botan::GeneralName::NameType;
301✔
558
   switch(gn_type) {
301✔
559
      case Type::Unknown:
1✔
560
         return std::nullopt;
1✔
561
      case Type::RFC822:
83✔
562
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
563
      case Type::DNS:
73✔
564
         return BOTAN_X509_DNS_NAME;
73✔
565
      case Type::URI:
28✔
566
         return BOTAN_X509_URI;
28✔
567
      case Type::DN:
95✔
568
         return BOTAN_X509_DIRECTORY_NAME;
95✔
569
      case Type::IPv4:
21✔
570
         return BOTAN_X509_IP_ADDRESS;
21✔
571
      case Type::Other:
×
572
         return BOTAN_X509_OTHER_NAME;
×
573
   }
574

575
   BOTAN_ASSERT_UNREACHABLE();
×
576
}
577

578
}  // namespace
579

580
extern "C" {
581

582
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
583
#if defined(BOTAN_HAS_X509_CERTIFICATES)
584
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
585
      if(Botan::any_null_pointers(type)) {
586
         return BOTAN_FFI_ERROR_NULL_POINTER;
587
      }
588

589
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
590
      if(!mapped_type.has_value()) {
591
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
592
      }
593

594
      *type = mapped_type.value();
595
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
596
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
597
      }
598

599
      return BOTAN_FFI_SUCCESS;
600
   });
601
#else
602
   BOTAN_UNUSED(name, type);
603
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
604
#endif
605
}
606

607
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
608
                                              botan_view_ctx ctx,
609
                                              botan_view_str_fn view) {
610
#if defined(BOTAN_HAS_X509_CERTIFICATES)
611
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
612
      const auto type = to_botan_x509_general_name_types(n.type_code());
613
      if(!type) {
614
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
615
      }
616

617
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
618
         type != BOTAN_X509_IP_ADDRESS) {
619
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
620
      }
621

622
      return invoke_view_callback(view, ctx, n.name());
623
   });
624
#else
625
   BOTAN_UNUSED(name, ctx, view);
626
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
627
#endif
628
}
629

630
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
631
                                              botan_view_ctx ctx,
632
                                              botan_view_bin_fn view) {
633
#if defined(BOTAN_HAS_X509_CERTIFICATES)
634
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
635
      const auto type = to_botan_x509_general_name_types(n.type_code());
636
      if(!type) {
637
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
638
      }
639

640
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
641
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
642
      }
643

644
      return invoke_view_callback(view, ctx, n.binary_name());
645
   });
646
#else
647
   BOTAN_UNUSED(name, ctx, view);
648
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
649
#endif
650
}
651

652
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
653
#if defined(BOTAN_HAS_X509_CERTIFICATES)
654
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
655
#else
656
   BOTAN_UNUSED(name);
657
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
658
#endif
659
}
660

661
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
662
                                               size_t index,
663
                                               botan_x509_general_name_t* constraint) {
664
#if defined(BOTAN_HAS_X509_CERTIFICATES)
665
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
666
      if(Botan::any_null_pointers(constraint)) {
667
         return BOTAN_FFI_ERROR_NULL_POINTER;
668
      }
669

670
      const auto& constraints = c.name_constraints().permitted();
671
      if(index >= constraints.size()) {
672
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
673
      }
674

675
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
676
   });
677
#else
678
   BOTAN_UNUSED(cert, index, constraint);
679
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
680
#endif
681
}
682

683
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
684
                                              size_t index,
685
                                              botan_x509_general_name_t* constraint) {
686
#if defined(BOTAN_HAS_X509_CERTIFICATES)
687
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
688
      if(Botan::any_null_pointers(constraint)) {
689
         return BOTAN_FFI_ERROR_NULL_POINTER;
690
      }
691

692
      const auto& constraints = c.name_constraints().excluded();
693
      if(index >= constraints.size()) {
694
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
695
      }
696

697
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
698
   });
699
#else
700
   BOTAN_UNUSED(cert, index, constraint);
701
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
702
#endif
703
}
704
}
705

706
namespace {
707

708
/**
709
 * As specified in RFC 5280 Section 4.2.1.6. alternative names essentially are a
710
 * collection of GeneralNames. This allows mapping a single entry of @p altnames
711
 * to a GeneralName by its @p index. If the index is out of range, std::nullopt
712
 * is returned.
713
 */
714
std::optional<Botan::GeneralName> extract_general_name_at(const Botan::AlternativeName& altnames, size_t index) {
132✔
715
   if(index < altnames.email().size()) {
132✔
716
      auto itr = altnames.email().begin();
12✔
717
      std::advance(itr, index);
12✔
718
      return Botan::GeneralName::email(*itr);
36✔
719
   }
720
   index -= altnames.email().size();
120✔
721

722
   if(index < altnames.dns().size()) {
120✔
723
      auto itr = altnames.dns().begin();
36✔
724
      std::advance(itr, index);
36✔
725
      return Botan::GeneralName::dns(*itr);
108✔
726
   }
727
   index -= altnames.dns().size();
84✔
728

729
   if(index < altnames.directory_names().size()) {
84✔
730
      auto itr = altnames.directory_names().begin();
36✔
731
      std::advance(itr, index);
36✔
732
      return Botan::GeneralName::directory_name(*itr);
108✔
733
   }
734
   index -= altnames.directory_names().size();
48✔
735

736
   if(index < altnames.uris().size()) {
48✔
737
      auto itr = altnames.uris().begin();
24✔
738
      std::advance(itr, index);
24✔
739
      return Botan::GeneralName::uri(*itr);
72✔
740
   }
741
   index -= altnames.uris().size();
24✔
742

743
   if(index < altnames.ipv4_address().size()) {
24✔
744
      auto itr = altnames.ipv4_address().begin();
12✔
745
      std::advance(itr, index);
12✔
746
      return Botan::GeneralName::ipv4_address(*itr);
36✔
747
   }
748

749
   return std::nullopt;
12✔
750
}
751

752
}  // namespace
753

754
extern "C" {
755

756
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
757
                                              size_t index,
758
                                              botan_x509_general_name_t* alt_name) {
759
#if defined(BOTAN_HAS_X509_CERTIFICATES)
760
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
761
      if(Botan::any_null_pointers(alt_name)) {
762
         return BOTAN_FFI_ERROR_NULL_POINTER;
763
      }
764

765
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
766
         return BOTAN_FFI_ERROR_NO_VALUE;
767
      }
768

769
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
770
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
771
      }
772

773
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
774
   });
775
#else
776
   BOTAN_UNUSED(cert, index, alt_name);
777
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
778
#endif
779
}
780

781
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
782
                                             size_t index,
783
                                             botan_x509_general_name_t* alt_name) {
784
#if defined(BOTAN_HAS_X509_CERTIFICATES)
785
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
786
      if(Botan::any_null_pointers(alt_name)) {
787
         return BOTAN_FFI_ERROR_NULL_POINTER;
788
      }
789

790
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
791
         return BOTAN_FFI_ERROR_NO_VALUE;
792
      }
793

794
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
795
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
796
      }
797

798
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
799
   });
800
#else
801
   BOTAN_UNUSED(cert, index, alt_name);
802
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
803
#endif
804
}
805

806
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
807
   if(hostname == nullptr) {
6✔
808
      return BOTAN_FFI_ERROR_NULL_POINTER;
809
   }
810

811
#if defined(BOTAN_HAS_X509_CERTIFICATES)
812
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
813
#else
814
   BOTAN_UNUSED(cert);
815
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
816
#endif
817
}
818

819
int botan_x509_cert_verify(int* result_code,
4✔
820
                           botan_x509_cert_t cert,
821
                           const botan_x509_cert_t* intermediates,
822
                           size_t intermediates_len,
823
                           const botan_x509_cert_t* trusted,
824
                           size_t trusted_len,
825
                           const char* trusted_path,
826
                           size_t required_strength,
827
                           const char* hostname_cstr,
828
                           uint64_t reference_time) {
829
   if(required_strength == 0) {
4✔
830
      required_strength = 110;
3✔
831
   }
832

833
#if defined(BOTAN_HAS_X509_CERTIFICATES)
834
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
835
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
836
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
837
      const auto validation_time = reference_time == 0
4✔
838
                                      ? std::chrono::system_clock::now()
4✔
839
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
840

841
      std::vector<Botan::X509_Certificate> end_certs;
4✔
842
      end_certs.push_back(safe_get(cert));
4✔
843
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
844
         end_certs.push_back(safe_get(intermediates[i]));
5✔
845
      }
846

847
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
848
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
849
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
850

851
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
852
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
853
         trusted_roots.push_back(trusted_from_path.get());
×
854
      }
855

856
      if(trusted_len > 0) {
4✔
857
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
858
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
859
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
860
         }
861
         trusted_roots.push_back(trusted_extra.get());
4✔
862
      }
863

864
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
865

866
      auto validation_result =
4✔
867
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
868

869
      if(result_code != nullptr) {
4✔
870
         *result_code = static_cast<int>(validation_result.result());
4✔
871
      }
872

873
      if(validation_result.successful_validation()) {
4✔
874
         return 0;
875
      } else {
876
         return 1;
3✔
877
      }
878
   });
4✔
879
#else
880
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
881
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
882
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
883
#endif
884
}
885

886
const char* botan_x509_cert_validation_status(int code) {
11✔
887
   if(code < 0) {
11✔
888
      return nullptr;
889
   }
890

891
#if defined(BOTAN_HAS_X509_CERTIFICATES)
892
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
893
   return Botan::to_string(sc);
11✔
894
#else
895
   return nullptr;
896
#endif
897
}
898

899
#if defined(BOTAN_HAS_X509_CERTIFICATES)
900

901
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
8✔
902
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_entry_struct, Botan::CRL_Entry, 0x4EAA5346);
1✔
903

904
#endif
905

906
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
907
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
908
      return BOTAN_FFI_ERROR_NULL_POINTER;
909
   }
910

911
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
912

913
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
914
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
915
      return ffi_new_object(crl_obj, std::move(c));
14✔
916
   });
14✔
917

918
#else
919
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
920
#endif
921
}
922

923
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
924
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
925
      return BOTAN_FFI_ERROR_NULL_POINTER;
926
   }
927

928
#if defined(BOTAN_HAS_X509_CERTIFICATES)
929
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
930
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
931
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
932
      return ffi_new_object(crl_obj, std::move(c));
1✔
933
   });
3✔
934
#else
935
   BOTAN_UNUSED(crl_bits_len);
936
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
937
#endif
938
}
939

940
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
941
#if defined(BOTAN_HAS_X509_CERTIFICATES)
942
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
943
      if(Botan::any_null_pointers(time_since_epoch)) {
944
         return BOTAN_FFI_ERROR_NULL_POINTER;
945
      }
946
      *time_since_epoch = c.this_update().time_since_epoch();
947
      return BOTAN_FFI_SUCCESS;
948
   });
949
#else
950
   BOTAN_UNUSED(crl, time_since_epoch);
951
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
952
#endif
953
}
954

955
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
4✔
956
#if defined(BOTAN_HAS_X509_CERTIFICATES)
957
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
8✔
958
      const auto& time = c.next_update();
959
      if(!time.time_is_set()) {
960
         return BOTAN_FFI_ERROR_NO_VALUE;
961
      }
962

963
      if(Botan::any_null_pointers(time_since_epoch)) {
964
         return BOTAN_FFI_ERROR_NULL_POINTER;
965
      }
966

967
      *time_since_epoch = c.next_update().time_since_epoch();
968
      return BOTAN_FFI_SUCCESS;
969
   });
970
#else
971
   BOTAN_UNUSED(crl, time_since_epoch);
972
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
973
#endif
974
}
975

976
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
8✔
977
#if defined(BOTAN_HAS_X509_CERTIFICATES)
978
   return BOTAN_FFI_CHECKED_DELETE(crl);
8✔
979
#else
980
   BOTAN_UNUSED(crl);
981
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
982
#endif
983
}
984

985
int botan_x509_crl_view_binary_values(botan_x509_crl_t crl_obj,
3✔
986
                                      botan_x509_value_type value_type,
987
                                      size_t index,
988
                                      botan_view_ctx ctx,
989
                                      botan_view_bin_fn view_fn) {
990
#if defined(BOTAN_HAS_X509_CERTIFICATES)
991
   if(index != 0) {
3✔
992
      // As of now there are no multi-value binary entries.
993
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
994
   }
995

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

998
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
12✔
999
      switch(value_type) {
1000
         case BOTAN_X509_SERIAL_NUMBER:
1001
            return view(Botan::store_be(crl.crl_number()));
1002
         case BOTAN_X509_ISSUER_DN_BITS:
1003
            return view(Botan::ASN1::put_in_sequence(crl.issuer_dn().get_bits()));
1004
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1005
            return crl.authority_key_id().empty() ? BOTAN_FFI_ERROR_NO_VALUE : view(crl.authority_key_id());
1006

1007
         case BOTAN_X509_TBS_DATA_BITS:
1008
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1009
         case BOTAN_X509_SIGNATURE_BITS:
1010
         case BOTAN_X509_DER_ENCODING:
1011
            return botan_x509_object_view_value(crl, value_type, index, ctx, view_fn);
1012

1013
         case BOTAN_X509_SUBJECT_DN_BITS:
1014
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1015
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1016
         case BOTAN_X509_PEM_ENCODING:
1017
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1018
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1019
         case BOTAN_X509_CA_ISSUERS_URLS:
1020
            return BOTAN_FFI_ERROR_NO_VALUE;
1021
      }
1022

1023
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1024
   });
1025
#else
1026
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view_fn);
1027
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1028
#endif
1029
}
1030

1031
int botan_x509_crl_view_binary_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1032
   return enumerator_count_values(count, [=](size_t index) {
1✔
1033
      return botan_x509_crl_view_binary_values(
1✔
1034
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1035
   });
1✔
1036
}
1037

1038
int botan_x509_crl_view_string_values(botan_x509_crl_t crl_obj,
3✔
1039
                                      botan_x509_value_type value_type,
1040
                                      size_t index,
1041
                                      botan_view_ctx ctx,
1042
                                      botan_view_str_fn view) {
1043
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1044
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
6✔
1045
      switch(value_type) {
1046
         case BOTAN_X509_PEM_ENCODING:
1047
            return botan_x509_object_view_value(crl, value_type, index, ctx, view);
1048

1049
         case BOTAN_X509_SERIAL_NUMBER:
1050
         case BOTAN_X509_SUBJECT_DN_BITS:
1051
         case BOTAN_X509_ISSUER_DN_BITS:
1052
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
1053
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
1054
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
1055
         case BOTAN_X509_TBS_DATA_BITS:
1056
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1057
         case BOTAN_X509_SIGNATURE_BITS:
1058
         case BOTAN_X509_DER_ENCODING:
1059
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
1060
         case BOTAN_X509_OCSP_RESPONDER_URLS:
1061
         case BOTAN_X509_CA_ISSUERS_URLS:
1062
            return BOTAN_FFI_ERROR_NO_VALUE;
1063
      }
1064

1065
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
1066
   });
1067
#else
1068
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view);
1069
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1070
#endif
1071
}
1072

1073
int botan_x509_crl_view_string_values_count(botan_x509_crl_t crl_obj, botan_x509_value_type value_type, size_t* count) {
1✔
1074
   return enumerator_count_values(count, [=](size_t index) {
1✔
1075
      return botan_x509_crl_view_string_values(
2✔
1076
         crl_obj, value_type, index, nullptr, [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; });
1077
   });
1✔
1078
}
1079

1080
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
1081
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1082
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
1083
#else
1084
   BOTAN_UNUSED(cert);
1085
   BOTAN_UNUSED(crl);
1086
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1087
#endif
1088
}
1089

1090
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
3✔
1091
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1092
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
6✔
1093
      const auto& entries = c.get_revoked();
1094
      if(index >= entries.size()) {
1095
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
1096
      }
1097

1098
      if(Botan::any_null_pointers(entry)) {
1099
         return BOTAN_FFI_ERROR_NULL_POINTER;
1100
      }
1101

1102
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
1103
   });
1104
#else
1105
   BOTAN_UNUSED(crl, index, entry);
1106
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1107
#endif
1108
}
1109

1110
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
1✔
1111
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1112
   return BOTAN_FFI_CHECKED_DELETE(entry);
1✔
1113
#else
1114
   BOTAN_UNUSED(entry);
1115
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1116
#endif
1117
}
1118

1119
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
1✔
1120
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1121
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
1122
      if(Botan::any_null_pointers(reason_code)) {
1123
         return BOTAN_FFI_ERROR_NULL_POINTER;
1124
      }
1125

1126
      *reason_code = static_cast<int>(e.reason_code());
1127
      return BOTAN_FFI_SUCCESS;
1128
   });
1129
#else
1130
   BOTAN_UNUSED(entry, reason_code);
1131
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1132
#endif
1133
}
1134

1135
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
1136
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1137
   return BOTAN_FFI_VISIT(
2✔
1138
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
1139
#else
1140
   BOTAN_UNUSED(entry, ctx, view);
1141
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1142
#endif
1143
}
1144

1145
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
1✔
1146
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1147
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
1148
      if(Botan::any_null_pointers(time_since_epoch)) {
1149
         return BOTAN_FFI_ERROR_NULL_POINTER;
1150
      }
1151

1152
      *time_since_epoch = e.expire_time().time_since_epoch();
1153
      return BOTAN_FFI_SUCCESS;
1154
   });
1155
#else
1156
   BOTAN_UNUSED(entry, time_since_epoch);
1157
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1158
#endif
1159
}
1160

1161
int botan_x509_cert_verify_with_crl(int* result_code,
12✔
1162
                                    botan_x509_cert_t cert,
1163
                                    const botan_x509_cert_t* intermediates,
1164
                                    size_t intermediates_len,
1165
                                    const botan_x509_cert_t* trusted,
1166
                                    size_t trusted_len,
1167
                                    const botan_x509_crl_t* crls,
1168
                                    size_t crls_len,
1169
                                    const char* trusted_path,
1170
                                    size_t required_strength,
1171
                                    const char* hostname_cstr,
1172
                                    uint64_t reference_time) {
1173
   if(required_strength == 0) {
12✔
1174
      required_strength = 110;
2✔
1175
   }
1176

1177
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1178
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
1179
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
14✔
1180
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
12✔
1181
      const auto validation_time = reference_time == 0
12✔
1182
                                      ? std::chrono::system_clock::now()
12✔
1183
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1184

1185
      std::vector<Botan::X509_Certificate> end_certs;
12✔
1186
      end_certs.push_back(safe_get(cert));
12✔
1187
      for(size_t i = 0; i != intermediates_len; ++i) {
30✔
1188
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1189
      }
1190

1191
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
12✔
1192
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
12✔
1193
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
12✔
1194
      std::vector<Botan::Certificate_Store*> trusted_roots;
12✔
1195

1196
      if(trusted_path != nullptr && *trusted_path != 0) {
12✔
1197
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1198
         trusted_roots.push_back(trusted_from_path.get());
2✔
1199
      }
1200

1201
      if(trusted_len > 0) {
12✔
1202
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
18✔
1203
         for(size_t i = 0; i != trusted_len; ++i) {
18✔
1204
            trusted_extra->add_certificate(safe_get(trusted[i]));
9✔
1205
         }
1206
         trusted_roots.push_back(trusted_extra.get());
9✔
1207
      }
1208

1209
      if(crls_len > 0) {
12✔
1210
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
1211
         for(size_t i = 0; i != crls_len; ++i) {
13✔
1212
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
1213
         }
1214
         trusted_roots.push_back(trusted_crls.get());
5✔
1215
      }
1216

1217
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
24✔
1218

1219
      auto validation_result =
12✔
1220
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
12✔
1221

1222
      if(result_code != nullptr) {
12✔
1223
         *result_code = static_cast<int>(validation_result.result());
12✔
1224
      }
1225

1226
      if(validation_result.successful_validation()) {
12✔
1227
         return 0;
1228
      } else {
1229
         return 1;
8✔
1230
      }
1231
   });
14✔
1232
#else
1233
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1234
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1235
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1236
#endif
1237
}
1238
}
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