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

randombit / botan / 15276869812

27 May 2025 01:39PM UTC coverage: 90.953% (-0.02%) from 90.977%
15276869812

Pull #4877

github

web-flow
Merge 28ebe8b3d into fa28fc6f4
Pull Request #4877: Add FFI for X.509 creation

98141 of 107903 relevant lines covered (90.95%)

12735553.39 hits per line

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

80.22
/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 <memory>
16

17
extern "C" {
18

19
using namespace Botan_FFI;
20

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

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

28
   return ffi_guard_thunk(__func__, [=]() -> int {
23✔
29
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
23✔
30
      *cert_obj = new botan_x509_cert_struct(std::move(c));
23✔
31
      return BOTAN_FFI_SUCCESS;
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) {
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
      *cert_obj = new botan_x509_cert_struct(std::move(c));
1✔
49
      return BOTAN_FFI_SUCCESS;
1✔
50
   });
2✔
51

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

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

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

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

81
   *key = nullptr;
2✔
82

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

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

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

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

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

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

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

171
int botan_x509_get_basic_constraints(botan_x509_cert_t cert, int* is_ca, size_t* limit) {
×
172
   if(!is_ca || !limit) {
×
173
      return BOTAN_FFI_ERROR_NULL_POINTER;
174
   }
175

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

193
int botan_x509_get_key_constraints(botan_x509_cert_t cert, uint32_t* usage) {
3✔
194
   if(!usage) {
3✔
195
      return BOTAN_FFI_ERROR_NULL_POINTER;
196
   }
197

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

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

219
int botan_x509_is_self_signed(botan_x509_cert_t cert, int* out) {
2✔
220
   if(!out) {
2✔
221
      return BOTAN_FFI_ERROR_NULL_POINTER;
222
   }
223

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

376
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
5✔
377
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
5✔
378
      std::vector<Botan::Certificate_Store*> trusted_roots;
5✔
379

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

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

393
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
10✔
394

395
      auto validation_result =
5✔
396
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
5✔
397

398
      if(result_code) {
5✔
399
         *result_code = static_cast<int>(validation_result.result());
5✔
400
      }
401

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

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

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

428
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
6✔
429
   if(!crl_obj || !crl_path) {
6✔
430
      return BOTAN_FFI_ERROR_NULL_POINTER;
431
   }
432

433
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
434

435
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
436
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
6✔
437
      *crl_obj = new botan_x509_crl_struct(std::move(c));
6✔
438
      return BOTAN_FFI_SUCCESS;
6✔
439
   });
12✔
440

441
#else
442
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
443
#endif
444
}
445

446
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
447
   if(!crl_obj || !crl_bits) {
1✔
448
      return BOTAN_FFI_ERROR_NULL_POINTER;
449
   }
450

451
#if defined(BOTAN_HAS_X509_CERTIFICATES)
452
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
453
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
454
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
455
      *crl_obj = new botan_x509_crl_struct(std::move(c));
1✔
456
      return BOTAN_FFI_SUCCESS;
2✔
457
   });
3✔
458
#else
459
   BOTAN_UNUSED(crl_bits_len);
460
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
461
#endif
462
}
463

464
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
7✔
465
#if defined(BOTAN_HAS_X509_CERTIFICATES)
466
   return BOTAN_FFI_CHECKED_DELETE(crl);
7✔
467
#else
468
   BOTAN_UNUSED(crl);
469
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
470
#endif
471
}
472

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

