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

randombit / botan / 21404660566

27 Jan 2026 04:09PM UTC coverage: 90.079% (+0.002%) from 90.077%
21404660566

Pull #5166

github

web-flow
Merge 8ad6b5c28 into 0d718b146
Pull Request #5166: Add CRL creation to FFI

102209 of 113466 relevant lines covered (90.08%)

11417695.65 hits per line

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

94.81
/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/data_src.h>
17
   #include <botan/x509_crl.h>
18
   #include <botan/x509cert.h>
19
   #include <botan/x509path.h>
20
   #include <botan/internal/ffi_mp.h>
21
   #include <botan/internal/ffi_oid.h>
22
#endif
23

24
#if defined(BOTAN_HAS_X509_CERTIFICATES)
25
namespace {
26
std::chrono::system_clock::time_point timepoint_from_timestamp(uint64_t time_since_epoch) {
5✔
27
   return std::chrono::system_clock::time_point(std::chrono::seconds(time_since_epoch));
5✔
28
}
29

30
std::string default_from_ptr(const char* value) {
10✔
31
   std::string ret;
10✔
32
   if(value != nullptr) {
10✔
33
      ret = value;
×
34
   }
35
   return ret;
10✔
36
}
×
37

38
}  // namespace
39
#endif
40

41
extern "C" {
42

43
using namespace Botan_FFI;
44

45
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
35✔
46
   if(cert_obj == nullptr || cert_path == nullptr) {
35✔
47
      return BOTAN_FFI_ERROR_NULL_POINTER;
48
   }
49

50
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
51

52
   return ffi_guard_thunk(__func__, [=]() -> int {
35✔
53
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
35✔
54
      return ffi_new_object(cert_obj, std::move(c));
35✔
55
   });
70✔
56

57
#else
58
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
59
#endif
60
}
61

62
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
63
   if(cert_obj == nullptr) {
1✔
64
      return BOTAN_FFI_ERROR_NULL_POINTER;
65
   }
66

67
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
68

69
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
70
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
71
      return ffi_new_object(cert_obj, std::move(c));
1✔
72
   });
2✔
73

74
#else
75
   BOTAN_UNUSED(cert);
76
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
77
#endif
78
}
79

80
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
81
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
82
      return BOTAN_FFI_ERROR_NULL_POINTER;
83
   }
84

85
#if defined(BOTAN_HAS_X509_CERTIFICATES)
86
   return ffi_guard_thunk(__func__, [=]() -> int {
×
87
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
88
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
89
      return ffi_new_object(cert_obj, std::move(c));
×
90
   });
×
91
#else
92
   BOTAN_UNUSED(cert_bits_len);
93
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
94
#endif
95
}
96

97
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
98
#if defined(BOTAN_HAS_X509_CERTIFICATES)
99
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? 1 : 0; });
4✔
100
#else
101
   BOTAN_UNUSED(cert);
102
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
103
#endif
104
}
105

106
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
107
#if defined(BOTAN_HAS_X509_CERTIFICATES)
108
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
109
      if(Botan::any_null_pointers(path_limit)) {
110
         return BOTAN_FFI_ERROR_NULL_POINTER;
111
      }
112

113
      if(const auto path_len = c.path_length_constraint()) {
114
         *path_limit = path_len.value();
115
         return BOTAN_FFI_SUCCESS;
116
      } else {
117
         return BOTAN_FFI_ERROR_NO_VALUE;
118
      }
119
   });
120
#else
121
   BOTAN_UNUSED(cert, path_limit);
122
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
123
#endif
124
}
125

126
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
127
   if(key == nullptr) {
2✔
128
      return BOTAN_FFI_ERROR_NULL_POINTER;
129
   }
130

131
   *key = nullptr;
2✔
132

133
#if defined(BOTAN_HAS_X509_CERTIFICATES)
134
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
135
      auto public_key = safe_get(cert).subject_public_key();
2✔
136
      return ffi_new_object(key, std::move(public_key));
2✔
137
   });
4✔
138
#else
139
   BOTAN_UNUSED(cert);
140
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
141
#endif
142
}
143

144
int botan_x509_cert_get_issuer_dn(
8✔
145
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
146
#if defined(BOTAN_HAS_X509_CERTIFICATES)
147
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
148
      auto issuer_info = c.issuer_info(key);
149
      if(index < issuer_info.size()) {
150
         // TODO(Botan4) change the type of out and remove this cast
151
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
152
      } else {
153
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
154
      }
155
   });
