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

randombit / botan / 20953603593

13 Jan 2026 09:53AM UTC coverage: 90.458% (+0.004%) from 90.454%
20953603593

push

github

web-flow
Merge pull request #5230 from Rohde-Schwarz/feature/ffi_serial_as_mp_t

FFI: Return serial numbers as `botan_mp_t` for X.509 certificates and CRL entries

102143 of 112918 relevant lines covered (90.46%)

12761585.62 hits per line

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

95.0
/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_mp.h>
19
   #include <botan/internal/ffi_oid.h>
20
#endif
21

22
extern "C" {
23

24
using namespace Botan_FFI;
25

26
#if defined(BOTAN_HAS_X509_CERTIFICATES)
27

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

31
#endif
32

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

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

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

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

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

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

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

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

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

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

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

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

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

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

119
   *key = nullptr;
2✔
120

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

277
int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) {
1✔
278
#if defined(BOTAN_HAS_X509_CERTIFICATES)
279
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
2✔
280
      if(Botan::any_null_pointers(serial_number)) {
281
         return BOTAN_FFI_ERROR_NULL_POINTER;
282
      }
283

284
      auto serial_bn = Botan::BigInt::from_bytes(c.serial_number());
285
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
286
   });
287
#else
288
   BOTAN_UNUSED(cert, serial_number);
289
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
290
#endif
291
}
292

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

297
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
298
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
299
   });
300
#else
301
   BOTAN_UNUSED(cert, hash, out, out_len);
302
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
303
#endif
304
}
305

306
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
307
#if defined(BOTAN_HAS_X509_CERTIFICATES)
308
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
309
#else
310
   BOTAN_UNUSED(cert, out, out_len);
311
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
312
#endif
313
}
314

315
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
316
#if defined(BOTAN_HAS_X509_CERTIFICATES)
317
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
318
#else
319
   BOTAN_UNUSED(cert, out, out_len);
320
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
321
#endif
322
}
323

324
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
325
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
326
}
327

328
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
329
#if defined(BOTAN_HAS_X509_CERTIFICATES)
330
   return BOTAN_FFI_VISIT(cert,
6✔
331
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
332
#else
333
   BOTAN_UNUSED(cert, ctx, view);
334
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
335
#endif
336
}
337
}
338

339
namespace {
340

341
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
301✔
342
   using Type = Botan::GeneralName::NameType;
301✔
343
   switch(gn_type) {
301✔
344
      case Type::Unknown:
1✔
345
         return std::nullopt;
1✔
346
      case Type::RFC822:
83✔
347
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
348
      case Type::DNS:
73✔
349
         return BOTAN_X509_DNS_NAME;
73✔
350
      case Type::URI:
28✔
351
         return BOTAN_X509_URI;
28✔
352
      case Type::DN:
95✔
353
         return BOTAN_X509_DIRECTORY_NAME;
95✔
354
      case Type::IPv4:
21✔
355
         return BOTAN_X509_IP_ADDRESS;
21✔
356
      case Type::Other:
×
357
         return BOTAN_X509_OTHER_NAME;
×
358
   }
359

360
   BOTAN_ASSERT_UNREACHABLE();
×
361
}
362

363
}  // namespace
364

365
extern "C" {
366

367
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
368
#if defined(BOTAN_HAS_X509_CERTIFICATES)
369
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
370
      if(Botan::any_null_pointers(type)) {
371
         return BOTAN_FFI_ERROR_NULL_POINTER;
372
      }
373

374
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
375
      if(!mapped_type.has_value()) {
376
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
377
      }
378

379
      *type = mapped_type.value();
380
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
381
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
382
      }
383

384
      return BOTAN_FFI_SUCCESS;
385
   });
386
#else
387
   BOTAN_UNUSED(name, type);
388
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
389
#endif
390
}
391

392
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
393
                                              botan_view_ctx ctx,
394
                                              botan_view_str_fn view) {
395
#if defined(BOTAN_HAS_X509_CERTIFICATES)
396
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
397
      const auto type = to_botan_x509_general_name_types(n.type_code());
398
      if(!type) {
399
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
400
      }
401

402
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
403
         type != BOTAN_X509_IP_ADDRESS) {
404
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
405
      }
406

407
      return invoke_view_callback(view, ctx, n.name());
