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

randombit / botan / 22280922156

22 Feb 2026 04:29PM UTC coverage: 90.342% (+0.009%) from 90.333%
22280922156

Pull #5166

github

web-flow
Merge 457353aed into 516662327
Pull Request #5166: Add CRL creation to FFI

103100 of 114122 relevant lines covered (90.34%)

11528669.83 hits per line

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

95.02
/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_cert.h>
10
#include <botan/internal/ffi_pkey.h>
11
#include <botan/internal/ffi_rng.h>
12
#include <botan/internal/ffi_util.h>
13
#include <memory>
14

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

25
#if defined(BOTAN_HAS_X509_CERTIFICATES)
26

27
namespace Botan_FFI {
28

29
namespace {
30

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

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

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

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

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

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

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

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

109
   BOTAN_ASSERT_UNREACHABLE();
×
110
}
111

112
std::chrono::system_clock::time_point timepoint_from_timestamp(uint64_t time_since_epoch) {
5✔
113
   return std::chrono::system_clock::time_point(std::chrono::seconds(time_since_epoch));
5✔
114
}
115

116
std::string default_from_ptr(const char* value) {
10✔
117
   std::string ret;
10✔
118
   if(value != nullptr) {
10✔
119
      ret = value;
×
120
   }
121
   return ret;
10✔
122
}
×
123

124
}  // namespace
125

126
}  // namespace Botan_FFI
127

128
#endif
129

130
extern "C" {
131

132
using namespace Botan_FFI;
133

134
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
35✔
135
   if(cert_obj == nullptr || cert_path == nullptr) {
35✔
136
      return BOTAN_FFI_ERROR_NULL_POINTER;
137
   }
138

139
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
140

141
   return ffi_guard_thunk(__func__, [=]() -> int {
35✔
142
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
35✔
143
      return ffi_new_object(cert_obj, std::move(c));
35✔
144
   });
70✔
145

146
#else
147
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
148
#endif
149
}
150

151
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
152
   if(cert_obj == nullptr) {
1✔
153
      return BOTAN_FFI_ERROR_NULL_POINTER;
154
   }
155

156
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
157

158
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
159
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
160
      return ffi_new_object(cert_obj, std::move(c));
1✔
161
   });
2✔
162

163
#else
164
   BOTAN_UNUSED(cert);
165
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
166
#endif
167
}
168

169
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
170
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
171
      return BOTAN_FFI_ERROR_NULL_POINTER;
172
   }
173

174
#if defined(BOTAN_HAS_X509_CERTIFICATES)
175
   return ffi_guard_thunk(__func__, [=]() -> int {
×
176
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
177
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
178
      return ffi_new_object(cert_obj, std::move(c));
×
179
   });
×
180
#else
181
   BOTAN_UNUSED(cert_bits_len);
182
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
183
#endif
184
}
185

186
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
187
#if defined(BOTAN_HAS_X509_CERTIFICATES)
188
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? 1 : 0; });
4✔
189
#else
190
   BOTAN_UNUSED(cert);
191
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
192
#endif
193
}
194

195
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
196
#if defined(BOTAN_HAS_X509_CERTIFICATES)
197
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
198
      if(Botan::any_null_pointers(path_limit)) {
199
         return BOTAN_FFI_ERROR_NULL_POINTER;
200
      }
201

202
      if(const auto path_len = c.path_length_constraint()) {
203
         *path_limit = path_len.value();
204
         return BOTAN_FFI_SUCCESS;
205
      } else {
206
         return BOTAN_FFI_ERROR_NO_VALUE;
207
      }
208
   });
209
#else
210
   BOTAN_UNUSED(cert, path_limit);
211
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
212
#endif
213
}
214

215
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
216
   if(key == nullptr) {
2✔
217
      return BOTAN_FFI_ERROR_NULL_POINTER;
218
   }
219

220
   *key = nullptr;
2✔
221

