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

randombit / botan / 20948790087

13 Jan 2026 07:45AM UTC coverage: 90.454% (+0.002%) from 90.452%
20948790087

push

github

web-flow
Merge pull request #5232 from Rohde-Schwarz/feature/ffi_count_functions

FFI: add `*_count()` functions for some FFI enumerators

102126 of 112904 relevant lines covered (90.45%)

12861917.72 hits per line

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

94.92
/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/x509cert.h>
17
   #include <botan/x509path.h>
18
   #include <botan/internal/ffi_oid.h>
19
#endif
20

21
extern "C" {
22

23
using namespace Botan_FFI;
24

25
#if defined(BOTAN_HAS_X509_CERTIFICATES)
26

27
BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
30✔
28
BOTAN_FFI_DECLARE_STRUCT(botan_x509_general_name_struct, Botan::GeneralName, 0x563654FD);
198✔
29

30
#endif
31

32
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
29✔
33
   if(cert_obj == nullptr || cert_path == nullptr) {
29✔
34
      return BOTAN_FFI_ERROR_NULL_POINTER;
35
   }
36

37
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
38

39
   return ffi_guard_thunk(__func__, [=]() -> int {
29✔
40
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
29✔
41
      return ffi_new_object(cert_obj, std::move(c));
29✔
42
   });
58✔
43

44
#else
45
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
46
#endif
47
}
48

49
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
50
   if(cert_obj == nullptr) {
1✔
51
      return BOTAN_FFI_ERROR_NULL_POINTER;
52
   }
53

54
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
55

56
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
57
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
58
      return ffi_new_object(cert_obj, std::move(c));
1✔
59
   });
2✔
60

61
#else
62
   BOTAN_UNUSED(cert);
63
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
64
#endif
65
}
66

67
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
68
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
69
      return BOTAN_FFI_ERROR_NULL_POINTER;
70
   }
71

72
#if defined(BOTAN_HAS_X509_CERTIFICATES)
73
   return ffi_guard_thunk(__func__, [=]() -> int {
×
74
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
75
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
76
      return ffi_new_object(cert_obj, std::move(c));
×
77
   });
×
78
#else
79
   BOTAN_UNUSED(cert_bits_len);
80
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
81
#endif
82
}
83

84
int botan_x509_cert_is_ca(botan_x509_cert_t cert) {
2✔
85
#if defined(BOTAN_HAS_X509_CERTIFICATES)
86
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.is_CA_cert() ? BOTAN_FFI_SUCCESS : 1; });
4✔
87
#else
88
   BOTAN_UNUSED(cert);
89
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
90
#endif
91
}
92

93
int botan_x509_cert_get_path_length_constraint(botan_x509_cert_t cert, size_t* path_limit) {
2✔
94
#if defined(BOTAN_HAS_X509_CERTIFICATES)
95
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
96
      if(Botan::any_null_pointers(path_limit)) {
97
         return BOTAN_FFI_ERROR_NULL_POINTER;
98
      }
99

100
      if(const auto path_len = c.path_length_constraint()) {
101
         *path_limit = path_len.value();
102
         return BOTAN_FFI_SUCCESS;
103
      } else {
104
         return BOTAN_FFI_ERROR_NO_VALUE;
105
      }
106
   });
107
#else
108
   BOTAN_UNUSED(cert, path_limit);
109
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
110
#endif
111
}
112

113
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
114
   if(key == nullptr) {
2✔
115
      return BOTAN_FFI_ERROR_NULL_POINTER;
116
   }
117

118
   *key = nullptr;
2✔
119

120
#if defined(BOTAN_HAS_X509_CERTIFICATES)
121
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
122
      auto public_key = safe_get(cert).subject_public_key();
2✔
123
      return ffi_new_object(key, std::move(public_key));
2✔
124
   });
4✔
125
#else
126
   BOTAN_UNUSED(cert);
127
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
128
#endif
129
}
130

