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

randombit / botan / 20751057581

06 Jan 2026 02:18PM UTC coverage: 90.433% (+0.009%) from 90.424%
20751057581

Pull #5188

github

web-flow
Merge 8cc4c6141 into f536862f0
Pull Request #5188: FFI: Generic getter(s) for X.509 objects

101763 of 112529 relevant lines covered (90.43%)

12998968.06 hits per line

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

93.94
/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/x509_ext.h>
17
   #include <botan/x509cert.h>
18
   #include <botan/x509path.h>
19
   #include <botan/internal/loadstor.h>
20
   #include <botan/internal/stl_util.h>
21
#endif
22

23
extern "C" {
24

25
using namespace Botan_FFI;
26

27
#if defined(BOTAN_HAS_X509_CERTIFICATES)
28

29
BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
26✔
30

31
#endif
32

33
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
25✔
34
   if(cert_obj == nullptr || cert_path == nullptr) {
25✔
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 {
25✔
41
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
25✔
42
      return ffi_new_object(cert_obj, std::move(c));
25✔
43
   });
50✔
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

86
namespace {
87

88
int botan_x509_object_view_binary_values(const Botan::X509_Object& object,
3✔
89
                                         botan_x509_value_type value_type,
90
                                         botan_view_ctx ctx,
91
                                         botan_view_bin_fn view_fn) {
92
   auto view = [=](std::span<const uint8_t> value) { return invoke_view_callback(view_fn, ctx, value); };
1✔
93

94
   switch(value_type) {
3✔
95
      case BOTAN_X509_TBS_DATA_BITS:
1✔
96
         return view(object.tbs_data());
3✔
97
      case BOTAN_X509_SIGNATURE_SCHEME_BITS:
1✔
98
         return view(object.signature_algorithm().BER_encode());
3✔
99
      case BOTAN_X509_SIGNATURE_BITS:
1✔
100
         return view(object.signature());
4✔
101
      case BOTAN_X509_DER_ENCODING:
×
102
         return view(object.BER_encode());
×
103
      default:
104
         return BOTAN_FFI_ERROR_INTERNAL_ERROR; /* called with unexpected (non-generic) value_type */
105
   }
106
}
107

108
}  // namespace
109

110
extern "C" {
111

112
int botan_x509_cert_view_binary_values(botan_x509_cert_t cert,
11✔
113
                                       botan_x509_value_type value_type,
114
                                       size_t index,
115
                                       botan_view_ctx ctx,
116
                                       botan_view_bin_fn view_fn) {
117
#if defined(BOTAN_HAS_X509_CERTIFICATES)
118
   if(index != 0) {
11✔
119
      // As of now there are no multi-value binary entries.
120
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
121
   }
122

123
   auto view = [=](std::span<const uint8_t> value) { return invoke_view_callback(view_fn, ctx, value); };
3✔
124

125
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
21✔
126
      switch(value_type) {
127
         case BOTAN_X509_SERIAL_NUMBER:
128
            return view(c.serial_number());
129
         case BOTAN_X509_SUBJECT_DN_BITS:
130
            return view(c.raw_subject_dn());
131
         case BOTAN_X509_ISSUER_DN_BITS:
132
            return view(c.raw_issuer_dn());
133
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
134
            return c.subject_key_id().empty() ? BOTAN_FFI_ERROR_NO_VALUE : view(c.subject_key_id());
135
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
136
            return c.authority_key_id().empty() ? BOTAN_FFI_ERROR_NO_VALUE : view(c.authority_key_id());
137
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
138
            return view(c.subject_public_key_info());
139

140
         case BOTAN_X509_TBS_DATA_BITS:
141
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
142
         case BOTAN_X509_SIGNATURE_BITS:
143
         case BOTAN_X509_DER_ENCODING:
144
            return botan_x509_object_view_binary_values(c, value_type, ctx, view_fn);
145

146
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
147
         case BOTAN_X509_OCSP_RESPONDER_URLS:
148
         case BOTAN_X509_CA_ISSUERS_URLS:
149
            return BOTAN_FFI_ERROR_NO_VALUE;
150
      }
151

152
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
153
   });
154
#else
155
   BOTAN_UNUSED(cert, value_type, index, ctx, view);
156
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
157
#endif
158
}
159