156
#else
157
   BOTAN_UNUSED(cert, key, index, out, out_len);
158
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
159
#endif
160
}
161

162
int botan_x509_cert_get_issuer_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
163
#if defined(BOTAN_HAS_X509_CERTIFICATES)
164
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
165
      if(Botan::any_null_pointers(count)) {
166
         return BOTAN_FFI_ERROR_NULL_POINTER;
167
      }
168

169
      *count = c.issuer_info(key).size();
170
      return BOTAN_FFI_SUCCESS;
171
   });
172
#else
173
   BOTAN_UNUSED(cert, key, count);
174
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
175
#endif
176
}
177

178
int botan_x509_cert_get_subject_dn(
8✔
179
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
180
#if defined(BOTAN_HAS_X509_CERTIFICATES)
181
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
182
      auto subject_info = c.subject_info(key);
183
      if(index < subject_info.size()) {
184
         // TODO(Botan4) change the type of out and remove this cast
185
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
186
      } else {
187
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
188
      }
189
   });
190
#else
191
   BOTAN_UNUSED(cert, key, index, out, out_len);
192
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
193
#endif
194
}
195

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

203
      *count = c.subject_info(key).size();
204
      return BOTAN_FFI_SUCCESS;
205
   });
206
#else
207
   BOTAN_UNUSED(cert, key, count);
208
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
209
#endif
210
}
211

212
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
213
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
214
}
215

216
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
217
#if defined(BOTAN_HAS_X509_CERTIFICATES)
218
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
219
#else
220
   BOTAN_UNUSED(cert, ctx, view);
221
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
222
#endif
223
}
224

225
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
226
#if defined(BOTAN_HAS_X509_CERTIFICATES)
227
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
228
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
229
      if(c.allowed_usage(k)) {
230
         return BOTAN_FFI_SUCCESS;
231
      }
232
      return 1;
233
   });
234
#else
235
   BOTAN_UNUSED(cert, key_usage);
236
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
237
#endif
238
}
239

240
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
241
#if defined(BOTAN_HAS_X509_CERTIFICATES)
242
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
243
      if(Botan::any_null_pointers(oid)) {
244
         return BOTAN_FFI_ERROR_NULL_POINTER;
245
      }
246

247
      return c.has_ex_constraint(oid) ? BOTAN_FFI_SUCCESS : 1;
248
   });
249
#else
250
   BOTAN_UNUSED(cert, oid);
251
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
252
#endif
253
}
254

255
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
256
#if defined(BOTAN_HAS_X509_CERTIFICATES)
257
   return BOTAN_FFI_VISIT(
8✔
258
      cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? BOTAN_FFI_SUCCESS : 1; });
259
#else
260
   BOTAN_UNUSED(cert, oid);
261
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
262
#endif
263
}
264

265
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
36✔
266
#if defined(BOTAN_HAS_X509_CERTIFICATES)
267
   return BOTAN_FFI_CHECKED_DELETE(cert);
36✔
268
#else
269
   BOTAN_UNUSED(cert);
270
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
271
#endif
272
}
273

274
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
275
#if defined(BOTAN_HAS_X509_CERTIFICATES)
276
   return BOTAN_FFI_VISIT(cert,
6✔
277
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
278
#else
279
   BOTAN_UNUSED(cert, out, out_len);
280
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
281
#endif
282
}
283

284
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
285
#if defined(BOTAN_HAS_X509_CERTIFICATES)
286
   return BOTAN_FFI_VISIT(cert,
4✔
287
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
288
#else
289
   BOTAN_UNUSED(cert, out, out_len);
290
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
291
#endif
292
}
293

294
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
295
#if defined(BOTAN_HAS_X509_CERTIFICATES)
296
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
297
#else
298
   BOTAN_UNUSED(cert, time_since_epoch);
299
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
300
#endif
301
}
302

303
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
304
#if defined(BOTAN_HAS_X509_CERTIFICATES)
305
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
306
#else
307
   BOTAN_UNUSED(cert, time_since_epoch);
308
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
309
#endif
310
}
311

312
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
313
#if defined(BOTAN_HAS_X509_CERTIFICATES)
314
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
315
#else
316
   BOTAN_UNUSED(cert, out, out_len);
317
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
318
#endif
319
}
320