222
#if defined(BOTAN_HAS_X509_CERTIFICATES)
223
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
224
      auto public_key = safe_get(cert).subject_public_key();
2✔
225
      return ffi_new_object(key, std::move(public_key));
2✔
226
   });
4✔
227
#else
228
   BOTAN_UNUSED(cert);
229
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
230
#endif
231
}
232

233
int botan_x509_cert_get_issuer_dn(
8✔
234
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
235
#if defined(BOTAN_HAS_X509_CERTIFICATES)
236
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
237
      auto issuer_info = c.issuer_info(key);
238
      if(index < issuer_info.size()) {
239
         // TODO(Botan4) change the type of out and remove this cast
240
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
241
      } else {
242
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
243
      }
244
   });
245
#else
246
   BOTAN_UNUSED(cert, key, index, out, out_len);
247
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
248
#endif
249
}
250

251
int botan_x509_cert_get_issuer_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
252
#if defined(BOTAN_HAS_X509_CERTIFICATES)
253
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
254
      if(Botan::any_null_pointers(count)) {
255
         return BOTAN_FFI_ERROR_NULL_POINTER;
256
      }
257

258
      *count = c.issuer_info(key).size();
259
      return BOTAN_FFI_SUCCESS;
260
   });
261
#else
262
   BOTAN_UNUSED(cert, key, count);
263
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
264
#endif
265
}
266

267
int botan_x509_cert_get_subject_dn(
8✔
268
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
269
#if defined(BOTAN_HAS_X509_CERTIFICATES)
270
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
271
      auto subject_info = c.subject_info(key);
272
      if(index < subject_info.size()) {
273
         // TODO(Botan4) change the type of out and remove this cast
274
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
275
      } else {
276
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
277
      }
278
   });
279
#else
280
   BOTAN_UNUSED(cert, key, index, out, out_len);
281
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
282
#endif
283
}
284

285
int botan_x509_cert_get_subject_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
286
#if defined(BOTAN_HAS_X509_CERTIFICATES)
287
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
288
      if(Botan::any_null_pointers(count)) {
289
         return BOTAN_FFI_ERROR_NULL_POINTER;
290
      }
291

292
      *count = c.subject_info(key).size();
293
      return BOTAN_FFI_SUCCESS;
294
   });
295
#else
296
   BOTAN_UNUSED(cert, key, count);
297
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
298
#endif
299
}
300

301
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
302
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
303
}
304

305
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
306
#if defined(BOTAN_HAS_X509_CERTIFICATES)
307
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
308
#else
309
   BOTAN_UNUSED(cert, ctx, view);
310
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
311
#endif
312
}
313

314
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
315
#if defined(BOTAN_HAS_X509_CERTIFICATES)
316
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
317
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
318
      if(c.allowed_usage(k)) {
319
         return BOTAN_FFI_SUCCESS;
320
      }
321
      return 1;
322
   });
323
#else
324
   BOTAN_UNUSED(cert, key_usage);
325
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
326
#endif
327
}
328

329
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
330
#if defined(BOTAN_HAS_X509_CERTIFICATES)
331
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
332
      if(Botan::any_null_pointers(oid)) {
333
         return BOTAN_FFI_ERROR_NULL_POINTER;
334
      }
335

336
      return c.has_ex_constraint(oid) ? BOTAN_FFI_SUCCESS : 1;
337
   });
338
#else
339
   BOTAN_UNUSED(cert, oid);
340
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
341
#endif
342
}
343

344
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
345
#if defined(BOTAN_HAS_X509_CERTIFICATES)
346
   return BOTAN_FFI_VISIT(
8✔
347
      cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? BOTAN_FFI_SUCCESS : 1; });
348
#else
349
   BOTAN_UNUSED(cert, oid);
350
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
351
#endif
352
}
353

354
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
36✔
355
#if defined(BOTAN_HAS_X509_CERTIFICATES)
356
   return BOTAN_FFI_CHECKED_DELETE(cert);