160
int botan_x509_cert_view_string_values(botan_x509_cert_t cert,
11✔
161
                                       botan_x509_value_type value_type,
162
                                       size_t index,
163
                                       botan_view_ctx ctx,
164
                                       botan_view_str_fn view_fn) {
165
#if defined(BOTAN_HAS_X509_CERTIFICATES)
166
   auto enumerate = [view_fn, ctx](auto values, size_t idx) -> int {
7✔
167
      if(idx >= values.size()) {
7✔
168
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;
169
      } else {
170
         return invoke_view_callback(view_fn, ctx, values[idx]);
3✔
171
      }
172
   };
11✔
173

174
   auto enumerate_crl_distribution_points = [view_fn, ctx](const Botan::X509_Certificate& c, size_t idx) -> int {
15✔
175
      const auto* crl_dp_ext =
4✔
176
         c.v3_extensions().get_extension_object_as<Botan::Cert_Extension::CRL_Distribution_Points>();
8✔
177
      if(crl_dp_ext == nullptr) {
4✔
178
         return BOTAN_FFI_ERROR_OUT_OF_RANGE;  // essentially an empty list
179
      }
180

181
      const auto& dps = crl_dp_ext->distribution_points();
3✔
182
      for(size_t i = idx; const auto& dp : dps) {
4✔
183
         const auto& uris = dp.point().uris();
3✔
184
         if(i >= uris.size()) {
3✔
185
            i -= uris.size();
1✔
186
            continue;
1✔
187
         }
188

189
         auto itr = uris.begin();
2✔
190
         std::advance(itr, i);
2✔
191
         return invoke_view_callback(view_fn, ctx, *itr);
4✔
192
      }
193

194
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
195
   };
11✔
196

197
   auto wrap_or_empty = [](std::string str) -> std::vector<std::string> {
14✔
198
      if(str.empty()) {
3✔
199
         return {};
1✔
200
      } else {
201
         return {std::move(str)};
4✔
202
      }
203
   };
2✔
204

205
   return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) -> int {
22✔
206
      switch(value_type) {
207
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
208
            return enumerate_crl_distribution_points(c, index);
209
         case BOTAN_X509_OCSP_RESPONDER_URLS:
210
            return enumerate(wrap_or_empty(c.ocsp_responder()), index);
211
         case BOTAN_X509_CA_ISSUERS_URLS:
212
            return enumerate(c.ca_issuers(), index);
213

214
         case BOTAN_X509_SERIAL_NUMBER:
215
         case BOTAN_X509_SUBJECT_DN_BITS:
216
         case BOTAN_X509_ISSUER_DN_BITS:
217
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
218
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
219
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
220
         case BOTAN_X509_TBS_DATA_BITS:
221
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
222
         case BOTAN_X509_SIGNATURE_BITS:
223
         case BOTAN_X509_DER_ENCODING:
224
            return BOTAN_FFI_ERROR_NO_VALUE;
225
      }
226

227
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
228
   });
229
#else
230
   BOTAN_UNUSED(cert, value_type, index, ctx, view);
231
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
232
#endif
233
}
234

235
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
236
   if(key == nullptr) {
2✔
237
      return BOTAN_FFI_ERROR_NULL_POINTER;
238
   }
239

240
   *key = nullptr;
2✔
241

242
#if defined(BOTAN_HAS_X509_CERTIFICATES)
243
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
244
      auto public_key = safe_get(cert).subject_public_key();
2✔
245
      return ffi_new_object(key, std::move(public_key));
2✔
246
   });
4✔
247
#else
248
   BOTAN_UNUSED(cert);
249
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
250
#endif
251
}
252

253
int botan_x509_cert_get_issuer_dn(
8✔
254
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
255
#if defined(BOTAN_HAS_X509_CERTIFICATES)
256
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
257
      auto issuer_info = c.issuer_info(key);
258
      if(index < issuer_info.size()) {
259
         // TODO(Botan4) change the type of out and remove this cast
260
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
261
      } else {
262
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
263
      }
264
   });
265
#else
266
   BOTAN_UNUSED(cert, key, index, out, out_len);
267
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
268
#endif
269
}
270