131
int botan_x509_cert_get_issuer_dn(
8✔
132
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
133
#if defined(BOTAN_HAS_X509_CERTIFICATES)
134
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
135
      auto issuer_info = c.issuer_info(key);
136
      if(index < issuer_info.size()) {
137
         // TODO(Botan4) change the type of out and remove this cast
138
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
139
      } else {
140
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
141
      }
142
   });
143
#else
144
   BOTAN_UNUSED(cert, key, index, out, out_len);
145
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
146
#endif
147
}
148

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

167
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
168
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
169
}
170

171
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
172
#if defined(BOTAN_HAS_X509_CERTIFICATES)
173
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
174
#else
175
   BOTAN_UNUSED(cert, ctx, view);
176
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
177
#endif
178
}
179

180
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
181
#if defined(BOTAN_HAS_X509_CERTIFICATES)
182
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
183
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
184
      if(c.allowed_usage(k)) {
185
         return BOTAN_FFI_SUCCESS;
186
      }
187
      return 1;
188
   });
189
#else
190
   BOTAN_UNUSED(cert, key_usage);
191
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
192
#endif
193
}
194

195
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
196
#if defined(BOTAN_HAS_X509_CERTIFICATES)
197
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
198
      if(Botan::any_null_pointers(oid)) {
199
         return BOTAN_FFI_ERROR_NULL_POINTER;
200
      }
201

202
      return c.has_ex_constraint(oid) ? BOTAN_FFI_SUCCESS : 1;
203
   });
204
#else
205
   BOTAN_UNUSED(cert, oid);
206
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
207
#endif
208
}
209

210
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
211
#if defined(BOTAN_HAS_X509_CERTIFICATES)
212
   return BOTAN_FFI_VISIT(
8✔
213
      cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? BOTAN_FFI_SUCCESS : 1; });
214
#else
215
   BOTAN_UNUSED(cert, oid);
216
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
217
#endif
218
}
219

220
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
30✔
221
#if defined(BOTAN_HAS_X509_CERTIFICATES)
222
   return BOTAN_FFI_CHECKED_DELETE(cert);
30✔
223
#else
224
   BOTAN_UNUSED(cert);
225
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
226
#endif
227
}
228

229
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
230
#if defined(BOTAN_HAS_X509_CERTIFICATES)
231
   return BOTAN_FFI_VISIT(cert,
6✔
232
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
233
#else
234
   BOTAN_UNUSED(cert, out, out_len);
235
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
236
#endif
237
}
238

239
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
240
#if defined(BOTAN_HAS_X509_CERTIFICATES)
241
   return BOTAN_FFI_VISIT(cert,
4✔
242
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
243
#else
244
   BOTAN_UNUSED(cert, out, out_len);
245
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
246
#endif
247
}
248

249
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
250
#if defined(BOTAN_HAS_X509_CERTIFICATES)
251
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
252
#else
253
   BOTAN_UNUSED(cert, time_since_epoch);
254
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
255
#endif
256
}
257

258
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
259
#if defined(BOTAN_HAS_X509_CERTIFICATES)
260
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
261
#else
262
   BOTAN_UNUSED(cert, time_since_epoch);
263
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
264
#endif
265
}
266

267
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
5✔
268
#if defined(BOTAN_HAS_X509_CERTIFICATES)
269
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
10✔
270
#else
271
   BOTAN_UNUSED(cert, out, out_len);
272
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
273
#endif
274
}
275

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

280
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
281
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
282
   });
283
#else
284
   BOTAN_UNUSED(cert, hash, out, out_len);
285
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
286
#endif
287
}
288

289
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
290
#if defined(BOTAN_HAS_X509_CERTIFICATES)
291
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
292
#else
293
   BOTAN_UNUSED(cert, out, out_len);
294
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
295
#endif
296
}
297

298
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
299
#if defined(BOTAN_HAS_X509_CERTIFICATES)
300
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
301
#else
302
   BOTAN_UNUSED(cert, out, out_len);
303
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
304
#endif
305
}
306

307
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
308
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
309
}
310