36✔
357
#else
358
   BOTAN_UNUSED(cert);
359
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
360
#endif
361
}
362

363
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
364
#if defined(BOTAN_HAS_X509_CERTIFICATES)
365
   return BOTAN_FFI_VISIT(cert,
6✔
366
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
367
#else
368
   BOTAN_UNUSED(cert, out, out_len);
369
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
370
#endif
371
}
372

373
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
374
#if defined(BOTAN_HAS_X509_CERTIFICATES)
375
   return BOTAN_FFI_VISIT(cert,
4✔
376
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
377
#else
378
   BOTAN_UNUSED(cert, out, out_len);
379
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
380
#endif
381
}
382

383
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
384
#if defined(BOTAN_HAS_X509_CERTIFICATES)
385
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
386
#else
387
   BOTAN_UNUSED(cert, time_since_epoch);
388
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
389
#endif
390
}
391

392
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
393
#if defined(BOTAN_HAS_X509_CERTIFICATES)
394
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
395
#else
396
   BOTAN_UNUSED(cert, time_since_epoch);
397
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
398
#endif
399
}
400

401
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
402
#if defined(BOTAN_HAS_X509_CERTIFICATES)
403
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
404
#else
405
   BOTAN_UNUSED(cert, out, out_len);
406
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
407
#endif
408
}
409

410
int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) {
1✔
411
#if defined(BOTAN_HAS_X509_CERTIFICATES)
412
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
2✔
413
      if(Botan::any_null_pointers(serial_number)) {
414
         return BOTAN_FFI_ERROR_NULL_POINTER;
415
      }
416

417
      auto serial_bn = Botan::BigInt::from_bytes(c.serial_number());
418
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
419
   });
420
#else
421
   BOTAN_UNUSED(cert, serial_number);
422
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
423
#endif
424
}
425

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

430
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
431
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
432
   });
433
#else
434
   BOTAN_UNUSED(cert, hash, out, out_len);
435
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
436
#endif
437
}
438

439
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
440
#if defined(BOTAN_HAS_X509_CERTIFICATES)
441
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
442
#else
443
   BOTAN_UNUSED(cert, out, out_len);
444
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
445
#endif
446
}
447

448
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
449
#if defined(BOTAN_HAS_X509_CERTIFICATES)
450
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
451
#else
452
   BOTAN_UNUSED(cert, out, out_len);
453
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
454
#endif
455
}
456

457
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
458
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
459
}
460

461
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
462
#if defined(BOTAN_HAS_X509_CERTIFICATES)
463
   return BOTAN_FFI_VISIT(cert,
6✔
464
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
465
#else
466
   BOTAN_UNUSED(cert, ctx, view);
467
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
468
#endif
469
}
470

471
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
472
#if defined(BOTAN_HAS_X509_CERTIFICATES)
473
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
474
      if(Botan::any_null_pointers(type)) {
475
         return BOTAN_FFI_ERROR_NULL_POINTER;
476
      }
477

478
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
479
      if(!mapped_type.has_value()) {
480
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
481
      }
482

483
      *type = mapped_type.value();
484
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
485
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
486
      }
487

488
      return BOTAN_FFI_SUCCESS;
489
   });
490
#else
491
   BOTAN_UNUSED(name, type);
492
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
493
#endif
494
}
495

496
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
497
                                              botan_view_ctx ctx,
498
                                              botan_view_str_fn view) {
499
#if defined(BOTAN_HAS_X509_CERTIFICATES)
500
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
501
      const auto type = to_botan_x509_general_name_types(n.type_code());
502
      if(!type) {
503
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
504
      }
505

506
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
507
         type != BOTAN_X509_IP_ADDRESS) {
508
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
509
      }
510

511
      return invoke_view_callback(view, ctx, n.name());
512
   });
513
#else
514
   BOTAN_UNUSED(name, ctx, view);