321
int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) {
1✔
322
#if defined(BOTAN_HAS_X509_CERTIFICATES)
323
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
2✔
324
      if(Botan::any_null_pointers(serial_number)) {
325
         return BOTAN_FFI_ERROR_NULL_POINTER;
326
      }
327

328
      auto serial_bn = Botan::BigInt::from_bytes(c.serial_number());
329
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
330
   });
331
#else
332
   BOTAN_UNUSED(cert, serial_number);
333
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
334
#endif
335
}
336

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

341
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
342
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
343
   });
344
#else
345
   BOTAN_UNUSED(cert, hash, out, out_len);
346
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
347
#endif
348
}
349

350
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
351
#if defined(BOTAN_HAS_X509_CERTIFICATES)
352
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
353
#else
354
   BOTAN_UNUSED(cert, out, out_len);
355
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
356
#endif
357
}
358

359
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
360
#if defined(BOTAN_HAS_X509_CERTIFICATES)
361
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
362
#else
363
   BOTAN_UNUSED(cert, out, out_len);
364
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
365
#endif
366
}
367

368
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
369
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
370
}
371

372
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
373
#if defined(BOTAN_HAS_X509_CERTIFICATES)
374
   return BOTAN_FFI_VISIT(cert,
6✔
375
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
376
#else
377
   BOTAN_UNUSED(cert, ctx, view);
378
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
379
#endif
380
}
381
}
382

383
namespace {
384

385
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
301✔
386
   using Type = Botan::GeneralName::NameType;
301✔
387
   switch(gn_type) {
301✔
388
      case Type::Unknown:
1✔
389
         return std::nullopt;
1✔
390
      case Type::RFC822:
83✔
391
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
392
      case Type::DNS:
73✔
393
         return BOTAN_X509_DNS_NAME;
73✔
394
      case Type::URI:
28✔
395
         return BOTAN_X509_URI;
28✔
396
      case Type::DN:
95✔
397
         return BOTAN_X509_DIRECTORY_NAME;
95✔
398
      case Type::IPv4:
21✔
399
         return BOTAN_X509_IP_ADDRESS;
21✔
400
      case Type::Other:
×
401
         return BOTAN_X509_OTHER_NAME;
×
402
   }
403

404
   BOTAN_ASSERT_UNREACHABLE();
×
405
}
406

407
}  // namespace
408

409
extern "C" {
410

411
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
412
#if defined(BOTAN_HAS_X509_CERTIFICATES)
413
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
414
      if(Botan::any_null_pointers(type)) {
415
         return BOTAN_FFI_ERROR_NULL_POINTER;
416
      }
417

418
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
419
      if(!mapped_type.has_value()) {
420
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
421
      }
422

423
      *type = mapped_type.value();
424
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
425
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
426
      }
427

428
      return BOTAN_FFI_SUCCESS;
429
   });
430
#else
431
   BOTAN_UNUSED(name, type);
432
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
433
#endif
434
}
435

436
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
437
                                              botan_view_ctx ctx,
438
                                              botan_view_str_fn view) {
439
#if defined(BOTAN_HAS_X509_CERTIFICATES)
440
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
441
      const auto type = to_botan_x509_general_name_types(n.type_code());
442
      if(!type) {
443
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
444
      }
445

446
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
447
         type != BOTAN_X509_IP_ADDRESS) {
448
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
449
      }
450

451
      return invoke_view_callback(view, ctx, n.name());
452
   });
453
#else
454
   BOTAN_UNUSED(name, ctx, view);
455
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
456
#endif
457
}
458

459
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
460
                                              botan_view_ctx ctx,
461
                                              botan_view_bin_fn view) {
462
#if defined(BOTAN_HAS_X509_CERTIFICATES)
463
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
464
      const auto type = to_botan_x509_general_name_types(n.type_code());
465
      if(!type) {
466
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
467
      }
468

469
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
470
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
471
      }
472

473
      return invoke_view_callback(view, ctx, n.binary_name());
474
   });
475
#else
476
   BOTAN_UNUSED(name, ctx, view);
477
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
478
#endif
479
}
480

481
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
482
#if defined(BOTAN_HAS_X509_CERTIFICATES)
483
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
484
#else
485
   BOTAN_UNUSED(name);
486
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
487
#endif
488
}
489

490
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
491
                                               size_t index,
