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

randombit / botan / 16263659650

14 Jul 2025 09:51AM UTC coverage: 90.624% (+0.001%) from 90.623%
16263659650

Pull #4877

github

web-flow
Merge b80c6178f into b71fdb4a3
Pull Request #4877: Add FFI for X.509 creation

100124 of 110483 relevant lines covered (90.62%)

12265790.22 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
   });
229
#else
230
   BOTAN_UNUSED(cert, out)
231
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
232
#endif
233
}
234

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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