515
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
516
#endif
517
}
518

519
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
520
                                              botan_view_ctx ctx,
521
                                              botan_view_bin_fn view) {
522
#if defined(BOTAN_HAS_X509_CERTIFICATES)
523
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
524
      const auto type = to_botan_x509_general_name_types(n.type_code());
525
      if(!type) {
526
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
527
      }
528

529
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
530
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
531
      }
532

533
      return invoke_view_callback(view, ctx, n.binary_name());
534
   });
535
#else
536
   BOTAN_UNUSED(name, ctx, view);
537
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
538
#endif
539
}
540

541
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
542
#if defined(BOTAN_HAS_X509_CERTIFICATES)
543
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
544
#else
545
   BOTAN_UNUSED(name);
546
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
547
#endif
548
}
549

550
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
551
                                               size_t index,
552
                                               botan_x509_general_name_t* constraint) {
553
#if defined(BOTAN_HAS_X509_CERTIFICATES)
554
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
555
      if(Botan::any_null_pointers(constraint)) {
556
         return BOTAN_FFI_ERROR_NULL_POINTER;
557
      }
558

559
      const auto& constraints = c.name_constraints().permitted();
560
      if(index >= constraints.size()) {
561
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
562
      }
563

564
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
565
   });
566
#else
567
   BOTAN_UNUSED(cert, index, constraint);
568
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
569
#endif
570
}
571

572
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
573
#if defined(BOTAN_HAS_X509_CERTIFICATES)
574
   if(Botan::any_null_pointers(count)) {
1✔
575
      return BOTAN_FFI_ERROR_NULL_POINTER;
576
   }
577

578
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
579
#else
580
   BOTAN_UNUSED(cert, count);
581
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
582
#endif
583
}
584

585
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
586
                                              size_t index,
587
                                              botan_x509_general_name_t* constraint) {
588
#if defined(BOTAN_HAS_X509_CERTIFICATES)
589
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
590
      if(Botan::any_null_pointers(constraint)) {
591
         return BOTAN_FFI_ERROR_NULL_POINTER;
592
      }
593

594
      const auto& constraints = c.name_constraints().excluded();
595
      if(index >= constraints.size()) {
596
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
597
      }
598

599
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
600
   });
601
#else
602
   BOTAN_UNUSED(cert, index, constraint);
603
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
604
#endif
605
}
606

607
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
608
#if defined(BOTAN_HAS_X509_CERTIFICATES)
609
   if(Botan::any_null_pointers(count)) {
1✔
610
      return BOTAN_FFI_ERROR_NULL_POINTER;
611
   }
612

613
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
614
#else
615
   BOTAN_UNUSED(cert, count);
616
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
617
#endif
618
}
619

620
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
621
                                              size_t index,
622
                                              botan_x509_general_name_t* alt_name) {
623
#if defined(BOTAN_HAS_X509_CERTIFICATES)
624
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
625
      if(Botan::any_null_pointers(alt_name)) {
626
         return BOTAN_FFI_ERROR_NULL_POINTER;
627
      }
628

629
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
630
         return BOTAN_FFI_ERROR_NO_VALUE;
631
      }
632

633
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
634
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
635
      }
636

637
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
638
   });
639
#else
640
   BOTAN_UNUSED(cert, index, alt_name);
641
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
642
#endif
643
}
644

645
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
646
#if defined(BOTAN_HAS_X509_CERTIFICATES)
647
   if(Botan::any_null_pointers(count)) {
6✔
648
      return BOTAN_FFI_ERROR_NULL_POINTER;
649
   }
650

651
   return BOTAN_FFI_VISIT(
12✔
652
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
653
#else
654
   BOTAN_UNUSED(cert, count);
655
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
656
#endif
657
}
658

659
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
660
                                             size_t index,
