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

randombit / botan / 20824387176

08 Jan 2026 04:42PM UTC coverage: 90.443% (+0.02%) from 90.423%
20824387176

Pull #5217

github

web-flow
Merge 4510d2bda into b1ff92a4e
Pull Request #5217: FFI: Query Certificate Subject/Issuer Alternative Names and Name Constraints

101933 of 112704 relevant lines covered (90.44%)

12903206.61 hits per line

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

93.95
/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
#endif
19

20
extern "C" {
21

22
using namespace Botan_FFI;
23

24
#if defined(BOTAN_HAS_X509_CERTIFICATES)
25

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

29
#endif
30

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

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

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

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

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

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

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

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

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

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

83
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
84
   if(key == nullptr) {
2✔
85
      return BOTAN_FFI_ERROR_NULL_POINTER;
86
   }
87

88
   *key = nullptr;
2✔
89

90
#if defined(BOTAN_HAS_X509_CERTIFICATES)
91
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
92
      auto public_key = safe_get(cert).subject_public_key();
2✔
93
      return ffi_new_object(key, std::move(public_key));
2✔
94
   });
4✔
95
#else
96
   BOTAN_UNUSED(cert);
97
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
98
#endif
99
}
100

101
int botan_x509_cert_get_issuer_dn(
8✔
102
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
103
#if defined(BOTAN_HAS_X509_CERTIFICATES)
104
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
105
      auto issuer_info = c.issuer_info(key);
106
      if(index < issuer_info.size()) {
107
         // TODO(Botan4) change the type of out and remove this cast
108
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
109
      } else {
110
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
111
      }
112
   });
113
#else
114
   BOTAN_UNUSED(cert, key, index, out, out_len);
115
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
116
#endif
117
}
118

119
int botan_x509_cert_get_subject_dn(
8✔
120
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
121
#if defined(BOTAN_HAS_X509_CERTIFICATES)
122
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
123
      auto subject_info = c.subject_info(key);
124
      if(index < subject_info.size()) {
125
         // TODO(Botan4) change the type of out and remove this cast
126
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
127
      } else {
128
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
129
      }
130
   });
131
#else
132
   BOTAN_UNUSED(cert, key, index, out, out_len);
133
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
134
#endif
135
}
136

137
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
138
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
139
}
140

141
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
142
#if defined(BOTAN_HAS_X509_CERTIFICATES)
143
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
144
#else
145
   BOTAN_UNUSED(cert, ctx, view);
146
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
147
#endif
148
}
149

150
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
151
#if defined(BOTAN_HAS_X509_CERTIFICATES)
152
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
153
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
154
      if(c.allowed_usage(k)) {
155
         return BOTAN_FFI_SUCCESS;
156
      }
157
      return 1;
158
   });
159
#else
160
   BOTAN_UNUSED(cert, key_usage);
161
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
162
#endif
163
}
164

165
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
27✔
166
#if defined(BOTAN_HAS_X509_CERTIFICATES)
167
   return BOTAN_FFI_CHECKED_DELETE(cert);
27✔
168
#else
169
   BOTAN_UNUSED(cert);
170
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
171
#endif
172
}
173

174
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
175
#if defined(BOTAN_HAS_X509_CERTIFICATES)
176
   return BOTAN_FFI_VISIT(cert,
6✔
177
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
178
#else
179
   BOTAN_UNUSED(cert, out, out_len);
180
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
181
#endif
182
}
183

184
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
185
#if defined(BOTAN_HAS_X509_CERTIFICATES)
186
   return BOTAN_FFI_VISIT(cert,
4✔
187
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
188
#else
189
   BOTAN_UNUSED(cert, out, out_len);
190
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
191
#endif
192
}
193

194
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
195
#if defined(BOTAN_HAS_X509_CERTIFICATES)
196
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
197
#else
198
   BOTAN_UNUSED(cert, time_since_epoch);
199
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
200
#endif
201
}
202

203
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
204
#if defined(BOTAN_HAS_X509_CERTIFICATES)
205
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
206
#else
207
   BOTAN_UNUSED(cert, time_since_epoch);
208
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
209
#endif
210
}
211

212
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
213
#if defined(BOTAN_HAS_X509_CERTIFICATES)
214
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
6✔
215
#else
216
   BOTAN_UNUSED(cert, out, out_len);
217
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
218
#endif
219
}
220

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

225
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
226
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
227
   });
228
#else
229
   BOTAN_UNUSED(cert, hash, out, out_len);
230
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
231
#endif
232
}
233

234
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
235
#if defined(BOTAN_HAS_X509_CERTIFICATES)
236
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
237
#else
238
   BOTAN_UNUSED(cert, out, out_len);
239
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
240
#endif
241
}
242

243
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
244
#if defined(BOTAN_HAS_X509_CERTIFICATES)
245
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
246
#else
247
   BOTAN_UNUSED(cert, out, out_len);
248
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
249
#endif
250
}
251

252
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
253
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
254
}
255

256
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
257
#if defined(BOTAN_HAS_X509_CERTIFICATES)
258
   return BOTAN_FFI_VISIT(cert,
6✔
259
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
260
#else
261
   BOTAN_UNUSED(cert, ctx, view);
262
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
263
#endif
264
}
265
}
266

267
namespace {
268

269
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
301✔
270
   using Type = Botan::GeneralName::NameType;
301✔
271
   switch(gn_type) {
301✔
272
      case Type::Unknown:
1✔
273
         return std::nullopt;
1✔
274
      case Type::RFC822:
83✔
275
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
276
      case Type::DNS:
73✔
277
         return BOTAN_X509_DNS_NAME;
73✔
278
      case Type::URI:
28✔
279
         return BOTAN_X509_URI;
28✔
280
      case Type::DN:
95✔
281
         return BOTAN_X509_DIRECTORY_NAME;
95✔
282
      case Type::IPv4:
21✔
283
         return BOTAN_X509_IP_ADDRESS;
21✔
284
      case Type::Other:
×
285
         return BOTAN_X509_OTHER_NAME;
×
286
   }
287

288
   BOTAN_ASSERT_UNREACHABLE();
×
289
}
290

291
}  // namespace
292

293
extern "C" {
294

295
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
296
#if defined(BOTAN_HAS_X509_CERTIFICATES)
297
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
298
      if(Botan::any_null_pointers(type)) {
299
         return BOTAN_FFI_ERROR_NULL_POINTER;
300
      }
301

302
      if(auto mapped_type = to_botan_x509_general_name_types(n.type_code())) {
303
         *type = mapped_type.value();
304
         if(*type != BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
305
            return BOTAN_FFI_SUCCESS;
306
         }
307
      }
308

309
      return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
310
   });
311
#else
312
   BOTAN_UNUSED(name, type);
313
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
314
#endif
315
}
316

317
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
318
                                              botan_view_ctx ctx,
319
                                              botan_view_str_fn view) {
320
#if defined(BOTAN_HAS_X509_CERTIFICATES)
321
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
322
      const auto type = to_botan_x509_general_name_types(n.type_code());
323
      if(!type) {
324
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
325
      }
326

327
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
328
         type != BOTAN_X509_IP_ADDRESS) {
329
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
330
      }
331

332
      return invoke_view_callback(view, ctx, n.name());
333
   });
334
#else
335
   BOTAN_UNUSED(name, ctx, view);
336
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
337
#endif
338
}
339

340
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
341
                                              botan_view_ctx ctx,
342
                                              botan_view_bin_fn view) {
343
#if defined(BOTAN_HAS_X509_CERTIFICATES)
344
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
345
      const auto type = to_botan_x509_general_name_types(n.type_code());
346
      if(!type) {
347
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
348
      }
349

350
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
351
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
352
      }
353

354
      return invoke_view_callback(view, ctx, n.binary_name());
355
   });
356
#else
357
   BOTAN_UNUSED(name, ctx, view);
358
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
359
#endif
360
}
361

362
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
363
#if defined(BOTAN_HAS_X509_CERTIFICATES)
364
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
365
#else
366
   BOTAN_UNUSED(name);
367
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
368
#endif
369
}
370

371
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
372
                                               size_t index,
373
                                               botan_x509_general_name_t* constraint) {
374
#if defined(BOTAN_HAS_X509_CERTIFICATES)
375
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
376
      if(Botan::any_null_pointers(constraint)) {
377
         return BOTAN_FFI_ERROR_NULL_POINTER;
378
      }
379

380
      const auto& constraints = c.name_constraints().permitted();
381
      if(index >= constraints.size()) {
382
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
383
      }
384

385
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
386
   });
387
#else
388
   BOTAN_UNUSED(cert, index, constraint);
389
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
390
#endif
391
}
392

393
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
394
                                              size_t index,
395
                                              botan_x509_general_name_t* constraint) {
396
#if defined(BOTAN_HAS_X509_CERTIFICATES)
397
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
398
      if(Botan::any_null_pointers(constraint)) {
399
         return BOTAN_FFI_ERROR_NULL_POINTER;
400
      }
401

402
      const auto& constraints = c.name_constraints().excluded();
403
      if(index >= constraints.size()) {
404
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
405
      }
406

407
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
408
   });
409
#else
410
   BOTAN_UNUSED(cert, index, constraint);
411
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
412
#endif
413
}
414
}
415

416
namespace {
417

418
/**
419
 * As specified in RFC 5280 Section 4.2.1.6. alternative names essentially are a
420
 * collection of GeneralNames. This allows mapping a single entry of @p altnames
421
 * to a GeneralName by its @p index. If the index is out of range, std::nullopt
422
 * is returned.
423
 */
424
std::optional<Botan::GeneralName> extract_general_name_at(const Botan::AlternativeName& altnames, size_t index) {
132✔
425
   if(index < altnames.email().size()) {
132✔
426
      auto itr = altnames.email().begin();
12✔
427
      std::advance(itr, index);
12✔
428
      return Botan::GeneralName::email(*itr);
36✔
429
   }
430
   index -= altnames.email().size();
120✔
431

432
   if(index < altnames.dns().size()) {
120✔
433
      auto itr = altnames.dns().begin();
36✔
434
      std::advance(itr, index);
36✔
435
      return Botan::GeneralName::dns(*itr);
108✔
436
   }
437
   index -= altnames.dns().size();
84✔
438

439
   if(index < altnames.directory_names().size()) {
84✔
440
      auto itr = altnames.directory_names().begin();
36✔
441
      std::advance(itr, index);
36✔
442
      return Botan::GeneralName::directory_name(*itr);
108✔
443
   }
444
   index -= altnames.directory_names().size();
48✔
445

446
   if(index < altnames.uris().size()) {
48✔
447
      auto itr = altnames.uris().begin();
24✔
448
      std::advance(itr, index);
24✔
449
      return Botan::GeneralName::uri(*itr);
72✔
450
   }
451
   index -= altnames.uris().size();
24✔
452

453
   if(index < altnames.ipv4_address().size()) {
24✔
454
      auto itr = altnames.ipv4_address().begin();
12✔
455
      std::advance(itr, index);
12✔
456
      return Botan::GeneralName::ipv4_address(*itr);
36✔
457
   }
458

459
   return std::nullopt;
12✔
460
}
461

462
}  // namespace
463

464
extern "C" {
465

466
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
467
                                              size_t index,
468
                                              botan_x509_general_name_t* alt_name) {
469
#if defined(BOTAN_HAS_X509_CERTIFICATES)
470
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
471
      if(Botan::any_null_pointers(alt_name)) {
472
         return BOTAN_FFI_ERROR_NULL_POINTER;
473
      }
474

475
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
476
         return BOTAN_FFI_ERROR_NO_VALUE;
477
      }
478

479
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
480
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
481
      }
482

483
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
484
   });
485
#else
486
   BOTAN_UNUSED(cert, index, alt_name);
487
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
488
#endif
489
}
490

491
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
492
                                             size_t index,
493
                                             botan_x509_general_name_t* alt_name) {
494
#if defined(BOTAN_HAS_X509_CERTIFICATES)
495
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
496
      if(Botan::any_null_pointers(alt_name)) {
497
         return BOTAN_FFI_ERROR_NULL_POINTER;
498
      }
499

500
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
501
         return BOTAN_FFI_ERROR_NO_VALUE;
502
      }
503

504
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
505
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
506
      }
507

508
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
509
   });
510
#else
511
   BOTAN_UNUSED(cert, index, alt_name);
512
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
513
#endif
514
}
515

516
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
517
   if(hostname == nullptr) {
6✔
518
      return BOTAN_FFI_ERROR_NULL_POINTER;
519
   }
520

521
#if defined(BOTAN_HAS_X509_CERTIFICATES)
522
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
523
#else
524
   BOTAN_UNUSED(cert);
525
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
526
#endif
527
}
528

529
int botan_x509_cert_verify(int* result_code,
4✔
530
                           botan_x509_cert_t cert,
531
                           const botan_x509_cert_t* intermediates,
532
                           size_t intermediates_len,
533
                           const botan_x509_cert_t* trusted,
534
                           size_t trusted_len,
535
                           const char* trusted_path,
536
                           size_t required_strength,
537
                           const char* hostname_cstr,
538
                           uint64_t reference_time) {
539
   if(required_strength == 0) {
4✔
540
      required_strength = 110;
3✔
541
   }
542

543
#if defined(BOTAN_HAS_X509_CERTIFICATES)
544
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
545
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
546
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
547
      const auto validation_time = reference_time == 0
4✔
548
                                      ? std::chrono::system_clock::now()
4✔
549
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
550

551
      std::vector<Botan::X509_Certificate> end_certs;
4✔
552
      end_certs.push_back(safe_get(cert));
4✔
553
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
554
         end_certs.push_back(safe_get(intermediates[i]));
5✔
555
      }
556

557
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
558
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
559
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
560

561
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
562
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
563
         trusted_roots.push_back(trusted_from_path.get());
×
564
      }
565

566
      if(trusted_len > 0) {
4✔
567
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
568
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
569
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
570
         }
571
         trusted_roots.push_back(trusted_extra.get());
4✔
572
      }
573

574
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
575

576
      auto validation_result =
4✔
577
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
578

579
      if(result_code != nullptr) {
4✔
580
         *result_code = static_cast<int>(validation_result.result());
4✔
581
      }
582

583
      if(validation_result.successful_validation()) {
4✔
584
         return 0;
585
      } else {
586
         return 1;
3✔
587
      }
588
   });
4✔
589
#else
590
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
591
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
592
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
593
#endif
594
}
595

596
const char* botan_x509_cert_validation_status(int code) {
11✔
597
   if(code < 0) {
11✔
598
      return nullptr;
599
   }
600

601
#if defined(BOTAN_HAS_X509_CERTIFICATES)
602
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
603
   return Botan::to_string(sc);
11✔
604
#else
605
   return nullptr;
606
#endif
607
}
608

609
#if defined(BOTAN_HAS_X509_CERTIFICATES)
610

611
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
7✔
612

613
#endif
614

615
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
6✔
616
   if(crl_obj == nullptr || crl_path == nullptr) {
6✔
617
      return BOTAN_FFI_ERROR_NULL_POINTER;
618
   }
619

620
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
621

622
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
623
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
6✔
624
      return ffi_new_object(crl_obj, std::move(c));
12✔
625
   });
12✔
626

627
#else
628
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
629
#endif
630
}
631

632
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
633
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
634
      return BOTAN_FFI_ERROR_NULL_POINTER;
635
   }
636

637
#if defined(BOTAN_HAS_X509_CERTIFICATES)
638
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
639
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
640
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
641
      return ffi_new_object(crl_obj, std::move(c));
1✔
642
   });
3✔
643
#else
644
   BOTAN_UNUSED(crl_bits_len);
645
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
646
#endif
647
}
648

649
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
7✔
650
#if defined(BOTAN_HAS_X509_CERTIFICATES)
651
   return BOTAN_FFI_CHECKED_DELETE(crl);
7✔
652
#else
653
   BOTAN_UNUSED(crl);
654
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
655
#endif
656
}
657

658
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
659
#if defined(BOTAN_HAS_X509_CERTIFICATES)
660
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
661
#else
662
   BOTAN_UNUSED(cert);
663
   BOTAN_UNUSED(crl);
664
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
665
#endif
666
}
667

668
int botan_x509_cert_verify_with_crl(int* result_code,
12✔
669
                                    botan_x509_cert_t cert,
670
                                    const botan_x509_cert_t* intermediates,
671
                                    size_t intermediates_len,
672
                                    const botan_x509_cert_t* trusted,
673
                                    size_t trusted_len,
674
                                    const botan_x509_crl_t* crls,
675
                                    size_t crls_len,
676
                                    const char* trusted_path,
677
                                    size_t required_strength,
678
                                    const char* hostname_cstr,
679
                                    uint64_t reference_time) {
680
   if(required_strength == 0) {
12✔
681
      required_strength = 110;
2✔
682
   }
683

684
#if defined(BOTAN_HAS_X509_CERTIFICATES)
685
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
686
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
14✔
687
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
12✔
688
      const auto validation_time = reference_time == 0
12✔
689
                                      ? std::chrono::system_clock::now()
12✔
690
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
691

692
      std::vector<Botan::X509_Certificate> end_certs;
12✔
693
      end_certs.push_back(safe_get(cert));
12✔
694
      for(size_t i = 0; i != intermediates_len; ++i) {
30✔
695
         end_certs.push_back(safe_get(intermediates[i]));
18✔
696
      }
697

698
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
12✔
699
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
12✔
700
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
12✔
701
      std::vector<Botan::Certificate_Store*> trusted_roots;
12✔
702

703
      if(trusted_path != nullptr && *trusted_path != 0) {
12✔
704
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
705
         trusted_roots.push_back(trusted_from_path.get());
2✔
706
      }
707

708
      if(trusted_len > 0) {
12✔
709
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
18✔
710
         for(size_t i = 0; i != trusted_len; ++i) {
18✔
711
            trusted_extra->add_certificate(safe_get(trusted[i]));
9✔
712
         }
713
         trusted_roots.push_back(trusted_extra.get());
9✔
714
      }
715

716
      if(crls_len > 0) {
12✔
717
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
718
         for(size_t i = 0; i != crls_len; ++i) {
13✔
719
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
720
         }
721
         trusted_roots.push_back(trusted_crls.get());
5✔
722
      }
723

724
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
24✔
725

726
      auto validation_result =
12✔
727
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
12✔
728

729
      if(result_code != nullptr) {
12✔
730
         *result_code = static_cast<int>(validation_result.result());
12✔
731
      }
732

733
      if(validation_result.successful_validation()) {
12✔
734
         return 0;
735
      } else {
736
         return 1;
8✔
737
      }
738
   });
14✔
739
#else
740
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
741
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
742
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
743
#endif
744
}
745
}
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