492
                                               botan_x509_general_name_t* constraint) {
493
#if defined(BOTAN_HAS_X509_CERTIFICATES)
494
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
495
      if(Botan::any_null_pointers(constraint)) {
496
         return BOTAN_FFI_ERROR_NULL_POINTER;
497
      }
498

499
      const auto& constraints = c.name_constraints().permitted();
500
      if(index >= constraints.size()) {
501
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
502
      }
503

504
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
505
   });
506
#else
507
   BOTAN_UNUSED(cert, index, constraint);
508
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
509
#endif
510
}
511

512
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
513
#if defined(BOTAN_HAS_X509_CERTIFICATES)
514
   if(Botan::any_null_pointers(count)) {
1✔
515
      return BOTAN_FFI_ERROR_NULL_POINTER;
516
   }
517

518
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
519
#else
520
   BOTAN_UNUSED(cert, count);
521
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
522
#endif
523
}
524

525
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
526
                                              size_t index,
527
                                              botan_x509_general_name_t* constraint) {
528
#if defined(BOTAN_HAS_X509_CERTIFICATES)
529
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
530
      if(Botan::any_null_pointers(constraint)) {
531
         return BOTAN_FFI_ERROR_NULL_POINTER;
532
      }
533

534
      const auto& constraints = c.name_constraints().excluded();
535
      if(index >= constraints.size()) {
536
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
537
      }
538

539
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
540
   });
541
#else
542
   BOTAN_UNUSED(cert, index, constraint);
543
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
544
#endif
545
}
546

547
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
548
#if defined(BOTAN_HAS_X509_CERTIFICATES)
549
   if(Botan::any_null_pointers(count)) {
1✔
550
      return BOTAN_FFI_ERROR_NULL_POINTER;
551
   }
552

553
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
554
#else
555
   BOTAN_UNUSED(cert, count);
556
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
557
#endif
558
}
559
}
560

561
namespace {
562

563
/**
564
 * As specified in RFC 5280 Section 4.2.1.6. alternative names essentially are a
565
 * collection of GeneralNames. This allows mapping a single entry of @p altnames
566
 * to a GeneralName by its @p index. If the index is out of range, std::nullopt
567
 * is returned.
568
 *
569
 * NOTE: if the set of alternative name types handled here is extended,
570
 *       count_general_names_in() must be updated accordingly!
571
 */
572
std::optional<Botan::GeneralName> extract_general_name_at(const Botan::AlternativeName& altnames, size_t index) {
132✔
573
   if(index < altnames.email().size()) {
132✔
574
      auto itr = altnames.email().begin();
12✔
575
      std::advance(itr, index);
12✔
576
      return Botan::GeneralName::email(*itr);
36✔
577
   }
578
   index -= altnames.email().size();
120✔
579

580
   if(index < altnames.dns().size()) {
120✔
581
      auto itr = altnames.dns().begin();
36✔
582
      std::advance(itr, index);
36✔
583
      return Botan::GeneralName::dns(*itr);
108✔
584
   }
585
   index -= altnames.dns().size();
84✔
586

587
   if(index < altnames.directory_names().size()) {
84✔
588
      auto itr = altnames.directory_names().begin();
36✔
589
      std::advance(itr, index);
36✔
590
      return Botan::GeneralName::directory_name(*itr);
108✔
591
   }
592
   index -= altnames.directory_names().size();
48✔
593

594
   if(index < altnames.uris().size()) {
48✔
595
      auto itr = altnames.uris().begin();
24✔
596
      std::advance(itr, index);
24✔
597
      return Botan::GeneralName::uri(*itr);
72✔
598
   }
599
   index -= altnames.uris().size();
24✔
600

601
   if(index < altnames.ipv4_address().size()) {
24✔
602
      auto itr = altnames.ipv4_address().begin();
12✔
603
      std::advance(itr, index);
12✔
604
      return Botan::GeneralName::ipv4_address(*itr);
36✔
605
   }
606

607
   return std::nullopt;
12✔
608
}
609

610
/**
611
 * Counts the total number of GeneralNames contained in the given
612
 * AlternativeName @p alt_names.
613
 *
614
 * NOTE: if the set of alternative name types handled here is extended,
615
 *       extract_general_name_at() must be updated accordingly!
616
 */
617
size_t count_general_names_in(const Botan::AlternativeName& alt_names) {
12✔
618
   return alt_names.email().size() + alt_names.dns().size() + alt_names.directory_names().size() +
12✔
619
          alt_names.uris().size() + alt_names.ipv4_address().size();
12✔
620
}
621

622
}  // namespace
623