661
                                             botan_x509_general_name_t* alt_name) {
662
#if defined(BOTAN_HAS_X509_CERTIFICATES)
663
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
664
      if(Botan::any_null_pointers(alt_name)) {
665
         return BOTAN_FFI_ERROR_NULL_POINTER;
666
      }
667

668
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
669
         return BOTAN_FFI_ERROR_NO_VALUE;
670
      }
671

672
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
673
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
674
      }
675

676
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
677
   });
678
#else
679
   BOTAN_UNUSED(cert, index, alt_name);
680
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
681
#endif
682
}
683

684
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
685
#if defined(BOTAN_HAS_X509_CERTIFICATES)
686
   if(Botan::any_null_pointers(count)) {
6✔
687
      return BOTAN_FFI_ERROR_NULL_POINTER;
688
   }
689

690
   return BOTAN_FFI_VISIT(
12✔
691
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.issuer_alt_name()); });
692
#else
693
   BOTAN_UNUSED(cert, count);
694
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
695
#endif
696
}
697

698
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
699
   if(hostname == nullptr) {
6✔
700
      return BOTAN_FFI_ERROR_NULL_POINTER;
701
   }
702

703
#if defined(BOTAN_HAS_X509_CERTIFICATES)
704
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
705
#else
706
   BOTAN_UNUSED(cert);
707
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
708
#endif
709
}
710

711
int botan_x509_cert_verify(int* result_code,
4✔
712
                           botan_x509_cert_t cert,
713
                           const botan_x509_cert_t* intermediates,
714
                           size_t intermediates_len,
715
                           const botan_x509_cert_t* trusted,
716
                           size_t trusted_len,
717
                           const char* trusted_path,
718
                           size_t required_strength,
719
                           const char* hostname_cstr,
720
                           uint64_t reference_time) {
721
   if(required_strength == 0) {
4✔
722
      required_strength = 110;
3✔
723
   }
724

725
#if defined(BOTAN_HAS_X509_CERTIFICATES)
726
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
727
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
728
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
729
      const auto validation_time = reference_time == 0
4✔
730
                                      ? std::chrono::system_clock::now()
4✔
731
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
732

733
      std::vector<Botan::X509_Certificate> end_certs;
4✔
734
      end_certs.push_back(safe_get(cert));
4✔
735
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
736
         end_certs.push_back(safe_get(intermediates[i]));
5✔
737
      }
738

739
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
740
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
741
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
742

743
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
744
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
745
         trusted_roots.push_back(trusted_from_path.get());
×
746
      }
747

748
      if(trusted_len > 0) {
4✔
749
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
750
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
751
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
752
         }
753
         trusted_roots.push_back(trusted_extra.get());
4✔
754
      }
755

756
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
757

758
      auto validation_result =
4✔
759
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
760

761
      if(result_code != nullptr) {
4✔
762
         *result_code = static_cast<int>(validation_result.result());
4✔
763
      }
764

765
      if(validation_result.successful_validation()) {
4✔
766
         return 0;
767
      } else {
768
         return 1;
3✔
769
      }
770
   });
4✔
771
#else
772
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
773
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
774
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
775
#endif
776
}
777

778
const char* botan_x509_cert_validation_status(int code) {
11✔
779
   if(code < 0) {
11✔
780
      return nullptr;
781
   }
782

783
#if defined(BOTAN_HAS_X509_CERTIFICATES)
784
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
785
   return Botan::to_string(sc);
11✔
786
#else
787
   return nullptr;
788
#endif
789
}
790

791
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
792
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
793
      return BOTAN_FFI_ERROR_NULL_POINTER;
794
   }
795

796
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
797

798
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
799
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
800
      return ffi_new_object(crl_obj, std::move(c));
14✔
801
   });
14✔
802

803
#else
804
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
805
#endif
806
}
807

808
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
809
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
810
      return BOTAN_FFI_ERROR_NULL_POINTER;
811
   }
812

