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

randombit / botan / 20949937781

13 Jan 2026 08:30AM UTC coverage: 91.917% (+1.5%) from 90.454%
20949937781

Pull #5234

github

web-flow
Merge 2cfce7a46 into cc836e3df
Pull Request #5234: FFI: add `*_count()` functions for DN enumerators

103790 of 112917 relevant lines covered (91.92%)

12511441.85 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_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;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
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_issuer_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
150
#if defined(BOTAN_HAS_X509_CERTIFICATES)
151
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
152
      if(Botan::any_null_pointers(count)) {
153
         return BOTAN_FFI_ERROR_NULL_POINTER;
154
      }
155

156
      *count = c.issuer_info(key).size();
157
      return BOTAN_FFI_SUCCESS;
158
   });
159
#else
160
   BOTAN_UNUSED(cert, key, count);
161
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
162
#endif
163
}
164

165
int botan_x509_cert_get_subject_dn(
8✔
166
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
167
#if defined(BOTAN_HAS_X509_CERTIFICATES)
168
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
169
      auto subject_info = c.subject_info(key);
170
      if(index < subject_info.size()) {
171
         // TODO(Botan4) change the type of out and remove this cast
172
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
173
      } else {
174
         return BOTAN_FFI_ERROR_BAD_PARAMETER;  // TODO(Botan4): use BOTAN_FFI_ERROR_OUT_OF_RANGE
175
      }
176
   });
177
#else
178
   BOTAN_UNUSED(cert, key, index, out, out_len);
179
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
180
#endif
181
}
182

183
int botan_x509_cert_get_subject_dn_count(botan_x509_cert_t cert, const char* key, size_t* count) {
2✔
184
#if defined(BOTAN_HAS_X509_CERTIFICATES)
185
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
4✔
186
      if(Botan::any_null_pointers(count)) {
187
         return BOTAN_FFI_ERROR_NULL_POINTER;
188
      }
189

190
      *count = c.subject_info(key).size();
191
      return BOTAN_FFI_SUCCESS;
192
   });
193
#else
194
   BOTAN_UNUSED(cert, key, count);
195
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
196
#endif
197
}
198

199
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
200
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
201
}
202

203
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
204
#if defined(BOTAN_HAS_X509_CERTIFICATES)
205
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
206
#else
207
   BOTAN_UNUSED(cert, ctx, view);
208
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
209
#endif
210
}
211

212
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
213
#if defined(BOTAN_HAS_X509_CERTIFICATES)
214
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
215
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
216
      if(c.allowed_usage(k)) {
217
         return BOTAN_FFI_SUCCESS;
218
      }
219
      return 1;
220
   });
221
#else
222
   BOTAN_UNUSED(cert, key_usage);
223
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
224
#endif
225
}
226

227
int botan_x509_cert_allowed_extended_usage_str(botan_x509_cert_t cert, const char* oid) {
12✔
228
#if defined(BOTAN_HAS_X509_CERTIFICATES)
229
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
32✔
230
      if(Botan::any_null_pointers(oid)) {
231
         return BOTAN_FFI_ERROR_NULL_POINTER;
232
      }
233

234
      return c.has_ex_constraint(oid) ? BOTAN_FFI_SUCCESS : 1;
235
   });
236
#else
237
   BOTAN_UNUSED(cert, oid);
238
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
239
#endif
240
}
241

242
int botan_x509_cert_allowed_extended_usage_oid(botan_x509_cert_t cert, botan_asn1_oid_t oid) {
4✔
243
#if defined(BOTAN_HAS_X509_CERTIFICATES)
244
   return BOTAN_FFI_VISIT(
8✔
245
      cert, [=](const auto& c) -> int { return c.has_ex_constraint(safe_get(oid)) ? BOTAN_FFI_SUCCESS : 1; });
246
#else
247
   BOTAN_UNUSED(cert, oid);
248
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
249
#endif
250
}
251

252
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
30✔
253
#if defined(BOTAN_HAS_X509_CERTIFICATES)
254
   return BOTAN_FFI_CHECKED_DELETE(cert);
30✔
255
#else
256
   BOTAN_UNUSED(cert);
257
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
258
#endif
259
}
260