311
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
312
#if defined(BOTAN_HAS_X509_CERTIFICATES)
313
   return BOTAN_FFI_VISIT(cert,
6✔
314
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
315
#else
316
   BOTAN_UNUSED(cert, ctx, view);
317
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
318
#endif
319
}
320
}
321

322
namespace {
323

324
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
301✔
325
   using Type = Botan::GeneralName::NameType;
301✔
326
   switch(gn_type) {
301✔
327
      case Type::Unknown:
1✔
328
         return std::nullopt;
1✔
329
      case Type::RFC822:
83✔
330
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
331
      case Type::DNS:
73✔
332
         return BOTAN_X509_DNS_NAME;
73✔
333
      case Type::URI:
28✔
334
         return BOTAN_X509_URI;
28✔
335
      case Type::DN:
95✔
336
         return BOTAN_X509_DIRECTORY_NAME;
95✔
337
      case Type::IPv4:
21✔
338
         return BOTAN_X509_IP_ADDRESS;
21✔
339
      case Type::Other:
×
340
         return BOTAN_X509_OTHER_NAME;
×
341
   }
342

343
   BOTAN_ASSERT_UNREACHABLE();
×
344
}
345

346
}  // namespace
347

348
extern "C" {
349

350
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
351
#if defined(BOTAN_HAS_X509_CERTIFICATES)
352
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
353
      if(Botan::any_null_pointers(type)) {
354
         return BOTAN_FFI_ERROR_NULL_POINTER;
355
      }
356

357
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
358
      if(!mapped_type.has_value()) {
359
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
360
      }
361

362
      *type = mapped_type.value();
363
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
364
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
365
      }
366

367
      return BOTAN_FFI_SUCCESS;
368
   });
369
#else
370
   BOTAN_UNUSED(name, type);
371
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
372
#endif
373
}
374

375
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
376
                                              botan_view_ctx ctx,
377
                                              botan_view_str_fn view) {
378
#if defined(BOTAN_HAS_X509_CERTIFICATES)
379
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
380
      const auto type = to_botan_x509_general_name_types(n.type_code());
381
      if(!type) {
382
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
383
      }
384

385
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
386
         type != BOTAN_X509_IP_ADDRESS) {
387
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
388
      }
389

390
      return invoke_view_callback(view, ctx, n.name());
391
   });
392
#else
393
   BOTAN_UNUSED(name, ctx, view);
394
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
395
#endif
396
}
397

398
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
399
                                              botan_view_ctx ctx,
400
                                              botan_view_bin_fn view) {
401
#if defined(BOTAN_HAS_X509_CERTIFICATES)
402
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
403
      const auto type = to_botan_x509_general_name_types(n.type_code());
404
      if(!type) {
405
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
406
      }
407

408
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
409
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
410
      }
411

412
      return invoke_view_callback(view, ctx, n.binary_name());
413
   });
414
#else
415
   BOTAN_UNUSED(name, ctx, view);
416
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
417
#endif
418
}
419

420
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
421
#if defined(BOTAN_HAS_X509_CERTIFICATES)
422
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
423
#else
424
   BOTAN_UNUSED(name);
425
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
426
#endif
427
}
428

429
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
430
                                               size_t index,
431
                                               botan_x509_general_name_t* constraint) {
432
#if defined(BOTAN_HAS_X509_CERTIFICATES)
433
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
434
      if(Botan::any_null_pointers(constraint)) {
435
         return BOTAN_FFI_ERROR_NULL_POINTER;
436
      }
437

438
      const auto& constraints = c.name_constraints().permitted();
439
      if(index >= constraints.size()) {
440
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
441
      }
442

443
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
444
   });
445
#else
446
   BOTAN_UNUSED(cert, index, constraint);
447
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
448
#endif
449
}
450

451
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
452
#if defined(BOTAN_HAS_X509_CERTIFICATES)
453
   if(Botan::any_null_pointers(count)) {
1✔
454
      return BOTAN_FFI_ERROR_NULL_POINTER;
455
   }
456

457
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
458
#else
459
   BOTAN_UNUSED(cert, count);