813
#if defined(BOTAN_HAS_X509_CERTIFICATES)
814
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
815
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
816
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
817
      return ffi_new_object(crl_obj, std::move(c));
1✔
818
   });
3✔
819
#else
820
   BOTAN_UNUSED(crl_bits_len);
821
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
822
#endif
823
}
824

825
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
826
#if defined(BOTAN_HAS_X509_CERTIFICATES)
827
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
828
      if(Botan::any_null_pointers(time_since_epoch)) {
829
         return BOTAN_FFI_ERROR_NULL_POINTER;
830
      }
831
      *time_since_epoch = c.this_update().time_since_epoch();
832
      return BOTAN_FFI_SUCCESS;
833
   });
834
#else
835
   BOTAN_UNUSED(crl, time_since_epoch);
836
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
837
#endif
838
}
839

840
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
5✔
841
#if defined(BOTAN_HAS_X509_CERTIFICATES)
842
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
10✔
843
      const auto& time = c.next_update();
844
      if(!time.time_is_set()) {
845
         return BOTAN_FFI_ERROR_NO_VALUE;
846
      }
847

848
      if(Botan::any_null_pointers(time_since_epoch)) {
849
         return BOTAN_FFI_ERROR_NULL_POINTER;
850
      }
851

852
      *time_since_epoch = c.next_update().time_since_epoch();
853
      return BOTAN_FFI_SUCCESS;
854
   });
855
#else
856
   BOTAN_UNUSED(crl, time_since_epoch);
857
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
858
#endif
859
}
860

861
int botan_x509_crl_create(botan_x509_crl_t* crl_obj,
2✔
862
                          botan_rng_t rng,
863
                          botan_x509_cert_t ca_cert,
864
                          botan_privkey_t ca_key,
865
                          uint64_t issue_time,
866
                          uint32_t next_update,
867
                          const char* hash_fn,
868
                          const char* padding) {
869
   if(Botan::any_null_pointers(crl_obj)) {
2✔
870
      return BOTAN_FFI_ERROR_NULL_POINTER;
871
   }
872
#if defined(BOTAN_HAS_X509_CERTIFICATES)
873
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
874
      auto& rng_ = safe_get(rng);
2✔
875
      auto ca = Botan::X509_CA(
2✔
876
         safe_get(ca_cert), safe_get(ca_key), default_from_ptr(hash_fn), default_from_ptr(padding), rng_);
4✔
877
      auto crl = std::make_unique<Botan::X509_CRL>(
2✔
878
         ca.new_crl(rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
2✔
879
      return ffi_new_object(crl_obj, std::move(crl));
4✔
880
   });
4✔
881
#else
882
   BOTAN_UNUSED(rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update);
883
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
884
#endif
885
}
886

887
int botan_x509_crl_entry_create(botan_x509_crl_entry_t* entry, botan_x509_cert_t cert, int reason_code) {
2✔
888
   if(Botan::any_null_pointers(entry)) {
2✔
889
      return BOTAN_FFI_ERROR_NULL_POINTER;
890
   }
891
#if defined(BOTAN_HAS_X509_CERTIFICATES)
892
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
893
      return ffi_new_object(
2✔
894
         entry, std::make_unique<Botan::CRL_Entry>(safe_get(cert), static_cast<Botan::CRL_Code>(reason_code)));
4✔
895
   });
2✔
896
#else
897
   BOTAN_UNUSED(cert, reason_code);
898
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
899
#endif
900
}
901