261
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
262
#if defined(BOTAN_HAS_X509_CERTIFICATES)
263
   return BOTAN_FFI_VISIT(cert,
6✔
264
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
265
#else
266
   BOTAN_UNUSED(cert, out, out_len);
267
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
268
#endif
269
}
270

271
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
272
#if defined(BOTAN_HAS_X509_CERTIFICATES)
273
   return BOTAN_FFI_VISIT(cert,
4✔
274
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
275
#else
276
   BOTAN_UNUSED(cert, out, out_len);
277
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
278
#endif
279
}
280

281
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
282
#if defined(BOTAN_HAS_X509_CERTIFICATES)
283
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
284
#else
285
   BOTAN_UNUSED(cert, time_since_epoch);
286
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
287
#endif
288
}
289

290
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
291
#if defined(BOTAN_HAS_X509_CERTIFICATES)
292
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
293
#else
294
   BOTAN_UNUSED(cert, time_since_epoch);
295
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
296
#endif
297
}
298

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

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

312
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
313
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
314
   });
315
#else
316
   BOTAN_UNUSED(cert, hash, out, out_len);
317
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
318
#endif
319
}
320

321
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
322
#if defined(BOTAN_HAS_X509_CERTIFICATES)
323
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
324
#else
325
   BOTAN_UNUSED(cert, out, out_len);
326
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
327
#endif
328
}
329

330
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
331
#if defined(BOTAN_HAS_X509_CERTIFICATES)
332
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
333
#else
334
   BOTAN_UNUSED(cert, out, out_len);
335
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
336
#endif
337
}
338

339
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
340
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
341
}
342

343
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
344
#if defined(BOTAN_HAS_X509_CERTIFICATES)
345
   return BOTAN_FFI_VISIT(cert,
6✔
346
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
347
#else
348
   BOTAN_UNUSED(cert, ctx, view);
349
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
350
#endif
351
}
352
}
353

354
namespace {
355

356
std::optional<botan_x509_general_name_types> to_botan_x509_general_name_types(Botan::GeneralName::NameType gn_type) {
301✔
357
   using Type = Botan::GeneralName::NameType;
301✔
358
   switch(gn_type) {
301✔
359
      case Type::Unknown:
1✔
360
         return std::nullopt;
1✔
361
      case Type::RFC822:
83✔
362
         return BOTAN_X509_EMAIL_ADDRESS;
83✔
363
      case Type::DNS:
73✔
364
         return BOTAN_X509_DNS_NAME;
73✔
365
      case Type::URI:
28✔
366
         return BOTAN_X509_URI;
28✔
367
      case Type::DN:
95✔
368
         return BOTAN_X509_DIRECTORY_NAME;
95✔
369
      case Type::IPv4:
21✔
370
         return BOTAN_X509_IP_ADDRESS;
21✔
371
      case Type::Other:
×
372
         return BOTAN_X509_OTHER_NAME;
×
373
   }
374

375
   BOTAN_ASSERT_UNREACHABLE();
×
376
}
377

378
}  // namespace
379

380
extern "C" {
381

382
int botan_x509_general_name_get_type(botan_x509_general_name_t name, unsigned int* type) {
198✔
383
#if defined(BOTAN_HAS_X509_CERTIFICATES)
384
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) {
396✔
385
      if(Botan::any_null_pointers(type)) {
386
         return BOTAN_FFI_ERROR_NULL_POINTER;
387
      }
388

389
      const auto mapped_type = to_botan_x509_general_name_types(n.type_code());
390
      if(!mapped_type.has_value()) {
391
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
392
      }
393

394
      *type = mapped_type.value();
395
      if(*type == BOTAN_X509_OTHER_NAME /* ... viewing of other-names not supported */) {
396
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
397
      }
398

399
      return BOTAN_FFI_SUCCESS;
400
   });
401
#else
402
   BOTAN_UNUSED(name, type);
403
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
404
#endif
405
}
406

407
int botan_x509_general_name_view_string_value(botan_x509_general_name_t name,
66✔
408
                                              botan_view_ctx ctx,
409
                                              botan_view_str_fn view) {
410
#if defined(BOTAN_HAS_X509_CERTIFICATES)
411
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
197✔
412
      const auto type = to_botan_x509_general_name_types(n.type_code());
413
      if(!type) {
414
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
415
      }
416

417
      if(type != BOTAN_X509_EMAIL_ADDRESS && type != BOTAN_X509_DNS_NAME && type != BOTAN_X509_URI &&
418
         type != BOTAN_X509_IP_ADDRESS) {
419
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
420
      }
421

422
      return invoke_view_callback(view, ctx, n.name());
423
   });
424
#else
425
   BOTAN_UNUSED(name, ctx, view);
426
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
427
#endif
428
}
429

430
int botan_x509_general_name_view_binary_value(botan_x509_general_name_t name,
37✔
431
                                              botan_view_ctx ctx,
432
                                              botan_view_bin_fn view) {
433
#if defined(BOTAN_HAS_X509_CERTIFICATES)
434
   return BOTAN_FFI_VISIT(name, [=](const Botan::GeneralName& n) -> int {
144✔
435
      const auto type = to_botan_x509_general_name_types(n.type_code());
436
      if(!type) {
437
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
438
      }
439

440
      if(type != BOTAN_X509_DIRECTORY_NAME && type != BOTAN_X509_IP_ADDRESS) {
441
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
442
      }
443

444
      return invoke_view_callback(view, ctx, n.binary_name());
445
   });
446
#else
447
   BOTAN_UNUSED(name, ctx, view);
448
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
449
#endif
450
}
451

452
int botan_x509_general_name_destroy(botan_x509_general_name_t name) {
198✔
453
#if defined(BOTAN_HAS_X509_CERTIFICATES)
454
   return BOTAN_FFI_CHECKED_DELETE(name);
198✔
455
#else
456
   BOTAN_UNUSED(name);
457
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
458
#endif
459
}
460

461
int botan_x509_cert_permitted_name_constraints(botan_x509_cert_t cert,
76✔
462
                                               size_t index,
463
                                               botan_x509_general_name_t* constraint) {
464
#if defined(BOTAN_HAS_X509_CERTIFICATES)
465
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
466
      if(Botan::any_null_pointers(constraint)) {
467
         return BOTAN_FFI_ERROR_NULL_POINTER;
468
      }
469

470
      const auto& constraints = c.name_constraints().permitted();
471
      if(index >= constraints.size()) {
472
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
473
      }
474

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

483
int botan_x509_cert_permitted_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
484
#if defined(BOTAN_HAS_X509_CERTIFICATES)
485
   if(Botan::any_null_pointers(count)) {
1✔
486
      return BOTAN_FFI_ERROR_NULL_POINTER;
487
   }
488

489
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().permitted().size(); });
2✔
490
#else
491
   BOTAN_UNUSED(cert, count);
492
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
493
#endif
494
}
495

496
int botan_x509_cert_excluded_name_constraints(botan_x509_cert_t cert,
4✔
497
                                              size_t index,
498
                                              botan_x509_general_name_t* constraint) {
499
#if defined(BOTAN_HAS_X509_CERTIFICATES)
500
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
8✔
501
      if(Botan::any_null_pointers(constraint)) {
502
         return BOTAN_FFI_ERROR_NULL_POINTER;
503
      }
504

505
      const auto& constraints = c.name_constraints().excluded();
506
      if(index >= constraints.size()) {
507
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
508
      }
509

510
      return ffi_new_object(constraint, std::make_unique<Botan::GeneralName>(constraints[index].base()));
511
   });
512
#else
513
   BOTAN_UNUSED(cert, index, constraint);
514
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
515
#endif
516
}
517

518
int botan_x509_cert_excluded_name_constraints_count(botan_x509_cert_t cert, size_t* count) {
1✔
519
#if defined(BOTAN_HAS_X509_CERTIFICATES)
520
   if(Botan::any_null_pointers(count)) {
1✔
521
      return BOTAN_FFI_ERROR_NULL_POINTER;
522
   }
523

524
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *count = c.name_constraints().excluded().size(); });
2✔
525
#else
526
   BOTAN_UNUSED(cert, count);
527
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
528
#endif
529
}
530
}
531

532
namespace {
533

534
/**
535
 * As specified in RFC 5280 Section 4.2.1.6. alternative names essentially are a
536
 * collection of GeneralNames. This allows mapping a single entry of @p altnames
537
 * to a GeneralName by its @p index. If the index is out of range, std::nullopt
538
 * is returned.
539
 *
540
 * NOTE: if the set of alternative name types handled here is extended,
541
 *       count_general_names_in() must be updated accordingly!
542
 */
543
std::optional<Botan::GeneralName> extract_general_name_at(const Botan::AlternativeName& altnames, size_t index) {
132✔
544
   if(index < altnames.email().size()) {
132✔
545
      auto itr = altnames.email().begin();
12✔
546
      std::advance(itr, index);
12✔
547
      return Botan::GeneralName::email(*itr);
36✔
548
   }
549
   index -= altnames.email().size();
120✔
550

551
   if(index < altnames.dns().size()) {
120✔
552
      auto itr = altnames.dns().begin();
36✔
553
      std::advance(itr, index);
36✔
554
      return Botan::GeneralName::dns(*itr);
108✔
555
   }
556
   index -= altnames.dns().size();
84✔
557

558
   if(index < altnames.directory_names().size()) {
84✔
559
      auto itr = altnames.directory_names().begin();
36✔
560
      std::advance(itr, index);
36✔
561
      return Botan::GeneralName::directory_name(*itr);
108✔
562
   }
563
   index -= altnames.directory_names().size();
48✔
564

565
   if(index < altnames.uris().size()) {
48✔
566
      auto itr = altnames.uris().begin();
24✔
567
      std::advance(itr, index);
24✔
568
      return Botan::GeneralName::uri(*itr);
72✔
569
   }
570
   index -= altnames.uris().size();
24✔
571

572
   if(index < altnames.ipv4_address().size()) {
24✔
573
      auto itr = altnames.ipv4_address().begin();
12✔
574
      std::advance(itr, index);
12✔
575
      return Botan::GeneralName::ipv4_address(*itr);
36✔
576
   }
577

578
   return std::nullopt;
12✔
579
}
580

581
/**
582
 * Counts the total number of GeneralNames contained in the given
583
 * AlternativeName @p alt_names.
584
 *
585
 * NOTE: if the set of alternative name types handled here is extended,
586
 *       extract_general_name_at() must be updated accordingly!
587
 */
588
size_t count_general_names_in(const Botan::AlternativeName& alt_names) {
12✔
589
   return alt_names.email().size() + alt_names.dns().size() + alt_names.directory_names().size() +
12✔
590
          alt_names.uris().size() + alt_names.ipv4_address().size();
12✔
591
}
592

593
}  // namespace
594

595
extern "C" {
596

597
int botan_x509_cert_subject_alternative_names(botan_x509_cert_t cert,
73✔
598
                                              size_t index,
599
                                              botan_x509_general_name_t* alt_name) {
600
#if defined(BOTAN_HAS_X509_CERTIFICATES)
601
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
152✔
602
      if(Botan::any_null_pointers(alt_name)) {
603
         return BOTAN_FFI_ERROR_NULL_POINTER;
604
      }
605

606
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.SubjectAlternativeName"))) {
607
         return BOTAN_FFI_ERROR_NO_VALUE;
608
      }
609

610
      if(auto name = extract_general_name_at(c.subject_alt_name(), index)) {
611
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
612
      }
613

614
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
615
   });
616
#else
617
   BOTAN_UNUSED(cert, index, alt_name);
618
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
619
#endif
620
}
621

622
int botan_x509_cert_subject_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
623
#if defined(BOTAN_HAS_X509_CERTIFICATES)
624
   if(Botan::any_null_pointers(count)) {
6✔
625
      return BOTAN_FFI_ERROR_NULL_POINTER;
626
   }
627

628
   return BOTAN_FFI_VISIT(
12✔
629
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.subject_alt_name()); });
630
#else
631
   BOTAN_UNUSED(cert, count);
632
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
633
#endif
634
}
635

636
int botan_x509_cert_issuer_alternative_names(botan_x509_cert_t cert,
61✔
637
                                             size_t index,
638
                                             botan_x509_general_name_t* alt_name) {
639
#if defined(BOTAN_HAS_X509_CERTIFICATES)
640
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) {
128✔
641
      if(Botan::any_null_pointers(alt_name)) {
642
         return BOTAN_FFI_ERROR_NULL_POINTER;
643
      }
644

645
      if(!c.v3_extensions().extension_set(Botan::OID::from_string("X509v3.IssuerAlternativeName"))) {
646
         return BOTAN_FFI_ERROR_NO_VALUE;
647
      }
648

649
      if(auto name = extract_general_name_at(c.issuer_alt_name(), index)) {
650
         return ffi_new_object(alt_name, std::make_unique<Botan::GeneralName>(std::move(name).value()));
651
      }
652

653
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
654
   });
655
#else
656
   BOTAN_UNUSED(cert, index, alt_name);
657
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
658
#endif
659
}
660

661
int botan_x509_cert_issuer_alternative_names_count(botan_x509_cert_t cert, size_t* count) {
6✔
662
#if defined(BOTAN_HAS_X509_CERTIFICATES)
663
   if(Botan::any_null_pointers(count)) {
6✔
664
      return BOTAN_FFI_ERROR_NULL_POINTER;
665
   }
666

667
   return BOTAN_FFI_VISIT(
12✔
668
      cert, [=](const Botan::X509_Certificate& c) { *count = count_general_names_in(c.issuer_alt_name()); });
669
#else
670
   BOTAN_UNUSED(cert, count);
671
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
672
#endif
673
}
674

675
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
676
   if(hostname == nullptr) {
6✔
677
      return BOTAN_FFI_ERROR_NULL_POINTER;
678
   }
679

680
#if defined(BOTAN_HAS_X509_CERTIFICATES)
681
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
682
#else
683
   BOTAN_UNUSED(cert);
684
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
685
#endif
686
}
687

688
int botan_x509_cert_verify(int* result_code,
4✔
689
                           botan_x509_cert_t cert,
690
                           const botan_x509_cert_t* intermediates,
691
                           size_t intermediates_len,
692
                           const botan_x509_cert_t* trusted,
693
                           size_t trusted_len,
694
                           const char* trusted_path,
695
                           size_t required_strength,
696
                           const char* hostname_cstr,
697
                           uint64_t reference_time) {
698
   if(required_strength == 0) {
4✔
699
      required_strength = 110;
3✔
700
   }
701

702
#if defined(BOTAN_HAS_X509_CERTIFICATES)
703
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
704
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
705
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
706
      const auto validation_time = reference_time == 0
4✔
707
                                      ? std::chrono::system_clock::now()
4✔
708
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
709

710
      std::vector<Botan::X509_Certificate> end_certs;
4✔
711
      end_certs.push_back(safe_get(cert));
4✔
712
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
713
         end_certs.push_back(safe_get(intermediates[i]));
5✔
714
      }
715

716
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
717
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
718
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
719

720
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
721
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
722
         trusted_roots.push_back(trusted_from_path.get());
×
723
      }
724

725
      if(trusted_len > 0) {
4✔
726
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
727
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
728
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
729
         }
730
         trusted_roots.push_back(trusted_extra.get());
4✔
731
      }
732

733
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
734

735
      auto validation_result =
4✔
736
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
737

738
      if(result_code != nullptr) {
4✔
739
         *result_code = static_cast<int>(validation_result.result());
4✔
740
      }
741

742
      if(validation_result.successful_validation()) {
4✔
743
         return 0;
744
      } else {
745
         return 1;
3✔
746
      }
747
   });
4✔
748
#else
749
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
750
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
751
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
752
#endif
753
}
754

755
const char* botan_x509_cert_validation_status(int code) {
11✔
756
   if(code < 0) {
11✔
757
      return nullptr;
758
   }
759

760
#if defined(BOTAN_HAS_X509_CERTIFICATES)
761
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
762
   return Botan::to_string(sc);
11✔
763
#else
764
   return nullptr;
765
#endif
766
}
767

768
#if defined(BOTAN_HAS_X509_CERTIFICATES)
769

770
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
8✔
771
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_entry_struct, Botan::CRL_Entry, 0x4EAA5346);
1✔
772

773
#endif
774

775
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
7✔
776
   if(crl_obj == nullptr || crl_path == nullptr) {
7✔
777
      return BOTAN_FFI_ERROR_NULL_POINTER;
778
   }
779

780
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
781

782
   return ffi_guard_thunk(__func__, [=]() -> int {
7✔
783
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
7✔
784
      return ffi_new_object(crl_obj, std::move(c));
14✔
785
   });
14✔
786

787
#else
788
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
789
#endif
790
}
791

792
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
793
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
794
      return BOTAN_FFI_ERROR_NULL_POINTER;
795
   }
796

797
#if defined(BOTAN_HAS_X509_CERTIFICATES)
798
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
799
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
800
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
801
      return ffi_new_object(crl_obj, std::move(c));
1✔
802
   });
3✔
803
#else
804
   BOTAN_UNUSED(crl_bits_len);
805
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
806
#endif
807
}
808

809
int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
2✔
810
#if defined(BOTAN_HAS_X509_CERTIFICATES)
811
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
4✔
812
      if(Botan::any_null_pointers(time_since_epoch)) {
813
         return BOTAN_FFI_ERROR_NULL_POINTER;
814
      }
815
      *time_since_epoch = c.this_update().time_since_epoch();
816
      return BOTAN_FFI_SUCCESS;
817
   });
818
#else
819
   BOTAN_UNUSED(crl, time_since_epoch);
820
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
821
#endif
822
}
823

824
int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch) {
4✔
825
#if defined(BOTAN_HAS_X509_CERTIFICATES)
826
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) {
8✔
827
      const auto& time = c.next_update();
828
      if(!time.time_is_set()) {
829
         return BOTAN_FFI_ERROR_NO_VALUE;
830
      }
831

832
      if(Botan::any_null_pointers(time_since_epoch)) {
833
         return BOTAN_FFI_ERROR_NULL_POINTER;
834
      }
835

836
      *time_since_epoch = c.next_update().time_since_epoch();
837
      return BOTAN_FFI_SUCCESS;
838
   });
839
#else
840
   BOTAN_UNUSED(crl, time_since_epoch);
841
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
842
#endif
843
}
844

845
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
8✔
846
#if defined(BOTAN_HAS_X509_CERTIFICATES)
847
   return BOTAN_FFI_CHECKED_DELETE(crl);
8✔
848
#else
849
   BOTAN_UNUSED(crl);
850
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
851
#endif
852
}
853

854
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
855
#if defined(BOTAN_HAS_X509_CERTIFICATES)
856
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
857
#else
858
   BOTAN_UNUSED(cert);
859
   BOTAN_UNUSED(crl);
860
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
861
#endif
862
}
863

864
int botan_x509_crl_entries(botan_x509_crl_t crl, size_t index, botan_x509_crl_entry_t* entry) {
3✔
865
#if defined(BOTAN_HAS_X509_CERTIFICATES)
866
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) -> int {
6✔
867
      const auto& entries = c.get_revoked();
868
      if(index >= entries.size()) {
869
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
870
      }
871

872
      if(Botan::any_null_pointers(entry)) {
873
         return BOTAN_FFI_ERROR_NULL_POINTER;
874
      }
875

876
      return ffi_new_object(entry, std::make_unique<Botan::CRL_Entry>(entries[index]));
877
   });
878
#else
879
   BOTAN_UNUSED(crl, index, entry);
880
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
881
#endif
882
}
883

884
int botan_x509_crl_entries_count(botan_x509_crl_t crl, size_t* count) {
2✔
885
#if defined(BOTAN_HAS_X509_CERTIFICATES)
886
   if(Botan::any_null_pointers(count)) {
2✔
887
      return BOTAN_FFI_ERROR_NULL_POINTER;
888
   }
889

890
   return BOTAN_FFI_VISIT(crl, [=](const Botan::X509_CRL& c) { *count = c.get_revoked().size(); });
4✔
891
#else
892
   BOTAN_UNUSED(crl, count);
893
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
894
#endif
895
}
896

897
int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) {
1✔
898
#if defined(BOTAN_HAS_X509_CERTIFICATES)
899
   return BOTAN_FFI_CHECKED_DELETE(entry);
1✔
900
#else
901
   BOTAN_UNUSED(entry);
902
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
903
#endif
904
}
905

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

913
      *reason_code = static_cast<int>(e.reason_code());
914
      return BOTAN_FFI_SUCCESS;
915
   });
916
#else
917
   BOTAN_UNUSED(entry, reason_code);
918
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
919
#endif
920
}
921

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

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

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

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

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

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

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

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

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

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

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

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

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

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