483
int botan_x509_cert_verify_with_crl(int* result_code,
13✔
484
                                    botan_x509_cert_t cert,
485
                                    const botan_x509_cert_t* intermediates,
486
                                    size_t intermediates_len,
487
                                    const botan_x509_cert_t* trusted,
488
                                    size_t trusted_len,
489
                                    const botan_x509_crl_t* crls,
490
                                    size_t crls_len,
491
                                    const char* trusted_path,
492
                                    size_t required_strength,
493
                                    const char* hostname_cstr,
494
                                    uint64_t reference_time) {
495
   if(required_strength == 0) {
13✔
496
      required_strength = 110;
3✔
497
   }
498

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

507
      std::vector<Botan::X509_Certificate> end_certs;
13✔
508
      end_certs.push_back(safe_get(cert));
13✔
509
      for(size_t i = 0; i != intermediates_len; ++i) {
31✔
510
         end_certs.push_back(safe_get(intermediates[i]));
18✔
511
      }
512

513
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
13✔
514
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
13✔
515
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
13✔
516
      std::vector<Botan::Certificate_Store*> trusted_roots;
13✔
517

518
      if(trusted_path && *trusted_path) {
13✔
519
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
520
         trusted_roots.push_back(trusted_from_path.get());
2✔
521
      }
522

523
      if(trusted_len > 0) {
13✔
524
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
20✔
525
         for(size_t i = 0; i != trusted_len; ++i) {
20✔
526
            trusted_extra->add_certificate(safe_get(trusted[i]));
10✔
527
         }
528
         trusted_roots.push_back(trusted_extra.get());
10✔
529
      }
530

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

539
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
26✔
540

541
      auto validation_result =
13✔
542
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
13✔
543

544
      if(result_code) {
13✔
545
         *result_code = static_cast<int>(validation_result.result());
13✔
546
      }
547

548
      if(validation_result.successful_validation()) {
13✔
549
         return 0;
550
      } else {
551
         return 1;
8✔
552
      }
553
   });
15✔
554
#else
555
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
556
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
557
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
558
#endif
559
}
560

561
int botan_x509_cert_opts_destroy(botan_x509_cert_opts_t opts) {
4✔
562
#if defined(BOTAN_HAS_X509_CERTIFICATES)
563
   return BOTAN_FFI_CHECKED_DELETE(opts);
4✔
564
#else
565
   BOTAN_UNUSED(opts);
566
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
567
#endif
568
}
569

570
int botan_x509_ca_destroy(botan_x509_ca_t ca) {
2✔
571
#if defined(BOTAN_HAS_X509_CERTIFICATES)
572
   return BOTAN_FFI_CHECKED_DELETE(ca);
2✔
573
#else
574
   BOTAN_UNUSED(ca);
575
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
576
#endif
577
}
578

579
int botan_x509_pkcs10_req_destroy(botan_x509_pkcs10_req_t req) {
2✔
580
#if defined(BOTAN_HAS_X509_CERTIFICATES)
581
   return BOTAN_FFI_CHECKED_DELETE(req);
2✔
582
#else
583
   BOTAN_UNUSED(req);
584
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
585
#endif
586
}
587

588
int botan_x509_time_destroy(botan_x509_time_t time) {
4✔
589
#if defined(BOTAN_HAS_X509_CERTIFICATES)
590
   return BOTAN_FFI_CHECKED_DELETE(time);
4✔
591
#else
592
   BOTAN_UNUSED(time);
593
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
594
#endif
595
}
596

597
int botan_x509_create_cert_opts(botan_x509_cert_opts_t* opts_obj, const char* opts, uint32_t* expire_time) {
4✔
598
   if(!opts_obj || !opts) {
4✔
599
      return BOTAN_FFI_ERROR_NULL_POINTER;
600
   }
601

602
#if defined(BOTAN_HAS_X509_CERTIFICATES)
603
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
604
      std::unique_ptr<Botan::X509_Cert_Options> co;
4✔
605
      if(expire_time) {
4✔
606
         co = std::make_unique<Botan::X509_Cert_Options>(opts, *expire_time);
×
607
      } else {
608
         co = std::make_unique<Botan::X509_Cert_Options>(opts);
8✔
609
      }
610

611
      *opts_obj = new botan_x509_cert_opts_struct(std::move(co));
4✔
612
      return BOTAN_FFI_SUCCESS;
4✔
613
   });
8✔
614
#else
615
   BOTAN_UNUSED(expire_time);
616
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
617
#endif
618
}
619

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

644
X509_GET_CERT_OPTS_STRING(common_name)
×
645
X509_GET_CERT_OPTS_STRING(country)
×
646
X509_GET_CERT_OPTS_STRING(organization)
×
647
X509_GET_CERT_OPTS_STRING(org_unit)
×
648
X509_GET_CERT_OPTS_STRING(locality)
×
649
X509_GET_CERT_OPTS_STRING(state)
×
650
X509_GET_CERT_OPTS_STRING(serial_number)
×
651
X509_GET_CERT_OPTS_STRING(email)
×
652
X509_GET_CERT_OPTS_STRING(uri)
4✔
653
X509_GET_CERT_OPTS_STRING(ip)
×
654
X509_GET_CERT_OPTS_STRING(dns)
×
655
X509_GET_CERT_OPTS_STRING(xmpp)
×
656
X509_GET_CERT_OPTS_STRING(challenge)
×
657

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