902
int botan_x509_crl_update(botan_x509_crl_t* crl_obj,
4✔
903
                          botan_x509_crl_t last_crl,
904
                          botan_rng_t rng,
905
                          botan_x509_cert_t ca_cert,
906
                          botan_privkey_t ca_key,
907
                          uint64_t issue_time,
908
                          uint32_t next_update,
909
                          const botan_x509_crl_entry_t* new_entries,
910
                          size_t new_entries_len,
911
                          const char* hash_fn,
912
                          const char* padding) {
913
   if(Botan::any_null_pointers(crl_obj)) {
4✔
914
      return BOTAN_FFI_ERROR_NULL_POINTER;
915
   }
916
   if(new_entries_len > 0 && Botan::any_null_pointers(new_entries)) {
4✔
917
      return BOTAN_FFI_ERROR_NULL_POINTER;
918
   }
919
#if defined(BOTAN_HAS_X509_CERTIFICATES)
920
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
921
      auto& rng_ = safe_get(rng);
3✔
922
      auto ca = Botan::X509_CA(
3✔
923
         safe_get(ca_cert), safe_get(ca_key), default_from_ptr(hash_fn), default_from_ptr(padding), rng_);
6✔
924

925
      std::vector<Botan::CRL_Entry> entries;
3✔
926
      entries.reserve(new_entries_len);
3✔
927
      for(size_t i = 0; i < new_entries_len; i++) {
5✔
928
         entries.push_back(safe_get(new_entries[i]));
2✔
929
      }
930

931
      auto crl = std::make_unique<Botan::X509_CRL>(ca.update_crl(
6✔
932
         safe_get(last_crl), entries, rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
6✔
933
      return ffi_new_object(crl_obj, std::move(crl));
6✔
934
   });
6✔
935
#else
936
   BOTAN_UNUSED(
937
      last_crl, rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update, new_entries, new_entries_len);
938
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
939
#endif
940
}
941

942
int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key) {
3✔
943
#if defined(BOTAN_HAS_X509_CERTIFICATES)
944
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) -> int { return c.check_signature(safe_get(key)) ? 1 : 0; });
6✔
945
#else
946
   BOTAN_UNUSED(crl, key);
947
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
948
#endif
949
}
950

951
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
13✔
952
#if defined(BOTAN_HAS_X509_CERTIFICATES)
953
   return BOTAN_FFI_CHECKED_DELETE(crl);
13✔
954
#else
955
   BOTAN_UNUSED(crl);
956
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
957
#endif
958
}
959

960
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
961
#if defined(BOTAN_HAS_X509_CERTIFICATES)
962
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
963
#else
964
   BOTAN_UNUSED(cert);
965
   BOTAN_UNUSED(crl);
966
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
967
#endif
968
}
969

970
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
8✔
971
#if defined(BOTAN_HAS_X509_CERTIFICATES)
972
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
16✔
973
      const auto& entries = c.get_revoked();
974
      if(index >= entries.size()) {
975
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
976
      }
977

978
      if(Botan::any_null_pointers(entry)) {
979
         return BOTAN_FFI_ERROR_NULL_POINTER;
980
      }
981

982
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
983
   });
984
#else
985
   BOTAN_UNUSED(crl, index, entry);
986
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
987
#endif
988
}
989

990
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
4✔
991
#if defined(BOTAN_HAS_X509_CERTIFICATES)
992
   if(Botan::any_null_pointers(count)) {
4✔
993
      return BOTAN_FFI_ERROR_NULL_POINTER;
994
   }
995

996
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
8✔
997
#else
998
   BOTAN_UNUSED(crl, count);
999
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1000
#endif
1001
}
1002

1003
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
6✔
1004
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1005
   return BOTAN_FFI_CHECKED_DELETE(entry);
6✔
1006
#else
1007
   BOTAN_UNUSED(entry);
1008
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1009
#endif
1010
}
1011

1012
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
3✔
1013
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1014
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1015
      if(Botan::any_null_pointers(reason_code)) {
1016
         return BOTAN_FFI_ERROR_NULL_POINTER;
1017
      }
1018

1019
      *reason_code = static_cast<int>(e.reason_code());
1020
      return BOTAN_FFI_SUCCESS;
1021
   });
1022
#else
1023
   BOTAN_UNUSED(entry, reason_code);
1024
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1025
#endif
1026
}
1027