460
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
461
#endif
462
}
463

464
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
465
                                              size_t index,
466
                                              botan_x509_general_name_t* constraint) {
467
#if defined(BOTAN_HAS_X509_CERTIFICATES)
468
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
469
      if(Botan::any_null_pointers(constraint)) {
470
         return BOTAN_FFI_ERROR_NULL_POINTER;
471
      }
472

473
      const auto& constraints = c.name_constraints().excluded();
474
      if(index >= constraints.size()) {
475
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
476
      }
477

478
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
479
   });
480
#else
481
   BOTAN_UNUSED(cert, index, constraint);
482
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
483
#endif
484
}
485

486
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
487
#if defined(BOTAN_HAS_X509_CERTIFICATES)
488
   if(Botan::any_null_pointers(count)) {
1✔
489
      return BOTAN_FFI_ERROR_NULL_POINTER;
490
   }
491

492
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
493
#else
494
   BOTAN_UNUSED(cert, count);
495
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
496
#endif
497
}
498
}
499

500
namespace {
501

502
/**
503
 * As specified in RFC 5280 Section 4.2.1.6. alternative names essentially are a
504
 * collection of GeneralNames. This allows mapping a single entry of @p altnames
505
 * to a GeneralName by its @p index. If the index is out of range, std::nullopt
506
 * is returned.
507
 *
508
 * NOTE: if the set of alternative name types handled here is extended,
509
 *       count_general_names_in() must be updated accordingly!
510
 */
511
std::optional<Botan::GeneralName> extract_general_name_at(const Botan::AlternativeName& altnames, size_t index) {
132✔
512
   if(index < altnames.email().size()) {
132✔
513
      auto itr = altnames.email().begin();
12✔
514
      std::advance(itr, index);
12✔
515
      return Botan::GeneralName::email(*itr);
36✔
516
   }
517
   index -= altnames.email().size();
120✔
518

519
   if(index < altnames.dns().size()) {
120✔
520
      auto itr = altnames.dns().begin();
36✔
521
      std::advance(itr, index);
36✔
522
      return Botan::GeneralName::dns(*itr);
108✔
523
   }
524
   index -= altnames.dns().size();
84✔
525

526
   if(index < altnames.directory_names().size()) {
84✔
527
      auto itr = altnames.directory_names().begin();
36✔
528
      std::advance(itr, index);
36✔
529
      return Botan::GeneralName::directory_name(*itr);
108✔
530
   }
531
   index -= altnames.directory_names().size();
48✔
532

533
   if(index < altnames.uris().size()) {
48✔
534
      auto itr = altnames.uris().begin();
24✔
535
      std::advance(itr, index);
24✔
536
      return Botan::GeneralName::uri(*itr);
72✔
537
   }
538
   index -= altnames.uris().size();
24✔
539

540
   if(index < altnames.ipv4_address().size()) {
24✔
541
      auto itr = altnames.ipv4_address().begin();
12✔
542
      std::advance(itr, index);
12✔
543
      return Botan::GeneralName::ipv4_address(*itr);
36✔
544
   }
545

546
   return std::nullopt;
12✔
547
}
548

549
/**
550
 * Counts the total number of GeneralNames contained in the given
551
 * AlternativeName @p alt_names.
552
 *
553
 * NOTE: if the set of alternative name types handled here is extended,
554
 *       extract_general_name_at() must be updated accordingly!
555
 */
556
size_t count_general_names_in(const Botan::AlternativeName& alt_names) {
12✔
557
   return alt_names.email().size() + alt_names.dns().size() + alt_names.directory_names().size() +
12✔
558
          alt_names.uris().size() + alt_names.ipv4_address().size();
12✔
559
}
560

561
}  // namespace
562

563
extern "C" {
564

565
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
566
                                              size_t index,
567
                                              botan_x509_general_name_t* alt_name) {
568
#if defined(BOTAN_HAS_X509_CERTIFICATES)
569
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
570
      if(Botan::any_null_pointers(alt_name)) {
571
         return BOTAN_FFI_ERROR_NULL_POINTER;
572
      }
573

574
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
575
         return BOTAN_FFI_ERROR_NO_VALUE;
576
      }