271
int botan_x509_cert_get_subject_dn(
8✔
272
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
273
#if defined(BOTAN_HAS_X509_CERTIFICATES)
274
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
275
      auto subject_info = c.subject_info(key);
276
      if(index < subject_info.size()) {
277
         // TODO(Botan4) change the type of out and remove this cast
278
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
279
      } else {
280
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
281
      }
282
   });
283
#else
284
   BOTAN_UNUSED(cert, key, index, out, out_len);
285
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
286
#endif
287
}
288

289
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
290
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
291
}
292

293
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
294
#if defined(BOTAN_HAS_X509_CERTIFICATES)
295
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
296
#else
297
   BOTAN_UNUSED(cert, ctx, view);
298
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
299
#endif
300
}
301

302
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
7✔
303
#if defined(BOTAN_HAS_X509_CERTIFICATES)
304
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
14✔
305
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
306
      if(c.allowed_usage(k)) {
307
         return BOTAN_FFI_SUCCESS;
308
      }
309
      return 1;
310
   });
311
#else
312
   BOTAN_UNUSED(cert, key_usage);
313
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
314
#endif
315
}
316

317
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
26✔
318
#if defined(BOTAN_HAS_X509_CERTIFICATES)
319
   return BOTAN_FFI_CHECKED_DELETE(cert);
26✔
320
#else
321
   BOTAN_UNUSED(cert);
322
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
323
#endif
324
}
325

326
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
327
#if defined(BOTAN_HAS_X509_CERTIFICATES)
328
   return BOTAN_FFI_VISIT(cert,
6✔
329
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
330
#else
331
   BOTAN_UNUSED(cert, out, out_len);
332
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
333
#endif
334
}
335

336
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
337
#if defined(BOTAN_HAS_X509_CERTIFICATES)
338
   return BOTAN_FFI_VISIT(cert,
4✔
339
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
340
#else
341
   BOTAN_UNUSED(cert, out, out_len);
342
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
343
#endif
344
}
345

346
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
347
#if defined(BOTAN_HAS_X509_CERTIFICATES)
348
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
349
#else
350
   BOTAN_UNUSED(cert, time_since_epoch);
351
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
352
#endif
353
}
354

355
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
356
#if defined(BOTAN_HAS_X509_CERTIFICATES)
357
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
358
#else
359
   BOTAN_UNUSED(cert, time_since_epoch);
360
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
361
#endif
362
}
363

364
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
365
#if defined(BOTAN_HAS_X509_CERTIFICATES)
366
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
6✔
367
#else
368
   BOTAN_UNUSED(cert, out, out_len);
369
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
370
#endif
371
}
372

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

377
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
378
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
379
   });
380
#else
381
   BOTAN_UNUSED(cert, hash, out, out_len);
382
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
383
#endif
384
}
385

386
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
387
#if defined(BOTAN_HAS_X509_CERTIFICATES)
388
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
389
#else
390
   BOTAN_UNUSED(cert, out, out_len);
391
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
392
#endif
393
}
394

395
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
396
#if defined(BOTAN_HAS_X509_CERTIFICATES)
397
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
398
#else
399
   BOTAN_UNUSED(cert, out, out_len);
400
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
401
#endif
402
}
403

404
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
405
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
406
}
407

408
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
409
#if defined(BOTAN_HAS_X509_CERTIFICATES)
410
   return BOTAN_FFI_VISIT(cert,
6✔
411
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
412
#else
413
   BOTAN_UNUSED(cert, ctx, view);
414
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
415
#endif
416
}
417

418
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
419
   if(hostname == nullptr) {
6✔
420
      return BOTAN_FFI_ERROR_NULL_POINTER;
421
   }
422

423
#if defined(BOTAN_HAS_X509_CERTIFICATES)
424
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
425
#else
426
   BOTAN_UNUSED(cert);
427
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
428
#endif
429
}
430

431
int botan_x509_cert_verify(int* result_code,
4✔
432
                           botan_x509_cert_t cert,
433
                           const botan_x509_cert_t* intermediates,
434
                           size_t intermediates_len,
435
                           const botan_x509_cert_t* trusted,
436
                           size_t trusted_len,
437
                           const char* trusted_path,
438
                           size_t required_strength,
439
                           const char* hostname_cstr,
440
                           uint64_t reference_time) {
441
   if(required_strength == 0) {
4✔
442
      required_strength = 110;
3✔
443
   }
444

445
#if defined(BOTAN_HAS_X509_CERTIFICATES)
446
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
447
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
448
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
449
      const auto validation_time = reference_time == 0
4✔
450
                                      ? std::chrono::system_clock::now()
4✔
451
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
452

453
      std::vector<Botan::X509_Certificate> end_certs;
4✔
454
      end_certs.push_back(safe_get(cert));
4✔
455
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
456
         end_certs.push_back(safe_get(intermediates[i]));
5✔
457
      }
458

459
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
460
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
461
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
462

463
      if(trusted_path != nullptr && *trusted_path != 0) {
4✔
464
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
465
         trusted_roots.push_back(trusted_from_path.get());
×
466
      }
467

468
      if(trusted_len > 0) {
4✔
469
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
470
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
471
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
472
         }
473
         trusted_roots.push_back(trusted_extra.get());
4✔
474
      }
475

476
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
477

478
      auto validation_result =
4✔
479
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
480

481
      if(result_code != nullptr) {
4✔
482
         *result_code = static_cast<int>(validation_result.result());
4✔
483
      }
484

485
      if(validation_result.successful_validation()) {
4✔
486
         return 0;
487
      } else {
488
         return 1;
3✔
489
      }
490
   });
4✔
491
#else
492
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
493
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
494
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
495
#endif
496
}
497

498
const char* botan_x509_cert_validation_status(int code) {
11✔
499
   if(code < 0) {
11✔
500
      return nullptr;
501
   }
502

503
#if defined(BOTAN_HAS_X509_CERTIFICATES)
504
   const Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
505
   return Botan::to_string(sc);
11✔
506
#else
507
   return nullptr;
508
#endif
509
}
510

511
#if defined(BOTAN_HAS_X509_CERTIFICATES)
512

513
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
7✔
514

515
#endif
516

517
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
6✔
518
   if(crl_obj == nullptr || crl_path == nullptr) {
6✔
519
      return BOTAN_FFI_ERROR_NULL_POINTER;
520
   }
521

522
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
523

524
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
525
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
6✔
526
      return ffi_new_object(crl_obj, std::move(c));
12✔
527
   });
12✔
528

529
#else
530
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
531
#endif
532
}
533

534
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
535
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
536
      return BOTAN_FFI_ERROR_NULL_POINTER;
537
   }
538

539
#if defined(BOTAN_HAS_X509_CERTIFICATES)
540
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
541
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
542
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
543
      return ffi_new_object(crl_obj, std::move(c));
1✔
544
   });
3✔
545
#else
546
   BOTAN_UNUSED(crl_bits_len);
547
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
548
#endif
549
}
550

551
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
7✔
552
#if defined(BOTAN_HAS_X509_CERTIFICATES)
553
   return BOTAN_FFI_CHECKED_DELETE(crl);
7✔
554
#else
555
   BOTAN_UNUSED(crl);
556
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
557
#endif
558
}
559