689
X509_GET_CERT_OPTS_VEC(more_org_units)
×
690
X509_GET_CERT_OPTS_VEC(more_dns)
8✔
691

692
int botan_x509_cert_opts_ca_key(botan_x509_cert_opts_t opts, size_t limit) {
2✔
693
#if defined(BOTAN_HAS_X509_CERTIFICATES)
694
   return BOTAN_FFI_VISIT(opts, [=](auto& o) { o.CA_key(limit); });
4✔
695
#else
696
   BOTAN_UNUSED(opts, limit);
697
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
698
#endif
699
}
700

701
int botan_x509_cert_opts_set_padding_scheme(botan_x509_cert_opts_t opts, const char* scheme) {
×
702
   if(!scheme) {
×
703
      return BOTAN_FFI_ERROR_NULL_POINTER;
704
   }
705

706
#if defined(BOTAN_HAS_X509_CERTIFICATES)
707
   return ffi_guard_thunk(__func__, [=]() -> int {
×
708
      safe_get(opts).set_padding_scheme(scheme);
×
709
      return BOTAN_FFI_SUCCESS;
×
710
   });
×
711
#else
712
   BOTAN_UNUSED(opts);
713
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
714
#endif
715
}
716

717
int botan_x509_cert_opts_not_before(botan_x509_cert_opts_t opts, botan_x509_time_t not_before) {
×
718
#if defined(BOTAN_HAS_X509_CERTIFICATES)
719
   return ffi_guard_thunk(__func__, [=]() -> int {
×
720
      safe_get(opts).start = safe_get(not_before);
×
721
      return BOTAN_FFI_SUCCESS;
×
722
   });
×
723
#else
724
   BOTAN_UNUSED(opts, not_before);
725
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
726
#endif
727
}
728

729
int botan_x509_cert_opts_not_after(botan_x509_cert_opts_t opts, botan_x509_time_t not_after) {
×
730
#if defined(BOTAN_HAS_X509_CERTIFICATES)
731
   return ffi_guard_thunk(__func__, [=]() -> int {
×
732
      safe_get(opts).end = safe_get(not_after);
×
733
      return BOTAN_FFI_SUCCESS;
×
734
   });
×
735
#else
736
   BOTAN_UNUSED(opts.not_after);
737
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
738
#endif
739
}
740

741
int botan_x509_cert_opts_add_constraints(botan_x509_cert_opts_t opts, uint32_t usage) {
1✔
742
#if defined(BOTAN_HAS_X509_CERTIFICATES)
743
   return BOTAN_FFI_VISIT(opts, [=](auto& o) { o.add_constraints(Botan::Key_Constraints(usage)); });
2✔
744
#else
745
   BOTAN_UNUSED(opts, usage);
746
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
747
#endif
748
}
749

750
int botan_x509_cert_opts_add_ex_constraint(botan_x509_cert_opts_t opts, botan_asn1_oid_t oid) {
×
751
#if defined(BOTAN_HAS_X509_CERTIFICATES)
752
   return ffi_guard_thunk(__func__, [=]() -> int {
×
753
      safe_get(opts).add_ex_constraint(safe_get(oid));
×
754
      return BOTAN_FFI_SUCCESS;
×
755
   });
×
756
#else
757
   BOTAN_UNUSED(opts, oid);
758
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
759
#endif
760
}
761

762
int botan_x509_create_self_signed_cert(botan_x509_cert_t* cert_obj,
2✔
763
                                       botan_privkey_t key,
764
                                       botan_x509_cert_opts_t opts,
765
                                       const char* hash_fn,
766
                                       const char* sig_padding,
767
                                       botan_rng_t rng) {
768
   if(!cert_obj || !hash_fn || !sig_padding) {
2✔
769
      return BOTAN_FFI_ERROR_NULL_POINTER;
770
   }
771
#if defined(BOTAN_HAS_X509_CERTIFICATES)
772
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
773
      auto ca_cert = std::make_unique<Botan::X509_Certificate>(
2✔
774
         Botan::X509::create_self_signed_cert(safe_get(opts), safe_get(key), hash_fn, safe_get(rng)));
2✔
775
      *cert_obj = new botan_x509_cert_struct(std::move(ca_cert));
2✔
776
      return BOTAN_FFI_SUCCESS;
2✔
777
   });