577

578
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
579
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
580
      }
581

582
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
583
   });
584
#else
585
   BOTAN_UNUSED(cert, index, alt_name);
586
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
587
#endif
588
}
589

590
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
591
#if defined(BOTAN_HAS_X509_CERTIFICATES)
592
   if(Botan::any_null_pointers(count)) {
6✔
593
      return BOTAN_FFI_ERROR_NULL_POINTER;
594
   }
595

596
   return BOTAN_FFI_VISIT(
12✔
597
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
598
#else
599
   BOTAN_UNUSED(cert, count);
600
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
601
#endif
602
}
603

604
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
605
                                             size_t index,
606
                                             botan_x509_general_name_t* alt_name) {
607
#if defined(BOTAN_HAS_X509_CERTIFICATES)
608
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
609
      if(Botan::any_null_pointers(alt_name)) {
610
         return BOTAN_FFI_ERROR_NULL_POINTER;
611
      }
612

613
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
614
         return BOTAN_FFI_ERROR_NO_VALUE;
615
      }
616

617
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
618
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
619
      }
620

621
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
622
   });
623
#else
624
   BOTAN_UNUSED(cert, index, alt_name);
625
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
626
#endif
627
}
628

629
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
630
#if defined(BOTAN_HAS_X509_CERTIFICATES)
631
   if(Botan::any_null_pointers(count)) {
6✔
632
      return BOTAN_FFI_ERROR_NULL_POINTER;
633
   }
634

635
   return BOTAN_FFI_VISIT(
12✔
636
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.issuer_alt_name()); });
637
#else
638
   BOTAN_UNUSED(cert, count);
639
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
640
#endif
641
}
642

643
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
644
   if(hostname == nullptr) {
6✔
645
      return BOTAN_FFI_ERROR_NULL_POINTER;
646
   }
647

648
#if defined(BOTAN_HAS_X509_CERTIFICATES)
649
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
650
#else
651
   BOTAN_UNUSED(cert);
652
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
653
#endif
654
}
655

656
int botan_x509_cert_verify(int* result_code,
4✔
657
                           botan_x509_cert_t cert,
658
                           const botan_x509_cert_t* intermediates,
659
                           size_t intermediates_len,
660
                           const botan_x509_cert_t* trusted,
661
                           size_t trusted_len,
662
                           const char* trusted_path,
663
                           size_t required_strength,
664
                           const char* hostname_cstr,
665
                           uint64_t reference_time) {
666
   if(required_strength == 0) {
4✔
667
      required_strength = 110;
3✔
668
   }
669

670
#if defined(BOTAN_HAS_X509_CERTIFICATES)
671
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
672
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
673
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
674
      const auto validation_time = reference_time == 0
4✔
675
                                      ? std::chrono::system_clock::now()
4✔
676
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
677

678
      std::vector<Botan::X509_Certificate> end_certs;
4✔
679
      end_certs.push_back(safe_get(cert));
4✔
680
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
681
         end_certs.push_back(safe_get(intermediates[i]));
5✔
682
      }
683

684
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
685
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
686
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
687

688
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
689
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
690
         trusted_roots.push_back(trusted_from_path.get());
×
691
      }
692

693
      if(trusted_len > 0) {
4✔
694
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
695
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
696
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
697
         }
698
         trusted_roots.push_back(trusted_extra.get());
4✔
699
      }
700

701
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
702

703
      auto validation_result =
4✔
704
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
705

706
      if(result_code != nullptr) {
4✔
707
         *result_code = static_cast<int>(validation_result.result());
4✔
708
      }
709

710
      if(validation_result.successful_validation()) {
4✔
711
         return 0;
712
      } else {
713
         return 1;
3✔
714
      }
715
   });
4✔
716
#else
717
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
718
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
719
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
720
#endif
721
}
722