408
   });
409
#else
410
   BOTAN_UNUSED(name, ctx, view);
411
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
412
#endif
413
}
414

415
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
416
                                              botan_view_ctx ctx,
417
                                              botan_view_bin_fn view) {
418
#if defined(BOTAN_HAS_X509_CERTIFICATES)
419
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
420
      const auto type = to_botan_x509_general_name_types(n.type_code());
421
      if(!type) {
422
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
423
      }
424

425
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
426
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
427
      }
428

429
      return invoke_view_callback(view, ctx, n.binary_name());
430
   });
431
#else
432
   BOTAN_UNUSED(name, ctx, view);
433
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
434
#endif
435
}
436

437
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
438
#if defined(BOTAN_HAS_X509_CERTIFICATES)
439
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
440
#else
441
   BOTAN_UNUSED(name);
442
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
443
#endif
444
}
445

446
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
447
                                               size_t index,
448
                                               botan_x509_general_name_t* constraint) {
449
#if defined(BOTAN_HAS_X509_CERTIFICATES)
450
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
451
      if(Botan::any_null_pointers(constraint)) {
452
         return BOTAN_FFI_ERROR_NULL_POINTER;
453
      }
454

455
      const auto& constraints = c.name_constraints().permitted();
456
      if(index >= constraints.size()) {
457
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
458
      }
459

460
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
461
   });
462
#else
463
   BOTAN_UNUSED(cert, index, constraint);
464
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
465
#endif
466
}
467

468
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
469
#if defined(BOTAN_HAS_X509_CERTIFICATES)
470
   if(Botan::any_null_pointers(count)) {
1✔
471
      return BOTAN_FFI_ERROR_NULL_POINTER;
472
   }
473

474
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
475
#else
476
   BOTAN_UNUSED(cert, count);
477
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
478
#endif
479
}
480

481
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
482
                                              size_t index,
483
                                              botan_x509_general_name_t* constraint) {
484
#if defined(BOTAN_HAS_X509_CERTIFICATES)
485
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
486
      if(Botan::any_null_pointers(constraint)) {
487
         return BOTAN_FFI_ERROR_NULL_POINTER;
488
      }
489

490
      const auto& constraints = c.name_constraints().excluded();
491
      if(index >= constraints.size()) {
492
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
493
      }
494

495
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
496
   });
497
#else
498
   BOTAN_UNUSED(cert, index, constraint);
499
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
500
#endif
501
}
502

503
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
504
#if defined(BOTAN_HAS_X509_CERTIFICATES)
505
   if(Botan::any_null_pointers(count)) {
1✔
506
      return BOTAN_FFI_ERROR_NULL_POINTER;
507
   }
508

509
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
510
#else
511
   BOTAN_UNUSED(cert, count);
512
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
513
#endif
514
}
515
}
516

517
namespace {
518

519
/**
520
 * As specified in RFC 5280 Section 4.2.1.6. alternative names essentially are a
521
 * collection of GeneralNames. This allows mapping a single entry of @p altnames
522
 * to a GeneralName by its @p index. If the index is out of range, std::nullopt
523
 * is returned.
524
 *
525
 * NOTE: if the set of alternative name types handled here is extended,
526
 *       count_general_names_in() must be updated accordingly!
527
 */
528
std::optional<Botan::GeneralName> extract_general_name_at(const Botan::AlternativeName& altnames, size_t index) {
132✔
529
   if(index < altnames.email().size()) {
132✔
530
      auto itr = altnames.email().begin();
12✔
531
      std::advance(itr, index);
12✔
532
      return Botan::GeneralName::email(*itr);
36✔
533
   }
534
   index -= altnames.email().size();
120✔
535

536
   if(index < altnames.dns().size()) {
120✔
537
      auto itr = altnames.dns().begin();
36✔
538
      std::advance(itr, index);
36✔
539
      return Botan::GeneralName::dns(*itr);
108✔
540
   }
541
   index -= altnames.dns().size();
84✔
542

543
   if(index < altnames.directory_names().size()) {
84✔
544
      auto itr = altnames.directory_names().begin();
36✔
545
      std::advance(itr, index);
36✔
546
      return Botan::GeneralName::directory_name(*itr);
108✔
547
   }
548
   index -= altnames.directory_names().size();
48✔
549

550
   if(index < altnames.uris().size()) {
48✔
551
      auto itr = altnames.uris().begin();
24✔
552
      std::advance(itr, index);
24✔
553
      return Botan::GeneralName::uri(*itr);
72✔
554
   }
555
   index -= altnames.uris().size();
24✔
556

557
   if(index < altnames.ipv4_address().size()) {
24✔
558
      auto itr = altnames.ipv4_address().begin();
12✔
559
      std::advance(itr, index);
12✔
560
      return Botan::GeneralName::ipv4_address(*itr);
36✔
561
   }
562

563
   return std::nullopt;
12✔
564
}
565

566
/**
567
 * Counts the total number of GeneralNames contained in the given
568
 * AlternativeName @p alt_names.
569
 *
570
 * NOTE: if the set of alternative name types handled here is extended,
571
 *       extract_general_name_at() must be updated accordingly!
572
 */
573
size_t count_general_names_in(const Botan::AlternativeName& alt_names) {
12✔
574
   return alt_names.email().size() + alt_names.dns().size() + alt_names.directory_names().size() +
12✔
575
          alt_names.uris().size() + alt_names.ipv4_address().size();
12✔
576
}
577

578
}  // namespace
579