560
int botan_x509_crl_view_binary_values(botan_x509_crl_t crl_obj,
2✔
561
                                      botan_x509_value_type value_type,
562
                                      size_t index,
563
                                      botan_view_ctx ctx,
564
                                      botan_view_bin_fn view_fn) {
565
#if defined(BOTAN_HAS_X509_CERTIFICATES)
566
   if(index != 0) {
2✔
567
      // As of now there are no multi-value binary entries.
568
      return BOTAN_FFI_ERROR_OUT_OF_RANGE;
569
   }
570

571
   auto view = [=](std::span<const uint8_t> value) { return invoke_view_callback(view_fn, ctx, value); };
1✔
572

573
   return BOTAN_FFI_VISIT(crl_obj, [=](const Botan::X509_CRL& crl) -> int {
8✔
574
      switch(value_type) {
575
         case BOTAN_X509_SERIAL_NUMBER:
576
            return view(Botan::store_be(crl.crl_number()));
577
         case BOTAN_X509_ISSUER_DN_BITS:
578
            return view(Botan::ASN1::put_in_sequence(crl.issuer_dn().get_bits()));
579
         case BOTAN_X509_AUTHORITY_KEY_IDENTIFIER:
580
            return crl.authority_key_id().empty() ? BOTAN_FFI_ERROR_NO_VALUE : view(crl.authority_key_id());
581

582
         case BOTAN_X509_TBS_DATA_BITS:
583
         case BOTAN_X509_SIGNATURE_SCHEME_BITS:
584
         case BOTAN_X509_SIGNATURE_BITS:
585
         case BOTAN_X509_DER_ENCODING:
586
            return botan_x509_object_view_binary_values(crl, value_type, ctx, view_fn);
587

588
         case BOTAN_X509_SUBJECT_DN_BITS:
589
         case BOTAN_X509_SUBJECT_KEY_IDENTIFIER:
590
         case BOTAN_X509_PUBLIC_KEY_PKCS8_BITS:
591
         case BOTAN_X509_CRL_DISTRIBUTION_URLS:
592
         case BOTAN_X509_OCSP_RESPONDER_URLS:
593
         case BOTAN_X509_CA_ISSUERS_URLS:
594
            return BOTAN_FFI_ERROR_NO_VALUE;
595
      }
596

597
      return BOTAN_FFI_ERROR_BAD_PARAMETER;
598
   });
599
#else
600
   BOTAN_UNUSED(crl_obj, value_type, index, ctx, view);
601
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
602
#endif
603
}
604

605
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
606
#if defined(BOTAN_HAS_X509_CERTIFICATES)
607
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
608
#else
609
   BOTAN_UNUSED(cert);
610
   BOTAN_UNUSED(crl);
611
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
612
#endif
613
}
614

615
int botan_x509_cert_verify_with_crl(int* result_code,
12✔
616
                                    botan_x509_cert_t cert,
617
                                    const botan_x509_cert_t* intermediates,
618
                                    size_t intermediates_len,
619
                                    const botan_x509_cert_t* trusted,
620
                                    size_t trusted_len,
621
                                    const botan_x509_crl_t* crls,
622
                                    size_t crls_len,
623
                                    const char* trusted_path,
624
                                    size_t required_strength,
625
                                    const char* hostname_cstr,
626
                                    uint64_t reference_time) {
627
   if(required_strength == 0) {
12✔
628
      required_strength = 110;
2✔
629
   }
630

631
#if defined(BOTAN_HAS_X509_CERTIFICATES)
632
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
633
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
14✔
634
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
12✔
635
      const auto validation_time = reference_time == 0
12✔
636
                                      ? std::chrono::system_clock::now()
12✔
637
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
638

639
      std::vector<Botan::X509_Certificate> end_certs;
12✔
640
      end_certs.push_back(safe_get(cert));
12✔
641
      for(size_t i = 0; i != intermediates_len; ++i) {
30✔
642
         end_certs.push_back(safe_get(intermediates[i]));
18✔
643
      }
644

645
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
12✔
646
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
12✔
647
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
12✔
648
      std::vector<Botan::Certificate_Store*> trusted_roots;
12✔
649

650
      if(trusted_path != nullptr && *trusted_path != 0) {
12✔
651
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
652
         trusted_roots.push_back(trusted_from_path.get());
2✔
653
      }
654

655
      if(trusted_len > 0) {
12✔
656
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
18✔
657
         for(size_t i = 0; i != trusted_len; ++i) {
18✔
658
            trusted_extra->add_certificate(safe_get(trusted[i]));
9✔
659
         }
660
         trusted_roots.push_back(trusted_extra.get());
9✔
661
      }
662

663
      if(crls_len > 0) {
12✔
664
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
665
         for(size_t i = 0; i != crls_len; ++i) {
13✔
666
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
667
         }
668
         trusted_roots.push_back(trusted_crls.get());
5✔
669
      }
670

671
      const Botan::Path_Validation_Restrictions restrictions(false, required_strength);
24✔
672

673
      auto validation_result =
12✔
674
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
12✔
675

676
      if(result_code != nullptr) {
12✔
677
         *result_code = static_cast<int>(validation_result.result());
12✔
678
      }
679

680
      if(validation_result.successful_validation()) {
12✔
681
         return 0;
682
      } else {
683
         return 1;
8✔
684
      }
685
   });
14✔
686
#else
687
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
688
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
689
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
690
#endif
691
}
692
}
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