4✔
778
#else
779
   BOTAN_UNUSED(key, opts, rng);
780
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
781
#endif
782
}
783

784
int botan_x509_create_ca(botan_x509_ca_t* ca_obj,
2✔
785
                         botan_x509_cert_t ca_cert,
786
                         botan_privkey_t key,
787
                         const char* hash_fn,
788
                         const char* sig_padding,
789
                         botan_rng_t rng) {
790
   if(!ca_obj || !hash_fn || !sig_padding) {
2✔
791
      return BOTAN_FFI_ERROR_NULL_POINTER;
792
   }
793
#if defined(BOTAN_HAS_X509_CERTIFICATES)
794
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
795
      auto ca = std::make_unique<Botan::X509_CA>(safe_get(ca_cert), safe_get(key), hash_fn, sig_padding, safe_get(rng));
2✔
796
      *ca_obj = new botan_x509_ca_struct(std::move(ca));
2✔
797
      return BOTAN_FFI_SUCCESS;
2✔
798
   });
4✔
799
#else
800
   BOTAN_UNUSED(ca_cert, key, rng);
801
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
802
#endif
803
}
804

805
int botan_x509_create_pkcs10_req(botan_x509_pkcs10_req_t* req_obj,
2✔
806
                                 botan_x509_cert_opts_t opts,
807
                                 botan_privkey_t key,
808
                                 const char* hash_fn,
809
                                 botan_rng_t rng) {
810
   if(!req_obj || !hash_fn) {
2✔
811
      return BOTAN_FFI_ERROR_NULL_POINTER;
812
   }
813
#if defined(BOTAN_HAS_X509_CERTIFICATES)
814
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
815
      auto req = std::make_unique<Botan::PKCS10_Request>(
2✔
816
         Botan::X509::create_cert_req(safe_get(opts), safe_get(key), hash_fn, safe_get(rng)));
2✔
817
      *req_obj = new botan_x509_pkcs10_req_struct(std::move(req));
2✔
818
      return BOTAN_FFI_SUCCESS;
2✔
819
   });
4✔
820
#else
821
   BOTAN_UNUSED(opts, key, rng);
822
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
823
#endif
824
}
825

826
int botan_x509_sign_req(botan_x509_cert_t* cert_obj,
2✔
827
                        botan_x509_ca_t ca,
828
                        botan_x509_pkcs10_req_t req,
829
                        botan_rng_t rng,
830
                        botan_x509_time_t not_before,
831
                        botan_x509_time_t not_after) {
832
   if(!cert_obj) {
2✔
833
      return BOTAN_FFI_ERROR_NULL_POINTER;
834
   }
835
#if defined(BOTAN_HAS_X509_CERTIFICATES)
836
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
837
      auto cert = std::make_unique<Botan::X509_Certificate>(safe_get<Botan::X509_CA>(ca).sign_request(
8✔
838
         safe_get(req), safe_get(rng), safe_get(not_before), safe_get(not_after)));
6✔
839
      *cert_obj = new botan_x509_cert_struct(std::move(cert));
2✔
840
      return BOTAN_FFI_SUCCESS;
2✔
841
   });
4✔
842
#else
843
   BOTAN_UNUSED(ca, req, rng, not_before, not_after);
844
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
845
#endif
846
}
847

848
int botan_x509_create_time(botan_x509_time_t* time_obj, uint64_t time_since_epoch) {
4✔
849
   if(!time_obj) {
4✔
850
      return BOTAN_FFI_ERROR_NULL_POINTER;
851
   }
852
#if defined(BOTAN_HAS_X509_CERTIFICATES)
853
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
854
      auto tp = std::chrono::system_clock::time_point(std::chrono::seconds(time_since_epoch));
4✔
855
      auto time = std::make_unique<Botan::X509_Time>(tp);
4✔
856
      *time_obj = new botan_x509_time_struct(std::move(time));
4✔
857
      return BOTAN_FFI_SUCCESS;
4✔
858
   });
8✔
859
#else
860
   BOTAN_UNUSED(time_since_epoch);
861
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
862
#endif
863
}
864
}
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