723
const char* botan_x509_cert_validation_status(int code) {
11✔
724
   if(code < 0) {
11✔
725
      return nullptr;
726
   }
727

728
#if defined(BOTAN_HAS_X509_CERTIFICATES)
729
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
730
   return Botan::to_string(sc);
11✔
731
#else
732
   return nullptr;
733
#endif
734
}
735

736
#if defined(BOTAN_HAS_X509_CERTIFICATES)
737

738
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
8✔
739
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_entry_struct, Botan::CRL_Entry, 0x4EAA5346);
1✔
740

741
#endif
742

743
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
744
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
745
      return BOTAN_FFI_ERROR_NULL_POINTER;
746
   }
747

748
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
749

750
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
751
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
752
      return ffi_new_object(crl_obj, std::move(c));
14✔
753
   });
14✔
754

755
#else
756
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
757
#endif
758
}
759

760
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
761
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
762
      return BOTAN_FFI_ERROR_NULL_POINTER;
763
   }
764

765
#if defined(BOTAN_HAS_X509_CERTIFICATES)
766
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
767
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
768
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
769
      return ffi_new_object(crl_obj, std::move(c));
1✔
770
   });
3✔
771
#else
772
   BOTAN_UNUSED(crl_bits_len);
773
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
774
#endif
775
}
776

777
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
778
#if defined(BOTAN_HAS_X509_CERTIFICATES)
779
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
780
      if(Botan::any_null_pointers(time_since_epoch)) {
781
         return BOTAN_FFI_ERROR_NULL_POINTER;
782
      }
783
      *time_since_epoch = c.this_update().time_since_epoch();
784
      return BOTAN_FFI_SUCCESS;
785
   });
786
#else
787
   BOTAN_UNUSED(crl, time_since_epoch);
788
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
789
#endif
790
}
791

792
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
4✔
793
#if defined(BOTAN_HAS_X509_CERTIFICATES)
794
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
8✔
795
      const auto& time = c.next_update();
796
      if(!time.time_is_set()) {
797
         return BOTAN_FFI_ERROR_NO_VALUE;
798
      }
799

800
      if(Botan::any_null_pointers(time_since_epoch)) {
801
         return BOTAN_FFI_ERROR_NULL_POINTER;
802
      }
803

804
      *time_since_epoch = c.next_update().time_since_epoch();
805
      return BOTAN_FFI_SUCCESS;
806
   });
807
#else
808
   BOTAN_UNUSED(crl, time_since_epoch);
809
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
810
#endif
811
}
812

813
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
8✔
814
#if defined(BOTAN_HAS_X509_CERTIFICATES)
815
   return BOTAN_FFI_CHECKED_DELETE(crl);
8✔
816
#else
817
   BOTAN_UNUSED(crl);
818
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
819
#endif
820
}
821

822
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
823
#if defined(BOTAN_HAS_X509_CERTIFICATES)
824
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
825
#else
826
   BOTAN_UNUSED(cert);
827
   BOTAN_UNUSED(crl);
828
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
829
#endif
830
}
831

832
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
3✔
833
#if defined(BOTAN_HAS_X509_CERTIFICATES)
834
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
6✔
835
      const auto& entries = c.get_revoked();
836
      if(index >= entries.size()) {
837
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
838
      }
839

840
      if(Botan::any_null_pointers(entry)) {
841
         return BOTAN_FFI_ERROR_NULL_POINTER;
842
      }
843

844
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
845
   });
846
#else
847
   BOTAN_UNUSED(crl, index, entry);
848
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
849
#endif
850
}
851

852
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
2✔
853
#if defined(BOTAN_HAS_X509_CERTIFICATES)
854
   if(Botan::any_null_pointers(count)) {
2✔
855
      return BOTAN_FFI_ERROR_NULL_POINTER;
856
   }
857

858
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
4✔
859
#else
860
   BOTAN_UNUSED(crl, count);
861
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
862
#endif
863
}
864

865
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
1✔
866
#if defined(BOTAN_HAS_X509_CERTIFICATES)
867
   return BOTAN_FFI_CHECKED_DELETE(entry);
1✔
868
#else
869
   BOTAN_UNUSED(entry);
870
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
871
#endif
872
}
873

874
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
1✔
875
#if defined(BOTAN_HAS_X509_CERTIFICATES)
876
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
877
      if(Botan::any_null_pointers(reason_code)) {
878
         return BOTAN_FFI_ERROR_NULL_POINTER;
879
      }
880

881
      *reason_code = static_cast<int>(e.reason_code());
882
      return BOTAN_FFI_SUCCESS;
883
   });
884
#else
885
   BOTAN_UNUSED(entry, reason_code);
886
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
887
#endif
888
}
889

890
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
891
#if defined(BOTAN_HAS_X509_CERTIFICATES)
892
   return BOTAN_FFI_VISIT(
2✔
893
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
894
#else
895
   BOTAN_UNUSED(entry, ctx, view);
896
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
897
#endif
898
}
899

900
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
1✔
901
#if defined(BOTAN_HAS_X509_CERTIFICATES)
902
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
903
      if(Botan::any_null_pointers(time_since_epoch)) {
904
         return BOTAN_FFI_ERROR_NULL_POINTER;
905
      }
906

907
      *time_since_epoch = e.expire_time().time_since_epoch();
908
      return BOTAN_FFI_SUCCESS;
909
   });
910
#else
911
   BOTAN_UNUSED(entry, time_since_epoch);
912
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
913
#endif
914
}
915

916
int botan_x509_cert_verify_with_crl(int* result_code,
12✔
917
                                    botan_x509_cert_t cert,
918
                                    const botan_x509_cert_t* intermediates,
919
                                    size_t intermediates_len,
920
                                    const botan_x509_cert_t* trusted,
921
                                    size_t trusted_len,
922
                                    const botan_x509_crl_t* crls,
923
                                    size_t crls_len,
924
                                    const char* trusted_path,
925
                                    size_t required_strength,
926
                                    const char* hostname_cstr,
927
                                    uint64_t reference_time) {
928
   if(required_strength == 0) {
12✔
929
      required_strength = 110;
2✔
930
   }
931

932
#if defined(BOTAN_HAS_X509_CERTIFICATES)
933
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
934
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
14✔
935
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
12✔
936
      const auto validation_time = reference_time == 0
12✔
937
                                      ? std::chrono::system_clock::now()
12✔
938
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
939

940
      std::vector<Botan::X509_Certificate> end_certs;
12✔
941
      end_certs.push_back(safe_get(cert));
12✔
942
      for(size_t i = 0; i != intermediates_len; ++i) {
30✔
943
         end_certs.push_back(safe_get(intermediates[i]));
18✔
944
      }
945

946
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
12✔
947
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
12✔
948
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
12✔
949
      std::vector<Botan::Certificate_Store*> trusted_roots;
12✔
950

951
      if(trusted_path != nullptr && *trusted_path != 0) {
12✔
952
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
953
         trusted_roots.push_back(trusted_from_path.get());
2✔
954
      }
955

956
      if(trusted_len > 0) {
12✔
957
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
18✔
958
         for(size_t i = 0; i != trusted_len; ++i) {
18✔
959
            trusted_extra->add_certificate(safe_get(trusted[i]));
9✔
960
         }
961
         trusted_roots.push_back(trusted_extra.get());
9✔
962
      }
963

964
      if(crls_len > 0) {
12✔
965
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
966
         for(size_t i = 0; i != crls_len; ++i) {
13✔
967
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
968
         }
969
         trusted_roots.push_back(trusted_crls.get());
5✔
970
      }
971

972
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
24✔
973

974
      auto validation_result =
12✔
975
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
12✔
976

977
      if(result_code != nullptr) {
12✔
978
         *result_code = static_cast<int>(validation_result.result());
12✔
979
      }
980

981
      if(validation_result.successful_validation()) {
12✔
982
         return 0;
983
      } else {
984
         return 1;
8✔
985
      }
986
   });
14✔
987
#else
988
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
989
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
990
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
991
#endif
992
}
993
}
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