1028
int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) {
3✔
1029
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1030
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1031
      if(Botan::any_null_pointers(serial_number)) {
1032
         return BOTAN_FFI_ERROR_NULL_POINTER;
1033
      }
1034

1035
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
1036
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
1037
   });
1038
#else
1039
   BOTAN_UNUSED(entry, serial_number);
1040
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1041
#endif
1042
}
1043

1044
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
1045
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1046
   return BOTAN_FFI_VISIT(
2✔
1047
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
1048
#else
1049
   BOTAN_UNUSED(entry, ctx, view);
1050
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1051
#endif
1052
}
1053

1054
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
3✔
1055
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1056
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1057
      if(Botan::any_null_pointers(time_since_epoch)) {
1058
         return BOTAN_FFI_ERROR_NULL_POINTER;
1059
      }
1060

1061
      *time_since_epoch = e.expire_time().time_since_epoch();
1062
      return BOTAN_FFI_SUCCESS;
1063
   });
1064
#else
1065
   BOTAN_UNUSED(entry, time_since_epoch);
1066
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1067
#endif
1068
}
1069

1070
int botan_x509_cert_verify_with_crl(int* result_code,
20✔
1071
                                    botan_x509_cert_t cert,
1072
                                    const botan_x509_cert_t* intermediates,
1073
                                    size_t intermediates_len,
1074
                                    const botan_x509_cert_t* trusted,
1075
                                    size_t trusted_len,
1076
                                    const botan_x509_crl_t* crls,
1077
                                    size_t crls_len,
1078
                                    const char* trusted_path,
1079
                                    size_t required_strength,
1080
                                    const char* hostname_cstr,
1081
                                    uint64_t reference_time) {
1082
   if(required_strength == 0) {
20✔
1083
      required_strength = 110;
10✔
1084
   }
1085

1086
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1087
   return ffi_guard_thunk(__func__, [=]() -> int {
20✔
1088
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
22✔
1089
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
20✔
1090
      const auto validation_time = reference_time == 0
20✔
1091
                                      ? std::chrono::system_clock::now()
20✔
1092
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1093

1094
      std::vector<Botan::X509_Certificate> end_certs;
20✔
1095
      end_certs.push_back(safe_get(cert));
20✔
1096
      for(size_t i = 0; i != intermediates_len; ++i) {
38✔
1097
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1098
      }
1099

1100
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
20✔
1101
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
20✔
1102
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
20✔
1103
      std::vector<Botan::Certificate_Store*> trusted_roots;
20✔
1104

1105
      if(trusted_path != nullptr && *trusted_path != 0) {
20✔
1106
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1107
         trusted_roots.push_back(trusted_from_path.get());
2✔
1108
      }
1109

1110
      if(trusted_len > 0) {
20✔
1111
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
34✔
1112
         for(size_t i = 0; i != trusted_len; ++i) {
34✔
1113
            trusted_extra->add_certificate(safe_get(trusted[i]));
17✔
1114
         }
1115
         trusted_roots.push_back(trusted_extra.get());
17✔
1116
      }
1117

1118
      if(crls_len > 0) {
20✔
1119
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
26✔
1120
         for(size_t i = 0; i != crls_len; ++i) {
29✔
1121
            trusted_crls->add_crl(safe_get(crls[i]));
16✔
1122
         }
1123
         trusted_roots.push_back(trusted_crls.get());
13✔
1124
      }
1125

1126
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
40✔
1127

1128
      auto validation_result =
20✔
1129
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
20✔
1130

1131
      if(result_code != nullptr) {
20✔
1132
         *result_code = static_cast<int>(validation_result.result());
20✔
1133
      }
1134

1135
      if(validation_result.successful_validation()) {
20✔
1136
         return 0;
1137
      } else {
1138
         return 1;
10✔
1139
      }
1140
   });
22✔
1141
#else
1142
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1143
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1144
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1145
#endif
1146
}
1147
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc