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

randombit / botan / 16273129754

14 Jul 2025 05:05PM UTC coverage: 90.628% (+0.004%) from 90.624%
16273129754

Pull #4877

github

web-flow
Merge 60770c75b into e18675f45
Pull Request #4877: Add FFI for X.509 creation

100141 of 110497 relevant lines covered (90.63%)

12218814.59 hits per line

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

80.45
/src/lib/ffi/ffi_cert.cpp
1
/*
2
* (C) 2015,2017,2018 Jack Lloyd
3
* (C) 2025 Dominik Schricker
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/ffi.h>
9

10
#include <botan/internal/ffi_cert.h>
11
#include <botan/internal/ffi_oid.h>
12
#include <botan/internal/ffi_pkey.h>
13
#include <botan/internal/ffi_rng.h>
14
#include <botan/internal/ffi_util.h>
15
#include <botan/internal/ffi_x509_rpki.h>
16
#include <memory>
17

18
extern "C" {
19

20
using namespace Botan_FFI;
21

22
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
23✔
23
   if(cert_obj == nullptr || cert_path == nullptr) {
23✔
24
      return BOTAN_FFI_ERROR_NULL_POINTER;
25
   }
26

27
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
28

29
   return ffi_guard_thunk(__func__, [=]() -> int {
23✔
30
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
23✔
31
      return ffi_new_object(cert_obj, std::move(c));
23✔
32
   });
46✔
33

34
#else
35
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
36
#endif
37
}
38

39
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
40
   if(cert_obj == nullptr) {
1✔
41
      return BOTAN_FFI_ERROR_NULL_POINTER;
42
   }
43

44
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
45

46
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
47
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
48
      return ffi_new_object(cert_obj, std::move(c));
1✔
49
   });
2✔
50

51
#else
52
   BOTAN_UNUSED(cert);
53
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
54
#endif
55
}
56

57
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
58
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
59
      return BOTAN_FFI_ERROR_NULL_POINTER;
60
   }
61

62
#if defined(BOTAN_HAS_X509_CERTIFICATES)
63
   return ffi_guard_thunk(__func__, [=]() -> int {
×
64
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
65
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
66
      return ffi_new_object(cert_obj, std::move(c));
×
67
   });
×
68
#else
69
   BOTAN_UNUSED(cert_bits_len);
70
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
71
#endif
72
}
73

74
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
75
   if(key == nullptr) {
2✔
76
      return BOTAN_FFI_ERROR_NULL_POINTER;
77
   }
78

79
   *key = nullptr;
2✔
80

81
#if defined(BOTAN_HAS_X509_CERTIFICATES)
82
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
83
      auto public_key = safe_get(cert).subject_public_key();
2✔
84
      return ffi_new_object(key, std::move(public_key));
2✔
85
   });
4✔
86
#else
87
   BOTAN_UNUSED(cert);
88
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
89
#endif
90
}
91

92
int botan_x509_cert_get_issuer_dn(
8✔
93
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
94
#if defined(BOTAN_HAS_X509_CERTIFICATES)
95
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
96
      auto issuer_info = c.issuer_info(key);
97
      if(index < issuer_info.size()) {
98
         return write_str_output(out, out_len, c.issuer_info(key).at(index));
99
      } else {
100
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
101
      }
102
   });
103
#else
104
   BOTAN_UNUSED(cert, key, index, out, out_len);
105
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
106
#endif
107
}
108

109
int botan_x509_cert_get_subject_dn(
8✔
110
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
111
#if defined(BOTAN_HAS_X509_CERTIFICATES)
112
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
113
      auto subject_info = c.subject_info(key);
114
      if(index < subject_info.size()) {
115
         return write_str_output(out, out_len, c.subject_info(key).at(index));
116
      } else {
117
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
118
      }
119
   });
120
#else
121
   BOTAN_UNUSED(cert, key, index, out, out_len);
122
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
123
#endif
124
}
125

126
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
127
#if defined(BOTAN_HAS_X509_CERTIFICATES)
128
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
129
#else
130
   BOTAN_UNUSED(cert, out, out_len)
131
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
132
#endif
133
}
134

135
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
3✔
136
#if defined(BOTAN_HAS_X509_CERTIFICATES)
137
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
9✔
138
#else
139
   BOTAN_UNUSED(cert, ctx, view);
140
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
141
#endif
142
}
143

144
int botan_x509_cert_view_pem(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
×
145
#if defined(BOTAN_HAS_X509_CERTIFICATES)
146
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.PEM_encode()); });
×
147
#else
148
   BOTAN_UNUSED(cert, ctx, view);
149
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
150
#endif
151
}
152

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

168
int botan_x509_get_basic_constraints(botan_x509_cert_t cert, int* is_ca, size_t* limit) {
×
169
   if(is_ca == nullptr || limit == nullptr) {
×
170
      return BOTAN_FFI_ERROR_NULL_POINTER;
171
   }
172

173
#if defined(BOTAN_HAS_X509_CERTIFICATES)
174
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
×
175
      if(c.is_CA_cert()) {
176
         *is_ca = 1;
177
         *limit = c.path_limit();
178
      } else {
179
         *is_ca = 0;
180
         *limit = 0;
181
      }
182
      return BOTAN_FFI_SUCCESS;
183
   });
184
#else
185
   BOTAN_UNUSED(cert)
186
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
187
#endif
188
}
189

190
int botan_x509_get_key_constraints(botan_x509_cert_t cert, uint32_t* usage) {
3✔
191
   if(usage == nullptr) {
3✔
192
      return BOTAN_FFI_ERROR_NULL_POINTER;
193
   }
194

195
#if defined(BOTAN_HAS_X509_CERTIFICATES)
196
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
6✔
197
      *usage = c.constraints().value();
198
      return BOTAN_FFI_SUCCESS;
199
   });
200
#else
201
   BOTAN_UNUSED(cert)
202
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
203
#endif
204
}
205

206
int botan_x509_get_ocsp_responder(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
×
207
#if defined(BOTAN_HAS_X509_CERTIFICATES)
208
   return BOTAN_FFI_VISIT(cert,
×
209
                          [=](const auto& c) -> int { return invoke_view_callback(view, ctx, c.ocsp_responder()); });
210
#else
211
   BOTAN_UNUSED(cert, ctx, view)
212
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
213
#endif
214
}
215

216
int botan_x509_is_self_signed(botan_x509_cert_t cert, int* out) {
2✔
217
   if(out == nullptr) {
2✔
218
      return BOTAN_FFI_ERROR_NULL_POINTER;
219
   }
220

221
#if defined(BOTAN_HAS_X509_CERTIFICATES)
222
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
4✔
223
      if(c.is_self_signed()) {
224
         *out = 1;
225
      } else {
226
         *out = 0;
227
      }
228
      return BOTAN_FFI_SUCCESS;
229
   });
230
#else
231
   BOTAN_UNUSED(cert, out)
232
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
233
#endif
234
}
235

236
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
32✔
237
#if defined(BOTAN_HAS_X509_CERTIFICATES)
238
   return BOTAN_FFI_CHECKED_DELETE(cert);
32✔
239
#else
240
   BOTAN_UNUSED(cert);
241
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
242
#endif
243
}
244

245
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
246
#if defined(BOTAN_HAS_X509_CERTIFICATES)
247
   return BOTAN_FFI_VISIT(cert,
6✔
248
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
249
#else
250
   BOTAN_UNUSED(cert, out, out_len);
251
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
252
#endif
253
}
254

255
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
256
#if defined(BOTAN_HAS_X509_CERTIFICATES)
257
   return BOTAN_FFI_VISIT(cert,
4✔
258
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
259
#else
260
   BOTAN_UNUSED(cert, out, out_len);
261
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
262
#endif
263
}
264

265
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
266
#if defined(BOTAN_HAS_X509_CERTIFICATES)
267
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
268
#else
269
   BOTAN_UNUSED(cert, time_since_epoch);
270
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
271
#endif
272
}
273

274
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
275
#if defined(BOTAN_HAS_X509_CERTIFICATES)
276
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
277
#else
278
   BOTAN_UNUSED(cert, time_since_epoch);
279
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
280
#endif
281
}
282

283
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
284
#if defined(BOTAN_HAS_X509_CERTIFICATES)
285
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
6✔
286
#else
287
   BOTAN_UNUSED(cert, out, out_len);
288
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
289
#endif
290
}
291

292
int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) {
3✔
293
#if defined(BOTAN_HAS_X509_CERTIFICATES)
294
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_str_output(out, out_len, c.fingerprint(hash)); });
6✔
295
#else
296
   BOTAN_UNUSED(cert, hash, out, out_len);
297
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
298
#endif
299
}
300

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

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

319
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
320
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
321
}
322

323
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
324
#if defined(BOTAN_HAS_X509_CERTIFICATES)
325
   return BOTAN_FFI_VISIT(cert,
6✔
326
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
327
#else
328
   BOTAN_UNUSED(cert, ctx, view);
329
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
330
#endif
331
}
332

333
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
334
   if(hostname == nullptr) {
6✔
335
      return BOTAN_FFI_ERROR_NULL_POINTER;
336
   }
337

338
#if defined(BOTAN_HAS_X509_CERTIFICATES)
339
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
340
#else
341
   BOTAN_UNUSED(cert);
342
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
343
#endif
344
}
345

346
int botan_x509_cert_verify(int* result_code,
6✔
347
                           botan_x509_cert_t cert,
348
                           const botan_x509_cert_t* intermediates,
349
                           size_t intermediates_len,
350
                           const botan_x509_cert_t* trusted,
351
                           size_t trusted_len,
352
                           const char* trusted_path,
353
                           size_t required_strength,
354
                           const char* hostname_cstr,
355
                           uint64_t reference_time) {
356
   if(required_strength == 0) {
6✔
357
      required_strength = 110;
5✔
358
   }
359

360
#if defined(BOTAN_HAS_X509_CERTIFICATES)
361
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
362
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
6✔
363
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
6✔
364
      const auto validation_time = reference_time == 0
6✔
365
                                      ? std::chrono::system_clock::now()
6✔
366
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
367

368
      std::vector<Botan::X509_Certificate> end_certs;
6✔
369
      end_certs.push_back(safe_get(cert));
6✔
370
      for(size_t i = 0; i != intermediates_len; ++i) {
11✔
371
         end_certs.push_back(safe_get(intermediates[i]));
5✔
372
      }
373

374
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
6✔
375
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
6✔
376
      std::vector<Botan::Certificate_Store*> trusted_roots;
6✔
377

378
      if(trusted_path && *trusted_path) {
6✔
379
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
380
         trusted_roots.push_back(trusted_from_path.get());
×
381
      }
382

383
      if(trusted_len > 0) {
6✔
384
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
12✔
385
         for(size_t i = 0; i != trusted_len; ++i) {
12✔
386
            trusted_extra->add_certificate(safe_get(trusted[i]));
6✔
387
         }
388
         trusted_roots.push_back(trusted_extra.get());
6✔
389
      }
390

391
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
12✔
392

393
      auto validation_result =
6✔
394
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
6✔
395

396
      if(result_code) {
6✔
397
         *result_code = static_cast<int>(validation_result.result());
6✔
398
      }
399

400
      if(validation_result.successful_validation()) {
6✔
401
         return 0;
402
      } else {
403
         return 1;
3✔
404
      }
405
   });
6✔
406
#else
407
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
408
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
409
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
410
#endif
411
}
412

413
const char* botan_x509_cert_validation_status(int code) {
11✔
414
   if(code < 0) {
11✔
415
      return nullptr;
416
   }
417

418
#if defined(BOTAN_HAS_X509_CERTIFICATES)
419
   Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
420
   return Botan::to_string(sc);
11✔
421
#else
422
   return nullptr;
423
#endif
424
}
425

426
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
6✔
427
   if(crl_obj == nullptr || crl_path == nullptr) {
6✔
428
      return BOTAN_FFI_ERROR_NULL_POINTER;
429
   }
430

431
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
432

433
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
434
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
6✔
435
      return ffi_new_object(crl_obj, std::move(c));
12✔
436
   });
12✔
437

438
#else
439
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
440
#endif
441
}
442

443
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
444
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
445
      return BOTAN_FFI_ERROR_NULL_POINTER;
446
   }
447

448
#if defined(BOTAN_HAS_X509_CERTIFICATES)
449
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
450
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
451
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
452
      return ffi_new_object(crl_obj, std::move(c));
1✔
453
   });
3✔
454
#else
455
   BOTAN_UNUSED(crl_bits_len);
456
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
457
#endif
458
}
459

460
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
7✔
461
#if defined(BOTAN_HAS_X509_CERTIFICATES)
462
   return BOTAN_FFI_CHECKED_DELETE(crl);
7✔
463
#else
464
   BOTAN_UNUSED(crl);
465
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
466
#endif
467
}
468

469
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
470
#if defined(BOTAN_HAS_X509_CERTIFICATES)
471
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
472
#else
473
   BOTAN_UNUSED(cert);
474
   BOTAN_UNUSED(crl);
475
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
476
#endif
477
}
478

479
int botan_x509_cert_verify_with_crl(int* result_code,
14✔
480
                                    botan_x509_cert_t cert,
481
                                    const botan_x509_cert_t* intermediates,
482
                                    size_t intermediates_len,
483
                                    const botan_x509_cert_t* trusted,
484
                                    size_t trusted_len,
485
                                    const botan_x509_crl_t* crls,
486
                                    size_t crls_len,
487
                                    const char* trusted_path,
488
                                    size_t required_strength,
489
                                    const char* hostname_cstr,
490
                                    uint64_t reference_time) {
491
   if(required_strength == 0) {
14✔
492
      required_strength = 110;
4✔
493
   }
494

495
#if defined(BOTAN_HAS_X509_CERTIFICATES)
496
   return ffi_guard_thunk(__func__, [=]() -> int {
14✔
497
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
16✔
498
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
14✔
499
      const auto validation_time = reference_time == 0
14✔
500
                                      ? std::chrono::system_clock::now()
14✔
501
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
502

503
      std::vector<Botan::X509_Certificate> end_certs;
14✔
504
      end_certs.push_back(safe_get(cert));
14✔
505
      for(size_t i = 0; i != intermediates_len; ++i) {
32✔
506
         end_certs.push_back(safe_get(intermediates[i]));
18✔
507
      }
508

509
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
14✔
510
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
14✔
511
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
14✔
512
      std::vector<Botan::Certificate_Store*> trusted_roots;
14✔
513

514
      if(trusted_path && *trusted_path) {
14✔
515
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
516
         trusted_roots.push_back(trusted_from_path.get());
2✔
517
      }
518

519
      if(trusted_len > 0) {
14✔
520
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
22✔
521
         for(size_t i = 0; i != trusted_len; ++i) {
22✔
522
            trusted_extra->add_certificate(safe_get(trusted[i]));
11✔
523
         }
524
         trusted_roots.push_back(trusted_extra.get());
11✔
525
      }
526

527
      if(crls_len > 0) {
14✔
528
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
529
         for(size_t i = 0; i != crls_len; ++i) {
13✔
530
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
531
         }
532
         trusted_roots.push_back(trusted_crls.get());
5✔
533
      }
534

535
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
28✔
536

537
      auto validation_result =
14✔
538
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
14✔
539

540
      if(result_code) {
14✔
541
         *result_code = static_cast<int>(validation_result.result());
14✔
542
      }
543

544
      if(validation_result.successful_validation()) {
14✔
545
         return 0;
546
      } else {
547
         return 1;
8✔
548
      }
549
   });
16✔
550
#else
551
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
552
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
553
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
554
#endif
555
}
556

557
int botan_x509_cert_opts_destroy(botan_x509_cert_opts_t opts) {
8✔
558
#if defined(BOTAN_HAS_X509_CERTIFICATES)
559
   return BOTAN_FFI_CHECKED_DELETE(opts);
8✔
560
#else
561
   BOTAN_UNUSED(opts);
562
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
563
#endif
564
}
565

566
int botan_x509_ca_destroy(botan_x509_ca_t ca) {
4✔
567
#if defined(BOTAN_HAS_X509_CERTIFICATES)
568
   return BOTAN_FFI_CHECKED_DELETE(ca);
4✔
569
#else
570
   BOTAN_UNUSED(ca);
571
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
572
#endif
573
}
574

575
int botan_x509_pkcs10_req_destroy(botan_x509_pkcs10_req_t req) {
4✔
576
#if defined(BOTAN_HAS_X509_CERTIFICATES)
577
   return BOTAN_FFI_CHECKED_DELETE(req);
4✔
578
#else
579
   BOTAN_UNUSED(req);
580
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
581
#endif
582
}
583

584
int botan_x509_time_destroy(botan_x509_time_t time) {
8✔
585
#if defined(BOTAN_HAS_X509_CERTIFICATES)
586
   return BOTAN_FFI_CHECKED_DELETE(time);
8✔
587
#else
588
   BOTAN_UNUSED(time);
589
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
590
#endif
591
}
592

593
int botan_x509_create_cert_opts(botan_x509_cert_opts_t* opts_obj, const char* opts, uint32_t* expire_time) {
8✔
594
   if(opts_obj == nullptr || opts == nullptr) {
8✔
595
      return BOTAN_FFI_ERROR_NULL_POINTER;
596
   }
597

598
#if defined(BOTAN_HAS_X509_CERTIFICATES)
599
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
600
      std::unique_ptr<Botan::X509_Cert_Options> co;
8✔
601
      if(expire_time) {
8✔
602
         co = std::make_unique<Botan::X509_Cert_Options>(opts, *expire_time);
×
603
      } else {
604
         co = std::make_unique<Botan::X509_Cert_Options>(opts);
16✔
605
      }
606
      return ffi_new_object(opts_obj, std::move(co));
16✔
607
   });
16✔
608
#else
609
   BOTAN_UNUSED(expire_time);
610
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
611
#endif
612
}
613

614
#if defined(BOTAN_HAS_X509_CERTIFICATES)
615
   // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
616
   #define X509_GET_CERT_OPTS_STRING(FIELD_NAME)                                              \
617
      int botan_x509_cert_opts_##FIELD_NAME(botan_x509_cert_opts_t opts, const char* value) { \
618
         if(value == nullptr) {                                                               \
619
            return BOTAN_FFI_ERROR_NULL_POINTER;                                              \
620
         }                                                                                    \
621
         return ffi_guard_thunk(__func__, [=]() -> int {                                      \
622
            safe_get(opts).FIELD_NAME = value;                                                \
623
            return BOTAN_FFI_SUCCESS;                                                         \
624
         });                                                                                  \
625
      }
626
#else
627
   // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
628
   #define X509_GET_CERT_OPTS_STRING(FIELD_NAME)                                              \
629
      int botan_x509_cert_opts_##FIELD_NAME(botan_x509_cert_opts_t opts, const char* value) { \
630
         if(value == nullptr) {                                                               \
631
            return BOTAN_FFI_ERROR_NULL_POINTER;                                              \
632
         }                                                                                    \
633
         BOTAN_UNUSED(opts);                                                                  \
634
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;                                              \
635
      }
636
#endif
637

638
X509_GET_CERT_OPTS_STRING(common_name)
×
639
X509_GET_CERT_OPTS_STRING(country)
×
640
X509_GET_CERT_OPTS_STRING(organization)
×
641
X509_GET_CERT_OPTS_STRING(org_unit)
×
642
X509_GET_CERT_OPTS_STRING(locality)
×
643
X509_GET_CERT_OPTS_STRING(state)
×
644
X509_GET_CERT_OPTS_STRING(serial_number)
×
645
X509_GET_CERT_OPTS_STRING(email)
×
646
X509_GET_CERT_OPTS_STRING(uri)
4✔
647
X509_GET_CERT_OPTS_STRING(ip)
×
648
X509_GET_CERT_OPTS_STRING(dns)
×
649
X509_GET_CERT_OPTS_STRING(xmpp)
×
650
X509_GET_CERT_OPTS_STRING(challenge)
×
651

652
#if defined(BOTAN_HAS_X509_CERTIFICATES)
653
   // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
654
   #define X509_GET_CERT_OPTS_VEC(FIELD_NAME)                                                              \
655
      int botan_x509_cert_opts_##FIELD_NAME(botan_x509_cert_opts_t opts, const char** value, size_t cnt) { \
656
         if(value == nullptr) {                                                                            \
657
            return BOTAN_FFI_ERROR_NULL_POINTER;                                                           \
658
         }                                                                                                 \
659
         return ffi_guard_thunk(__func__, [=]() -> int {                                                   \
660
            std::vector<std::string> val;                                                                  \
661
            for(size_t i = 0; i < cnt; i++) {                                                              \
662
               if(value[i] == nullptr) {                                                                   \
663
                  return BOTAN_FFI_ERROR_NULL_POINTER;                                                     \
664
               }                                                                                           \
665
               val.push_back(value[i]);                                                                    \
666
            }                                                                                              \
667
            safe_get(opts).FIELD_NAME = val;                                                               \
668
            return BOTAN_FFI_SUCCESS;                                                                      \
669
         });                                                                                               \
670
      }
671
#else
672
   // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
673
   #define X509_GET_CERT_OPTS_VEC(FIELD_NAME)                                                              \
674
      int botan_x509_cert_opts_##FIELD_NAME(botan_x509_cert_opts_t opts, const char** value, size_t cnt) { \
675
         if(value == nullptr) {                                                                            \
676
            return BOTAN_FFI_ERROR_NULL_POINTER;                                                           \
677
         }                                                                                                 \
678
         BOTAN_UNUSED(opts, cnt);                                                                          \
679
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;                                                           \
680
      }
681
#endif
682

683
X509_GET_CERT_OPTS_VEC(more_org_units)
×
684
X509_GET_CERT_OPTS_VEC(more_dns)
8✔
685

686
int botan_x509_cert_opts_ca_key(botan_x509_cert_opts_t opts, size_t limit) {
4✔
687
#if defined(BOTAN_HAS_X509_CERTIFICATES)
688
   return BOTAN_FFI_VISIT(opts, [=](auto& o) { o.CA_key(limit); });
8✔
689
#else
690
   BOTAN_UNUSED(opts, limit);
691
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
692
#endif
693
}
694

695
int botan_x509_cert_opts_padding_scheme(botan_x509_cert_opts_t opts, const char* scheme) {
×
696
   if(scheme == nullptr) {
×
697
      return BOTAN_FFI_ERROR_NULL_POINTER;
698
   }
699

700
#if defined(BOTAN_HAS_X509_CERTIFICATES)
701
   return ffi_guard_thunk(__func__, [=]() -> int {
×
702
      safe_get(opts).set_padding_scheme(scheme);
×
703
      return BOTAN_FFI_SUCCESS;
×
704
   });
×
705
#else
706
   BOTAN_UNUSED(opts);
707
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
708
#endif
709
}
710

711
int botan_x509_cert_opts_not_before(botan_x509_cert_opts_t opts, botan_x509_time_t not_before) {
×
712
#if defined(BOTAN_HAS_X509_CERTIFICATES)
713
   return ffi_guard_thunk(__func__, [=]() -> int {
×
714
      safe_get(opts).start = safe_get(not_before);
×
715
      return BOTAN_FFI_SUCCESS;
×
716
   });
×
717
#else
718
   BOTAN_UNUSED(opts, not_before);
719
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
720
#endif
721
}
722

723
int botan_x509_cert_opts_not_after(botan_x509_cert_opts_t opts, botan_x509_time_t not_after) {
×
724
#if defined(BOTAN_HAS_X509_CERTIFICATES)
725
   return ffi_guard_thunk(__func__, [=]() -> int {
×
726
      safe_get(opts).end = safe_get(not_after);
×
727
      return BOTAN_FFI_SUCCESS;
×
728
   });
×
729
#else
730
   BOTAN_UNUSED(opts.not_after);
731
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
732
#endif
733
}
734

735
int botan_x509_cert_opts_constraints(botan_x509_cert_opts_t opts, uint32_t usage) {
2✔
736
#if defined(BOTAN_HAS_X509_CERTIFICATES)
737
   return BOTAN_FFI_VISIT(opts, [=](auto& o) { o.add_constraints(Botan::Key_Constraints(usage)); });
4✔
738
#else
739
   BOTAN_UNUSED(opts, usage);
740
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
741
#endif
742
}
743

744
int botan_x509_cert_opts_ex_constraint(botan_x509_cert_opts_t opts, botan_asn1_oid_t oid) {
×
745
#if defined(BOTAN_HAS_X509_CERTIFICATES)
746
   return ffi_guard_thunk(__func__, [=]() -> int {
×
747
      safe_get(opts).add_ex_constraint(safe_get(oid));
×
748
      return BOTAN_FFI_SUCCESS;
×
749
   });
×
750
#else
751
   BOTAN_UNUSED(opts, oid);
752
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
753
#endif
754
}
755

756
int botan_x509_create_time(botan_x509_time_t* time_obj, uint64_t time_since_epoch) {
8✔
757
   if(time_obj == nullptr) {
8✔
758
      return BOTAN_FFI_ERROR_NULL_POINTER;
759
   }
760
#if defined(BOTAN_HAS_X509_CERTIFICATES)
761
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
762
      auto tp = std::chrono::system_clock::time_point(std::chrono::seconds(time_since_epoch));
8✔
763
      auto time = std::make_unique<Botan::X509_Time>(tp);
8✔
764
      return ffi_new_object(time_obj, std::move(time));
8✔
765
   });
16✔
766
#else
767
   BOTAN_UNUSED(time_since_epoch);
768
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
769
#endif
770
}
771

772
int botan_x509_cert_opts_ext_ip_addr_blocks(botan_x509_cert_opts_t opts,
4✔
773
                                            botan_x509_ext_ip_addr_blocks_t ip_addr_blocks) {
774
#if defined(BOTAN_HAS_X509_CERTIFICATES)
775
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
776
      safe_get(opts).extensions.add(safe_get(ip_addr_blocks).copy());
4✔
777
      return BOTAN_FFI_SUCCESS;
4✔
778
   });
4✔
779
#else
780
   BOTAN_UNUSED(opts, as_blocks);
781
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
782
#endif
783
}
784

785
int botan_x509_cert_opts_ext_as_blocks(botan_x509_cert_opts_t opts, botan_x509_ext_as_blocks_t as_blocks) {
4✔
786
#if defined(BOTAN_HAS_X509_CERTIFICATES)
787
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
788
      safe_get(opts).extensions.add(safe_get(as_blocks).copy());
4✔
789
      return BOTAN_FFI_SUCCESS;
4✔
790
   });
4✔
791
#else
792
   BOTAN_UNUSED(opts, as_blocks);
793
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
794
#endif
795
}
796

797
int botan_x509_create_self_signed_cert(botan_x509_cert_t* cert_obj,
4✔
798
                                       botan_privkey_t key,
799
                                       botan_x509_cert_opts_t opts,
800
                                       const char* hash_fn,
801
                                       const char* sig_padding,
802
                                       botan_rng_t rng) {
803
   if(cert_obj == nullptr || hash_fn == nullptr || sig_padding == nullptr) {
4✔
804
      return BOTAN_FFI_ERROR_NULL_POINTER;
805
   }
806
#if defined(BOTAN_HAS_X509_CERTIFICATES)
807
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
808
      auto ca_cert = std::make_unique<Botan::X509_Certificate>(
4✔
809
         Botan::X509::create_self_signed_cert(safe_get(opts), safe_get(key), hash_fn, safe_get(rng)));
4✔
810
      return ffi_new_object(cert_obj, std::move(ca_cert));
4✔
811
   });
8✔
812
#else
813
   BOTAN_UNUSED(key, opts, rng);
814
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
815
#endif
816
}
817

818
int botan_x509_create_ca(botan_x509_ca_t* ca_obj,
4✔
819
                         botan_x509_cert_t ca_cert,
820
                         botan_privkey_t key,
821
                         const char* hash_fn,
822
                         const char* sig_padding,
823
                         botan_rng_t rng) {
824
   if(ca_obj == nullptr || hash_fn == nullptr || sig_padding == nullptr) {
4✔
825
      return BOTAN_FFI_ERROR_NULL_POINTER;
826
   }
827
#if defined(BOTAN_HAS_X509_CERTIFICATES)
828
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
829
      auto ca = std::make_unique<Botan::X509_CA>(safe_get(ca_cert), safe_get(key), hash_fn, sig_padding, safe_get(rng));
4✔
830
      return ffi_new_object(ca_obj, std::move(ca));
8✔
831
   });
8✔
832
#else
833
   BOTAN_UNUSED(ca_cert, key, rng);
834
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
835
#endif
836
}
837

838
int botan_x509_create_pkcs10_req(botan_x509_pkcs10_req_t* req_obj,
4✔
839
                                 botan_x509_cert_opts_t opts,
840
                                 botan_privkey_t key,
841
                                 const char* hash_fn,
842
                                 botan_rng_t rng) {
843
   if(req_obj == nullptr || hash_fn == nullptr) {
4✔
844
      return BOTAN_FFI_ERROR_NULL_POINTER;
845
   }
846
#if defined(BOTAN_HAS_X509_CERTIFICATES)
847
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
848
      auto req = std::make_unique<Botan::PKCS10_Request>(
4✔
849
         Botan::X509::create_cert_req(safe_get(opts), safe_get(key), hash_fn, safe_get(rng)));
4✔
850
      return ffi_new_object(req_obj, std::move(req));
8✔
851
   });
8✔
852
#else
853
   BOTAN_UNUSED(opts, key, rng);
854
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
855
#endif
856
}
857

858
int botan_x509_sign_req(botan_x509_cert_t* cert_obj,
4✔
859
                        botan_x509_ca_t ca,
860
                        botan_x509_pkcs10_req_t req,
861
                        botan_rng_t rng,
862
                        botan_x509_time_t not_before,
863
                        botan_x509_time_t not_after) {
864
   if(cert_obj == nullptr) {
4✔
865
      return BOTAN_FFI_ERROR_NULL_POINTER;
866
   }
867
#if defined(BOTAN_HAS_X509_CERTIFICATES)
868
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
869
      auto cert = std::make_unique<Botan::X509_Certificate>(safe_get<Botan::X509_CA>(ca).sign_request(
16✔
870
         safe_get(req), safe_get(rng), safe_get(not_before), safe_get(not_after)));
12✔
871
      return ffi_new_object(cert_obj, std::move(cert));
4✔
872
   });
8✔
873
#else
874
   BOTAN_UNUSED(ca, req, rng, not_before, not_after);
875
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
876
#endif
877
}
878
}
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