580
extern "C" {
581

582
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
583
                                              size_t index,
584
                                              botan_x509_general_name_t* alt_name) {
585
#if defined(BOTAN_HAS_X509_CERTIFICATES)
586
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
587
      if(Botan::any_null_pointers(alt_name)) {
588
         return BOTAN_FFI_ERROR_NULL_POINTER;
589
      }
590

591
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
592
         return BOTAN_FFI_ERROR_NO_VALUE;
593
      }
594

595
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
596
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
597
      }
598

599
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
600
   });
601
#else
602
   BOTAN_UNUSED(cert, index, alt_name);
603
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
604
#endif
605
}
606

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

613
   return BOTAN_FFI_VISIT(
12✔
614
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
615
#else
616
   BOTAN_UNUSED(cert, count);
617
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
618
#endif
619
}
620

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

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

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

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

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

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

660
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
661
   if(hostname == nullptr) {
6✔
662
      return BOTAN_FFI_ERROR_NULL_POINTER;
663
   }
664

665
#if defined(BOTAN_HAS_X509_CERTIFICATES)
666
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
667
#else
668
   BOTAN_UNUSED(cert);
669
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
670
#endif
671
}
672

673
int botan_x509_cert_verify(int* result_code,
4✔
674
                           botan_x509_cert_t cert,
675
                           const botan_x509_cert_t* intermediates,
676
                           size_t intermediates_len,
677
                           const botan_x509_cert_t* trusted,
678
                           size_t trusted_len,
679
                           const char* trusted_path,
680
                           size_t required_strength,
681
                           const char* hostname_cstr,
682
                           uint64_t reference_time) {
683
   if(required_strength == 0) {
4✔
684
      required_strength = 110;
3✔
685
   }
686

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

695
      std::vector<Botan::X509_Certificate> end_certs;
4✔
696
      end_certs.push_back(safe_get(cert));
4✔
697
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
698
         end_certs.push_back(safe_get(intermediates[i]));
5✔
699
      }
700

701
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
702
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
703
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
704

705
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
706
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
707
         trusted_roots.push_back(trusted_from_path.get());
×
708
      }
709

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

718
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
719

720
      auto validation_result =
4✔
721
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
722

723
      if(result_code != nullptr) {
4✔
724
         *result_code = static_cast<int>(validation_result.result());
4✔
725
      }
726

727
      if(validation_result.successful_validation()) {
4✔
728
         return 0;
729
      } else {
730
         return 1;
3✔
731
      }
732
   });
4✔
733
#else
734
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
735
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
736
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
737
#endif
738
}
739

740
const char* botan_x509_cert_validation_status(int code) {
11✔
741
   if(code < 0) {
11✔
742
      return nullptr;
743
   }
744

745
#if defined(BOTAN_HAS_X509_CERTIFICATES)
746
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
747
   return Botan::to_string(sc);
11✔
748
#else
749
   return nullptr;
750
#endif
751
}
752

753
#if defined(BOTAN_HAS_X509_CERTIFICATES)
754

755
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
8✔
756
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_entry_struct, Botan::CRL_Entry, 0x4EAA5346);
1✔
757

758
#endif
759

760
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
761
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
762
      return BOTAN_FFI_ERROR_NULL_POINTER;
763
   }
764

765
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
766

767
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
768
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
769
      return ffi_new_object(crl_obj, std::move(c));
14✔
770
   });
14✔
771

772
#else
773
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
774
#endif
775
}
776

777
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
778
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
779
      return BOTAN_FFI_ERROR_NULL_POINTER;
780
   }
781

782
#if defined(BOTAN_HAS_X509_CERTIFICATES)
783
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
784
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
785
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
786
      return ffi_new_object(crl_obj, std::move(c));
1✔
787
   });
3✔
788
#else
789
   BOTAN_UNUSED(crl_bits_len);
790
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
791
#endif
792
}
793

794
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
795
#if defined(BOTAN_HAS_X509_CERTIFICATES)
796
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
797
      if(Botan::any_null_pointers(time_since_epoch)) {
798
         return BOTAN_FFI_ERROR_NULL_POINTER;
799
      }
800
      *time_since_epoch = c.this_update().time_since_epoch();
801
      return BOTAN_FFI_SUCCESS;
802
   });
803
#else
804
   BOTAN_UNUSED(crl, time_since_epoch);
805
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
806
#endif
807
}
808

809
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
4✔
810
#if defined(BOTAN_HAS_X509_CERTIFICATES)
811
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
8✔
812
      const auto& time = c.next_update();
813
      if(!time.time_is_set()) {
814
         return BOTAN_FFI_ERROR_NO_VALUE;
815
      }
816

817
      if(Botan::any_null_pointers(time_since_epoch)) {
818
         return BOTAN_FFI_ERROR_NULL_POINTER;
819
      }
820

821
      *time_since_epoch = c.next_update().time_since_epoch();
822
      return BOTAN_FFI_SUCCESS;
823
   });
824
#else
825
   BOTAN_UNUSED(crl, time_since_epoch);
826
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
827
#endif
828
}
829

830
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
8✔
831
#if defined(BOTAN_HAS_X509_CERTIFICATES)
832
   return BOTAN_FFI_CHECKED_DELETE(crl);
8✔
833
#else
834
   BOTAN_UNUSED(crl);
835
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
836
#endif
837
}
838

839
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
840
#if defined(BOTAN_HAS_X509_CERTIFICATES)
841
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
842
#else
843
   BOTAN_UNUSED(cert);
844
   BOTAN_UNUSED(crl);
845
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
846
#endif
847
}
848

849
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
3✔
850
#if defined(BOTAN_HAS_X509_CERTIFICATES)
851
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
6✔
852
      const auto& entries = c.get_revoked();
853
      if(index >= entries.size()) {
854
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
855
      }
856

857
      if(Botan::any_null_pointers(entry)) {
858
         return BOTAN_FFI_ERROR_NULL_POINTER;
859
      }
860

861
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
862
   });
863
#else
864
   BOTAN_UNUSED(crl, index, entry);
865
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
866
#endif
867
}
868

869
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
2✔
870
#if defined(BOTAN_HAS_X509_CERTIFICATES)
871
   if(Botan::any_null_pointers(count)) {
2✔
872
      return BOTAN_FFI_ERROR_NULL_POINTER;
873
   }
874

875
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
4✔
876
#else
877
   BOTAN_UNUSED(crl, count);
878
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
879
#endif
880
}
881

882
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
1✔
883
#if defined(BOTAN_HAS_X509_CERTIFICATES)
884
   return BOTAN_FFI_CHECKED_DELETE(entry);
1✔
885
#else
886
   BOTAN_UNUSED(entry);
887
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
888
#endif
889
}
890

891
int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) {
1✔
892
#if defined(BOTAN_HAS_X509_CERTIFICATES)
893
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
894
      if(Botan::any_null_pointers(reason_code)) {
895
         return BOTAN_FFI_ERROR_NULL_POINTER;
896
      }
897

898
      *reason_code = static_cast<int>(e.reason_code());
899
      return BOTAN_FFI_SUCCESS;
900
   });
901
#else
902
   BOTAN_UNUSED(entry, reason_code);
903
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
904
#endif
905
}
906

907
int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) {
1✔
908
#if defined(BOTAN_HAS_X509_CERTIFICATES)
909
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
910
      if(Botan::any_null_pointers(serial_number)) {
911
         return BOTAN_FFI_ERROR_NULL_POINTER;
912
      }
913

914
      auto serial_bn = Botan::BigInt::from_bytes(e.serial_number());
915
      return ffi_new_object(serial_number, std::make_unique<Botan::BigInt>(std::move(serial_bn)));
916
   });
917
#else
918
   BOTAN_UNUSED(entry, serial_number);
919
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
920
#endif
921
}
922

923
int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) {
1✔
924
#if defined(BOTAN_HAS_X509_CERTIFICATES)
925
   return BOTAN_FFI_VISIT(
2✔
926
      entry, [=](const Botan::CRL_Entry& e) { return invoke_view_callback(view, ctx, e.serial_number()); });
927
#else
928
   BOTAN_UNUSED(entry, ctx, view);
929
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
930
#endif
931
}
932

933
int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch) {
1✔
934
#if defined(BOTAN_HAS_X509_CERTIFICATES)
935
   return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) {
2✔
936
      if(Botan::any_null_pointers(time_since_epoch)) {
937
         return BOTAN_FFI_ERROR_NULL_POINTER;
938
      }
939

940
      *time_since_epoch = e.expire_time().time_since_epoch();
941
      return BOTAN_FFI_SUCCESS;
942
   });
943
#else
944
   BOTAN_UNUSED(entry, time_since_epoch);
945
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
946
#endif
947
}
948

949
int botan_x509_cert_verify_with_crl(int* result_code,
12✔
950
                                    botan_x509_cert_t cert,
951
                                    const botan_x509_cert_t* intermediates,
952
                                    size_t intermediates_len,
953
                                    const botan_x509_cert_t* trusted,
954
                                    size_t trusted_len,
955
                                    const botan_x509_crl_t* crls,
956
                                    size_t crls_len,
957
                                    const char* trusted_path,
958
                                    size_t required_strength,
959
                                    const char* hostname_cstr,
960
                                    uint64_t reference_time) {
961
   if(required_strength == 0) {
12✔
962
      required_strength = 110;
2✔
963
   }
964

965
#if defined(BOTAN_HAS_X509_CERTIFICATES)
966
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
967
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
14✔
968
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
12✔
969
      const auto validation_time = reference_time == 0
12✔
970
                                      ? std::chrono::system_clock::now()
12✔
971
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
972

973
      std::vector<Botan::X509_Certificate> end_certs;
12✔
974
      end_certs.push_back(safe_get(cert));
12✔
975
      for(size_t i = 0; i != intermediates_len; ++i) {
30✔
976
         end_certs.push_back(safe_get(intermediates[i]));
18✔
977
      }
978

979
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
12✔
980
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
12✔
981
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
12✔
982
      std::vector<Botan::Certificate_Store*> trusted_roots;
12✔
983

984
      if(trusted_path != nullptr && *trusted_path != 0) {
12✔
985
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
986
         trusted_roots.push_back(trusted_from_path.get());
2✔
987
      }
988

989
      if(trusted_len > 0) {
12✔
990
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
18✔
991
         for(size_t i = 0; i != trusted_len; ++i) {
18✔
992
            trusted_extra->add_certificate(safe_get(trusted[i]));
9✔
993
         }
994
         trusted_roots.push_back(trusted_extra.get());
9✔
995
      }
996

997
      if(crls_len > 0) {
12✔
998
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
999
         for(size_t i = 0; i != crls_len; ++i) {
13✔
1000
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
1001
         }
1002
         trusted_roots.push_back(trusted_crls.get());
5✔
1003
      }
1004

1005
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
24✔
1006

1007
      auto validation_result =
12✔
1008
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
12✔
1009

1010
      if(result_code != nullptr) {
12✔
1011
         *result_code = static_cast<int>(validation_result.result());
12✔
1012
      }
1013

1014
      if(validation_result.successful_validation()) {
12✔
1015
         return 0;
1016
      } else {
1017
         return 1;
8✔
1018
      }
1019
   });
14✔
1020
#else
1021
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
1022
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
1023
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
1024
#endif
1025
}
1026
}
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