624
extern "C" {
625

626
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
627
                                              size_t index,
628
                                              botan_x509_general_name_t* alt_name) {
629
#if defined(BOTAN_HAS_X509_CERTIFICATES)
630
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
631
      if(Botan::any_null_pointers(alt_name)) {
632
         return BOTAN_FFI_ERROR_NULL_POINTER;
633
      }
634

635
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
636
         return BOTAN_FFI_ERROR_NO_VALUE;
637
      }
638

639
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
640
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
641
      }
642

643
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
644
   });
645
#else
646
   BOTAN_UNUSED(cert, index, alt_name);
647
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
648
#endif
649
}
650

651
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
652
#if defined(BOTAN_HAS_X509_CERTIFICATES)
653
   if(Botan::any_null_pointers(count)) {
6✔
654
      return BOTAN_FFI_ERROR_NULL_POINTER;
655
   }
656

657
   return BOTAN_FFI_VISIT(
12✔
658
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
659
#else
660
   BOTAN_UNUSED(cert, count);
661
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
662
#endif
663
}
664

665
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
666
                                             size_t index,
667
                                             botan_x509_general_name_t* alt_name) {
668
#if defined(BOTAN_HAS_X509_CERTIFICATES)
669
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
670
      if(Botan::any_null_pointers(alt_name)) {
671
         return BOTAN_FFI_ERROR_NULL_POINTER;
672
      }
673

674
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
675
         return BOTAN_FFI_ERROR_NO_VALUE;
676
      }
677

678
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
679
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
680
      }
681

682
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
683
   });
684
#else
685
   BOTAN_UNUSED(cert, index, alt_name);
686
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
687
#endif
688
}
689

690
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
691
#if defined(BOTAN_HAS_X509_CERTIFICATES)
692
   if(Botan::any_null_pointers(count)) {
6✔
693
      return BOTAN_FFI_ERROR_NULL_POINTER;
694
   }
695

696
   return BOTAN_FFI_VISIT(
12✔
697
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.issuer_alt_name()); });
698
#else
699
   BOTAN_UNUSED(cert, count);
700
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
701
#endif
702
}
703

704
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
705
   if(hostname == nullptr) {
6✔
706
      return BOTAN_FFI_ERROR_NULL_POINTER;
707
   }
708

709
#if defined(BOTAN_HAS_X509_CERTIFICATES)
710
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
711
#else
712
   BOTAN_UNUSED(cert);
713
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
714
#endif
715
}
716

717
int botan_x509_cert_verify(int* result_code,
4✔
718
                           botan_x509_cert_t cert,
719
                           const botan_x509_cert_t* intermediates,
720
                           size_t intermediates_len,
721
                           const botan_x509_cert_t* trusted,
722
                           size_t trusted_len,
723
                           const char* trusted_path,
724
                           size_t required_strength,
725
                           const char* hostname_cstr,
726
                           uint64_t reference_time) {
727
   if(required_strength == 0) {
4✔
728
      required_strength = 110;
3✔
729
   }
730

731
#if defined(BOTAN_HAS_X509_CERTIFICATES)
732
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
733
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
734
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
735
      const auto validation_time = reference_time == 0
4✔
736
                                      ? std::chrono::system_clock::now()
4✔
737
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
738

739
      std::vector<Botan::X509_Certificate> end_certs;
4✔
740
      end_certs.push_back(safe_get(cert));
4✔
741
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
742
         end_certs.push_back(safe_get(intermediates[i]));
5✔
743
      }
744

745
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
746
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
747
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
748

749
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
750
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
751
         trusted_roots.push_back(trusted_from_path.get());
×
752
      }
753

754
      if(trusted_len > 0) {
4✔
755
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
756
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
757
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
758
         }
759
         trusted_roots.push_back(trusted_extra.get());
4✔
760
      }
761

762
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
763

764
      auto validation_result =
4✔
765
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
766

767
      if(result_code != nullptr) {
4✔
768
         *result_code = static_cast<int>(validation_result.result());
4✔
769
      }
770

771
      if(validation_result.successful_validation()) {
4✔
772
         return 0;
773
      } else {
774
         return 1;
3✔
775
      }
776
   });
4✔
777
#else
778
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
779
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
780
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
781
#endif
782
}
783

784
const char* botan_x509_cert_validation_status(int code) {
11✔
785
   if(code < 0) {
11✔
786
      return nullptr;
787
   }
788

789
#if defined(BOTAN_HAS_X509_CERTIFICATES)
790
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
791
   return Botan::to_string(sc);
11✔
792
#else
793
   return nullptr;
794
#endif
795
}
796

797
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
798
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
799
      return BOTAN_FFI_ERROR_NULL_POINTER;
800
   }
801

802
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
803

804
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
805
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
806
      return ffi_new_object(crl_obj, std::move(c));
14✔
807
   });
14✔
808

809
#else
810
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
811
#endif
812
}
813

814
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
815
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
816
      return BOTAN_FFI_ERROR_NULL_POINTER;
817
   }
818

819
#if defined(BOTAN_HAS_X509_CERTIFICATES)
820
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
821
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
822
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
823
      return ffi_new_object(crl_obj, std::move(c));
1✔
824
   });
3✔
825
#else
826
   BOTAN_UNUSED(crl_bits_len);
827
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
828
#endif
829
}
830

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

846
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
5✔
847
#if defined(BOTAN_HAS_X509_CERTIFICATES)
848
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
10✔
849
      const auto& time = c.next_update();
850
      if(!time.time_is_set()) {
851
         return BOTAN_FFI_ERROR_NO_VALUE;
852
      }
853

854
      if(Botan::any_null_pointers(time_since_epoch)) {
855
         return BOTAN_FFI_ERROR_NULL_POINTER;
856
      }
857

858
      *time_since_epoch = c.next_update().time_since_epoch();
859
      return BOTAN_FFI_SUCCESS;
860
   });
861
#else
862
   BOTAN_UNUSED(crl, time_since_epoch);
863
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
864
#endif
865
}
866

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

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

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

931
      std::vector<Botan::CRL_Entry> entries;
3✔
932
      entries.reserve(new_entries_len);
3✔
933
      for(size_t i = 0; i < new_entries_len; i++) {
5✔
934
         entries.push_back(safe_get(new_entries[i]));
2✔
935
      }
936

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

948
int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key, int* result) {
3✔
949
   if(Botan::any_null_pointers(result)) {
3✔
950
      return BOTAN_FFI_ERROR_NULL_POINTER;
951
   }
952
#if defined(BOTAN_HAS_X509_CERTIFICATES)
953
   return ffi_guard_thunk(__func__, [=]() -> int {
3✔
954
      const bool ok = safe_get(crl).check_signature(safe_get(key));
3✔
955
      if(ok) {
3✔
956
         *result = 1;
3✔
957
      } else {
958
         *result = 0;
×
959
      }
960
      return BOTAN_FFI_SUCCESS;
3✔
961
   });
3✔
962
#else
963
   BOTAN_UNUSED(crl, key);
964
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
965
#endif
966
}
967

968
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
13✔
969
#if defined(BOTAN_HAS_X509_CERTIFICATES)
970
   return BOTAN_FFI_CHECKED_DELETE(crl);
13✔
971
#else
972
   BOTAN_UNUSED(crl);
973
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
974
#endif
975
}
976

977
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
978
#if defined(BOTAN_HAS_X509_CERTIFICATES)
979
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
980
#else
981
   BOTAN_UNUSED(cert);
982
   BOTAN_UNUSED(crl);
983
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
984
#endif
985
}
986

987
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
8✔
988
#if defined(BOTAN_HAS_X509_CERTIFICATES)
989
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
16✔
990
      const auto& entries = c.get_revoked();
991
      if(index >= entries.size()) {
992
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
993
      }
994

995
      if(Botan::any_null_pointers(entry)) {
996
         return BOTAN_FFI_ERROR_NULL_POINTER;
997
      }
998

999
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
1000
   });
1001
#else
1002
   BOTAN_UNUSED(crl, index, entry);
1003
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1004
#endif
1005
}
1006

1007
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
4✔
1008
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1009
   if(Botan::any_null_pointers(count)) {
4✔
1010
      return BOTAN_FFI_ERROR_NULL_POINTER;
1011
   }
1012

1013
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
8✔
1014
#else
1015
   BOTAN_UNUSED(crl, count);
1016
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1017
#endif
1018
}
1019

1020
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
6✔
1021
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1022
   return BOTAN_FFI_CHECKED_DELETE(entry);
6✔
1023
#else
1024
   BOTAN_UNUSED(entry);
1025
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1026
#endif
1027
}
1028

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

1036
      *reason_code = static_cast<int>(e.reason_code());
1037
      return BOTAN_FFI_SUCCESS;
1038
   });
1039
#else
1040
   BOTAN_UNUSED(entry, reason_code);
1041
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1042
#endif
1043
}
1044

1045
int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) {
3✔
1046
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1047
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1048
      if(Botan::any_null_pointers(serial_number)) {
1049
         return BOTAN_FFI_ERROR_NULL_POINTER;
1050
      }
1051

1052
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
1053
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
1054
   });
1055
#else
1056
   BOTAN_UNUSED(entry, serial_number);
1057
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1058
#endif
1059
}
1060

1061
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
1062
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1063
   return BOTAN_FFI_VISIT(
2✔
1064
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
1065
#else
1066
   BOTAN_UNUSED(entry, ctx, view);
1067
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1068
#endif
1069
}
1070

1071
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
3✔
1072
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1073
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
6✔
1074
      if(Botan::any_null_pointers(time_since_epoch)) {
1075
         return BOTAN_FFI_ERROR_NULL_POINTER;
1076
      }
1077

1078
      *time_since_epoch = e.expire_time().time_since_epoch();
1079
      return BOTAN_FFI_SUCCESS;
1080
   });
1081
#else
1082
   BOTAN_UNUSED(entry, time_since_epoch);
1083
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1084
#endif
1085
}
1086

1087
int botan_x509_cert_verify_with_crl(int* result_code,
20✔
1088
                                    botan_x509_cert_t cert,
1089
                                    const botan_x509_cert_t* intermediates,
1090
                                    size_t intermediates_len,
1091
                                    const botan_x509_cert_t* trusted,
1092
                                    size_t trusted_len,
1093
                                    const botan_x509_crl_t* crls,
1094
                                    size_t crls_len,
1095
                                    const char* trusted_path,
1096
                                    size_t required_strength,
1097
                                    const char* hostname_cstr,
1098
                                    uint64_t reference_time) {
1099
   if(required_strength == 0) {
20✔
1100
      required_strength = 110;
10✔
1101
   }
1102

1103
#if defined(BOTAN_HAS_X509_CERTIFICATES)
1104
   return ffi_guard_thunk(__func__, [=]() -> int {
20✔
1105
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
22✔
1106
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
20✔
1107
      const auto validation_time = reference_time == 0
20✔
1108
                                      ? std::chrono::system_clock::now()
20✔
1109
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
1110

1111
      std::vector<Botan::X509_Certificate> end_certs;
20✔
1112
      end_certs.push_back(safe_get(cert));
20✔
1113
      for(size_t i = 0; i != intermediates_len; ++i) {
38✔
1114
         end_certs.push_back(safe_get(intermediates[i]));
18✔
1115
      }
1116

1117
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
20✔
1118
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
20✔
1119
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
20✔
1120
      std::vector<Botan::Certificate_Store*> trusted_roots;
20✔
1121

1122
      if(trusted_path != nullptr && *trusted_path != 0) {
20✔
1123
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
1124
         trusted_roots.push_back(trusted_from_path.get());
2✔
1125
      }
1126

1127
      if(trusted_len > 0) {
20✔
1128
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
34✔
1129
         for(size_t i = 0; i != trusted_len; ++i) {
34✔
1130
            trusted_extra->add_certificate(safe_get(trusted[i]));
17✔
1131
         }
1132
         trusted_roots.push_back(trusted_extra.get());
17✔
1133
      }
1134

1135
      if(crls_len > 0) {
20✔
1136
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
26✔
1137
         for(size_t i = 0; i != crls_len; ++i) {
29✔
1138
            trusted_crls->add_crl(safe_get(crls[i]));
16✔
1139
         }
1140
         trusted_roots.push_back(trusted_crls.get());
13✔
1141
      }
1142

1143
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
40✔
1144

1145
      auto validation_result =
20✔
1146
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
20✔
1147

1148
      if(result_code != nullptr) {
20✔
1149
         *result_code = static_cast<int>(validation_result.result());
20✔
1150
      }
1151

1152
      if(validation_result.successful_validation()) {
20✔
1153
         return 0;
1154
      } else {
1155
         return 1;
10✔
1156
      }
1157
   });
22✔
1158
#else
1159
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1160
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1161
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1162
#endif
1163
}
1164
}
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