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

randombit / botan / 16305137006

15 Jul 2025 09:52PM UTC coverage: 90.627% (+0.004%) from 90.623%
16305137006

Pull #4877

github

web-flow
Merge 94b4cba0d into 6eea3cee4
Pull Request #4877: Add FFI for X.509 creation

100130 of 110486 relevant lines covered (90.63%)

12324675.48 hits per line

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

78.99
/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
namespace {
19
Botan::X509_Time time_from_timestamp(uint64_t time_since_epoch) {
8✔
20
   auto tp = std::chrono::system_clock::time_point(std::chrono::seconds(time_since_epoch));
8✔
21
   return Botan::X509_Time(tp);
4✔
22
}
23
}  // namespace
24

25
extern "C" {
26

27
using namespace Botan_FFI;
28

29
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
23✔
30
   if(cert_obj == nullptr || cert_path == nullptr) {
23✔
31
      return BOTAN_FFI_ERROR_NULL_POINTER;
32
   }
33

34
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
35

36
   return ffi_guard_thunk(__func__, [=]() -> int {
23✔
37
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
23✔
38
      return ffi_new_object(cert_obj, std::move(c));
23✔
39
   });
46✔
40

41
#else
42
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
43
#endif
44
}
45

46
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
47
   if(cert_obj == nullptr) {
1✔
48
      return BOTAN_FFI_ERROR_NULL_POINTER;
49
   }
50

51
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
52

53
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
54
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
55
      return ffi_new_object(cert_obj, std::move(c));
1✔
56
   });
2✔
57

58
#else
59
   BOTAN_UNUSED(cert);
60
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
61
#endif
62
}
63

64
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
×
65
   if(cert_obj == nullptr || cert_bits == nullptr) {
×
66
      return BOTAN_FFI_ERROR_NULL_POINTER;
67
   }
68

69
#if defined(BOTAN_HAS_X509_CERTIFICATES)
70
   return ffi_guard_thunk(__func__, [=]() -> int {
×
71
      Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
×
72
      auto c = std::make_unique<Botan::X509_Certificate>(bits);
×
73
      return ffi_new_object(cert_obj, std::move(c));
×
74
   });
×
75
#else
76
   BOTAN_UNUSED(cert_bits_len);
77
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
78
#endif
79
}
80

81
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
82
   if(key == nullptr) {
2✔
83
      return BOTAN_FFI_ERROR_NULL_POINTER;
84
   }
85

86
   *key = nullptr;
2✔
87

88
#if defined(BOTAN_HAS_X509_CERTIFICATES)
89
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
90
      auto public_key = safe_get(cert).subject_public_key();
2✔
91
      return ffi_new_object(key, std::move(public_key));
2✔
92
   });
4✔
93
#else
94
   BOTAN_UNUSED(cert);
95
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
96
#endif
97
}
98

99
int botan_x509_cert_get_issuer_dn(
8✔
100
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
101
#if defined(BOTAN_HAS_X509_CERTIFICATES)
102
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
103
      auto issuer_info = c.issuer_info(key);
104
      if(index < issuer_info.size()) {
105
         // TODO(Botan4) change the type of out and remove this cast
106
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.issuer_info(key).at(index));
107
      } else {
108
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
109
      }
110
   });
111
#else
112
   BOTAN_UNUSED(cert, key, index, out, out_len);
113
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
114
#endif
115
}
116

117
int botan_x509_cert_get_subject_dn(
8✔
118
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
119
#if defined(BOTAN_HAS_X509_CERTIFICATES)
120
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
121
      auto subject_info = c.subject_info(key);
122
      if(index < subject_info.size()) {
123
         // TODO(Botan4) change the type of out and remove this cast
124
         return write_str_output(reinterpret_cast<char*>(out), out_len, c.subject_info(key).at(index));
125
      } else {
126
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
127
      }
128
   });
129
#else
130
   BOTAN_UNUSED(cert, key, index, out, out_len);
131
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
132
#endif
133
}
134

135
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
136
#if defined(BOTAN_HAS_X509_CERTIFICATES)
137
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
138
#else
139
   BOTAN_UNUSED(cert, out, out_len)
140
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
141
#endif
142
}
143

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

153
int botan_x509_cert_view_pem(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
×
154
#if defined(BOTAN_HAS_X509_CERTIFICATES)
155
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.PEM_encode()); });
×
156
#else
157
   BOTAN_UNUSED(cert, ctx, view);
158
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
159
#endif
160
}
161

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

177
int botan_x509_get_basic_constraints(botan_x509_cert_t cert, int* is_ca, size_t* limit) {
×
178
   if(is_ca == nullptr || limit == nullptr) {
×
179
      return BOTAN_FFI_ERROR_NULL_POINTER;
180
   }
181

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

199
int botan_x509_get_key_constraints(botan_x509_cert_t cert, uint32_t* usage) {
3✔
200
   if(usage == nullptr) {
3✔
201
      return BOTAN_FFI_ERROR_NULL_POINTER;
202
   }
203

204
#if defined(BOTAN_HAS_X509_CERTIFICATES)
205
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
6✔
206
      *usage = c.constraints().value();
207
      return BOTAN_FFI_SUCCESS;
208
   });
209
#else
210
   BOTAN_UNUSED(cert)
211
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
212
#endif
213
}
214

215
int botan_x509_get_ocsp_responder(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
×
216
#if defined(BOTAN_HAS_X509_CERTIFICATES)
217
   return BOTAN_FFI_VISIT(cert,
×
218
                          [=](const auto& c) -> int { return invoke_view_callback(view, ctx, c.ocsp_responder()); });
219
#else
220
   BOTAN_UNUSED(cert, ctx, view)
221
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
222
#endif
223
}
224

225
int botan_x509_is_self_signed(botan_x509_cert_t cert, int* out) {
2✔
226
   if(out == nullptr) {
2✔
227
      return BOTAN_FFI_ERROR_NULL_POINTER;
228
   }
229

230
#if defined(BOTAN_HAS_X509_CERTIFICATES)
231
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
4✔
232
      if(c.is_self_signed()) {
233
         *out = 1;
234
      } else {
235
         *out = 0;
236
      }
237
      return BOTAN_FFI_SUCCESS;
238
   });
239
#else
240
   BOTAN_UNUSED(cert, out)
241
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
242
#endif
243
}
244

245
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
32✔
246
#if defined(BOTAN_HAS_X509_CERTIFICATES)
247
   return BOTAN_FFI_CHECKED_DELETE(cert);
32✔
248
#else
249
   BOTAN_UNUSED(cert);
250
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
251
#endif
252
}
253

254
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
255
#if defined(BOTAN_HAS_X509_CERTIFICATES)
256
   return BOTAN_FFI_VISIT(cert,
6✔
257
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().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_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
265
#if defined(BOTAN_HAS_X509_CERTIFICATES)
266
   return BOTAN_FFI_VISIT(cert,
4✔
267
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
268
#else
269
   BOTAN_UNUSED(cert, out, out_len);
270
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
271
#endif
272
}
273

274
int botan_x509_cert_not_before(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_before().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_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
284
#if defined(BOTAN_HAS_X509_CERTIFICATES)
285
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
286
#else
287
   BOTAN_UNUSED(cert, time_since_epoch);
288
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
289
#endif
290
}
291

292
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, 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_vec_output(out, out_len, c.serial_number()); });
6✔
295
#else
296
   BOTAN_UNUSED(cert, out, out_len);
297
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
298
#endif
299
}
300

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

305
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) {
6✔
306
      return write_str_output(reinterpret_cast<char*>(out), out_len, c.fingerprint(hash));
307
   });
308
#else
309
   BOTAN_UNUSED(cert, hash, out, out_len);
310
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
311
#endif
312
}
313

314
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
315
#if defined(BOTAN_HAS_X509_CERTIFICATES)
316
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
317
#else
318
   BOTAN_UNUSED(cert, out, out_len);
319
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
320
#endif
321
}
322

323
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
324
#if defined(BOTAN_HAS_X509_CERTIFICATES)
325
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
326
#else
327
   BOTAN_UNUSED(cert, out, out_len);
328
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
329
#endif
330
}
331

332
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
333
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
334
}
335

336
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
337
#if defined(BOTAN_HAS_X509_CERTIFICATES)
338
   return BOTAN_FFI_VISIT(cert,
6✔
339
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
340
#else
341
   BOTAN_UNUSED(cert, ctx, view);
342
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
343
#endif
344
}
345

346
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
347
   if(hostname == nullptr) {
6✔
348
      return BOTAN_FFI_ERROR_NULL_POINTER;
349
   }
350

351
#if defined(BOTAN_HAS_X509_CERTIFICATES)
352
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
353
#else
354
   BOTAN_UNUSED(cert);
355
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
356
#endif
357
}
358

359
int botan_x509_cert_verify(int* result_code,
6✔
360
                           botan_x509_cert_t cert,
361
                           const botan_x509_cert_t* intermediates,
362
                           size_t intermediates_len,
363
                           const botan_x509_cert_t* trusted,
364
                           size_t trusted_len,
365
                           const char* trusted_path,
366
                           size_t required_strength,
367
                           const char* hostname_cstr,
368
                           uint64_t reference_time) {
369
   if(required_strength == 0) {
6✔
370
      required_strength = 110;
5✔
371
   }
372

373
#if defined(BOTAN_HAS_X509_CERTIFICATES)
374
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
375
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
6✔
376
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
6✔
377
      const auto validation_time = reference_time == 0
6✔
378
                                      ? std::chrono::system_clock::now()
6✔
379
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
380

381
      std::vector<Botan::X509_Certificate> end_certs;
6✔
382
      end_certs.push_back(safe_get(cert));
6✔
383
      for(size_t i = 0; i != intermediates_len; ++i) {
11✔
384
         end_certs.push_back(safe_get(intermediates[i]));
5✔
385
      }
386

387
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
6✔
388
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
6✔
389
      std::vector<Botan::Certificate_Store*> trusted_roots;
6✔
390

391
      if(trusted_path && *trusted_path) {
6✔
392
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
393
         trusted_roots.push_back(trusted_from_path.get());
×
394
      }
395

396
      if(trusted_len > 0) {
6✔
397
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
12✔
398
         for(size_t i = 0; i != trusted_len; ++i) {
12✔
399
            trusted_extra->add_certificate(safe_get(trusted[i]));
6✔
400
         }
401
         trusted_roots.push_back(trusted_extra.get());
6✔
402
      }
403

404
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
12✔
405

406
      auto validation_result =
6✔
407
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
6✔
408

409
      if(result_code) {
6✔
410
         *result_code = static_cast<int>(validation_result.result());
6✔
411
      }
412

413
      if(validation_result.successful_validation()) {
6✔
414
         return 0;
415
      } else {
416
         return 1;
3✔
417
      }
418
   });
6✔
419
#else
420
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
421
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
422
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
423
#endif
424
}
425

426
const char* botan_x509_cert_validation_status(int code) {
11✔
427
   if(code < 0) {
11✔
428
      return nullptr;
429
   }
430

431
#if defined(BOTAN_HAS_X509_CERTIFICATES)
432
   Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
433
   return Botan::to_string(sc);
11✔
434
#else
435
   return nullptr;
436
#endif
437
}
438

439
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
6✔
440
   if(crl_obj == nullptr || crl_path == nullptr) {
6✔
441
      return BOTAN_FFI_ERROR_NULL_POINTER;
442
   }
443

444
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
445

446
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
447
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
6✔
448
      return ffi_new_object(crl_obj, std::move(c));
12✔
449
   });
12✔
450

451
#else
452
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
453
#endif
454
}
455

456
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
457
   if(crl_obj == nullptr || crl_bits == nullptr) {
1✔
458
      return BOTAN_FFI_ERROR_NULL_POINTER;
459
   }
460

461
#if defined(BOTAN_HAS_X509_CERTIFICATES)
462
   return ffi_guard_thunk(__func__, [=]() -> int {
1✔
463
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
464
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
465
      return ffi_new_object(crl_obj, std::move(c));
1✔
466
   });
3✔
467
#else
468
   BOTAN_UNUSED(crl_bits_len);
469
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
470
#endif
471
}
472

473
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
7✔
474
#if defined(BOTAN_HAS_X509_CERTIFICATES)
475
   return BOTAN_FFI_CHECKED_DELETE(crl);
7✔
476
#else
477
   BOTAN_UNUSED(crl);
478
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
479
#endif
480
}
481

482
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
483
#if defined(BOTAN_HAS_X509_CERTIFICATES)
484
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
485
#else
486
   BOTAN_UNUSED(cert);
487
   BOTAN_UNUSED(crl);
488
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
489
#endif
490
}
491

492
int botan_x509_cert_verify_with_crl(int* result_code,
14✔
493
                                    botan_x509_cert_t cert,
494
                                    const botan_x509_cert_t* intermediates,
495
                                    size_t intermediates_len,
496
                                    const botan_x509_cert_t* trusted,
497
                                    size_t trusted_len,
498
                                    const botan_x509_crl_t* crls,
499
                                    size_t crls_len,
500
                                    const char* trusted_path,
501
                                    size_t required_strength,
502
                                    const char* hostname_cstr,
503
                                    uint64_t reference_time) {
504
   if(required_strength == 0) {
14✔
505
      required_strength = 110;
4✔
506
   }
507

508
#if defined(BOTAN_HAS_X509_CERTIFICATES)
509
   return ffi_guard_thunk(__func__, [=]() -> int {
14✔
510
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
16✔
511
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
14✔
512
      const auto validation_time = reference_time == 0
14✔
513
                                      ? std::chrono::system_clock::now()
14✔
514
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
515

516
      std::vector<Botan::X509_Certificate> end_certs;
14✔
517
      end_certs.push_back(safe_get(cert));
14✔
518
      for(size_t i = 0; i != intermediates_len; ++i) {
32✔
519
         end_certs.push_back(safe_get(intermediates[i]));
18✔
520
      }
521

522
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
14✔
523
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
14✔
524
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
14✔
525
      std::vector<Botan::Certificate_Store*> trusted_roots;
14✔
526

527
      if(trusted_path && *trusted_path) {
14✔
528
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
529
         trusted_roots.push_back(trusted_from_path.get());
2✔
530
      }
531

532
      if(trusted_len > 0) {
14✔
533
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
22✔
534
         for(size_t i = 0; i != trusted_len; ++i) {
22✔
535
            trusted_extra->add_certificate(safe_get(trusted[i]));
11✔
536
         }
537
         trusted_roots.push_back(trusted_extra.get());
11✔
538
      }
539

540
      if(crls_len > 0) {
14✔
541
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
542
         for(size_t i = 0; i != crls_len; ++i) {
13✔
543
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
544
         }
545
         trusted_roots.push_back(trusted_crls.get());
5✔
546
      }
547

548
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
28✔
549

550
      auto validation_result =
14✔
551
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
14✔
552

553
      if(result_code) {
14✔
554
         *result_code = static_cast<int>(validation_result.result());
14✔
555
      }
556

557
      if(validation_result.successful_validation()) {
14✔
558
         return 0;
559
      } else {
560
         return 1;
8✔
561
      }
562
   });
16✔
563
#else
564
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
565
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
566
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
567
#endif
568
}
569

570
int botan_x509_cert_params_builder_destroy(botan_x509_cert_params_builder_t builder) {
8✔
571
#if defined(BOTAN_HAS_X509_CERTIFICATES)
572
   return BOTAN_FFI_CHECKED_DELETE(builder);
8✔
573
#else
574
   BOTAN_UNUSED(builder);
575
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
576
#endif
577
}
578

579
int botan_x509_create_cert_params_builder(botan_x509_cert_params_builder_t* builder_obj,
8✔
580
                                          const char* opts,
581
                                          uint32_t* expire_time) {
582
   if(builder_obj == nullptr || opts == nullptr) {
8✔
583
      return BOTAN_FFI_ERROR_NULL_POINTER;
584
   }
585

586
#if defined(BOTAN_HAS_X509_CERTIFICATES)
587
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
588
      std::unique_ptr<Botan::X509_Cert_Options> co;
8✔
589
      if(expire_time) {
8✔
590
         co = std::make_unique<Botan::X509_Cert_Options>(opts, *expire_time);
×
591
      } else {
592
         co = std::make_unique<Botan::X509_Cert_Options>(opts);
16✔
593
      }
594
      return ffi_new_object(builder_obj, std::move(co));
16✔
595
   });
16✔
596
#else
597
   BOTAN_UNUSED(expire_time);
598
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
599
#endif
600
}
601

602
#if defined(BOTAN_HAS_X509_CERTIFICATES)
603
   // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
604
   #define X509_GET_CERT_PARAMS_BUILDER_STRING(FIELD_NAME)                                          \
605
      int botan_x509_cert_params_builder_add_##FIELD_NAME(botan_x509_cert_params_builder_t builder, \
606
                                                          const char* value) {                      \
607
         if(value == nullptr) {                                                                     \
608
            return BOTAN_FFI_ERROR_NULL_POINTER;                                                    \
609
         }                                                                                          \
610
         return ffi_guard_thunk(__func__, [=]() -> int {                                            \
611
            auto& builder_ = safe_get(builder);                                                     \
612
            if(!builder_.FIELD_NAME.empty()) {                                                      \
613
               return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;                                         \
614
            }                                                                                       \
615
            builder_.FIELD_NAME = value;                                                            \
616
            return BOTAN_FFI_SUCCESS;                                                               \
617
         });                                                                                        \
618
      }
619
#else
620
   // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
621
   #define X509_GET_CERT_PARAMS_BUILDER_STRING(FIELD_NAME)                                          \
622
      int botan_x509_cert_params_builder_add_##FIELD_NAME(botan_x509_cert_params_builder_t builder, \
623
                                                          const char* value) {                      \
624
         if(value == nullptr) {                                                                     \
625
            return BOTAN_FFI_ERROR_NULL_POINTER;                                                    \
626
         }                                                                                          \
627
         BOTAN_UNUSED(builder);                                                                     \
628
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;                                                    \
629
      }
630
#endif
631

632
X509_GET_CERT_PARAMS_BUILDER_STRING(common_name)
×
633
X509_GET_CERT_PARAMS_BUILDER_STRING(country)
×
634
X509_GET_CERT_PARAMS_BUILDER_STRING(organization)
×
635
X509_GET_CERT_PARAMS_BUILDER_STRING(locality)
×
636
X509_GET_CERT_PARAMS_BUILDER_STRING(state)
×
637
X509_GET_CERT_PARAMS_BUILDER_STRING(serial_number)
×
638
X509_GET_CERT_PARAMS_BUILDER_STRING(email)
×
639
X509_GET_CERT_PARAMS_BUILDER_STRING(uri)
4✔
640
X509_GET_CERT_PARAMS_BUILDER_STRING(ip)
×
641
X509_GET_CERT_PARAMS_BUILDER_STRING(xmpp)
×
642
X509_GET_CERT_PARAMS_BUILDER_STRING(challenge)
×
643

644
int botan_x509_cert_params_builder_add_org_unit(botan_x509_cert_params_builder_t builder, const char* org_unit) {
×
645
   if(org_unit == nullptr) {
×
646
      return BOTAN_FFI_ERROR_NULL_POINTER;
647
   }
648
#if defined(BOTAN_HAS_X509_CERTIFICATES)
649
   return ffi_guard_thunk(__func__, [=]() -> int {
×
650
      auto& builder_ = safe_get(builder);
×
651
      if(builder_.org_unit.empty()) {
×
652
         builder_.org_unit = org_unit;
×
653
      } else {
654
         builder_.more_org_units.push_back(org_unit);
×
655
      }
656
      return BOTAN_FFI_SUCCESS;
×
657
   });
×
658
#else
659
   BOTAN_UNUSED(builder);
660
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
661
#endif
662
}
663

664
int botan_x509_cert_params_builder_add_dns(botan_x509_cert_params_builder_t builder, const char* dns) {
6✔
665
   if(dns == nullptr) {
6✔
666
      return BOTAN_FFI_ERROR_NULL_POINTER;
667
   }
668
#if defined(BOTAN_HAS_X509_CERTIFICATES)
669
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
670
      auto& builder_ = safe_get(builder);
6✔
671
      if(builder_.dns.empty()) {
6✔
672
         builder_.dns = dns;
2✔
673
      } else {
674
         builder_.more_dns.push_back(dns);
8✔
675
      }
676
      return BOTAN_FFI_SUCCESS;
6✔
677
   });
6✔
678
#else
679
   BOTAN_UNUSED(builder);
680
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
681
#endif
682
}
683

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

693
int botan_x509_cert_params_builder_add_not_before(botan_x509_cert_params_builder_t builder, uint64_t time_since_epoch) {
×
694
#if defined(BOTAN_HAS_X509_CERTIFICATES)
695
   return ffi_guard_thunk(__func__, [=]() -> int {
×
696
      auto& builder_ = safe_get(builder);
×
697
      if(builder_.start.time_is_set()) {
×
698
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
699
      }
700
      builder_.start = time_from_timestamp(time_since_epoch);
×
701
      return BOTAN_FFI_SUCCESS;
×
702
   });
×
703
#else
704
   BOTAN_UNUSED(builder, not_before);
705
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
706
#endif
707
}
708

709
int botan_x509_cert_params_builder_add_not_after(botan_x509_cert_params_builder_t builder, uint64_t time_since_epoch) {
×
710
#if defined(BOTAN_HAS_X509_CERTIFICATES)
711
   return ffi_guard_thunk(__func__, [=]() -> int {
×
712
      auto& builder_ = safe_get(builder);
×
713
      if(builder_.end.time_is_set()) {
×
714
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
715
      }
716
      builder_.end = time_from_timestamp(time_since_epoch);
×
717
      return BOTAN_FFI_SUCCESS;
×
718
   });
×
719
#else
720
   BOTAN_UNUSED(builder.not_after);
721
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
722
#endif
723
}
724

725
int botan_x509_cert_params_builder_add_constraints(botan_x509_cert_params_builder_t builder, uint32_t usage) {
2✔
726
#if defined(BOTAN_HAS_X509_CERTIFICATES)
727
   return BOTAN_FFI_VISIT(builder, [=](auto& o) { o.add_constraints(Botan::Key_Constraints(usage)); });
4✔
728
#else
729
   BOTAN_UNUSED(builder, usage);
730
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
731
#endif
732
}
733

734
int botan_x509_cert_params_builder_add_ex_constraint(botan_x509_cert_params_builder_t builder, botan_asn1_oid_t oid) {
×
735
#if defined(BOTAN_HAS_X509_CERTIFICATES)
736
   return ffi_guard_thunk(__func__, [=]() -> int {
×
737
      safe_get(builder).add_ex_constraint(safe_get(oid));
×
738
      return BOTAN_FFI_SUCCESS;
×
739
   });
×
740
#else
741
   BOTAN_UNUSED(builder, oid);
742
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
743
#endif
744
}
745

746
int botan_x509_cert_params_builder_add_ext_ip_addr_blocks(botan_x509_cert_params_builder_t builder,
6✔
747
                                                          botan_x509_ext_ip_addr_blocks_t ip_addr_blocks) {
748
#if defined(BOTAN_HAS_X509_CERTIFICATES)
749
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
750
      try {
6✔
751
         safe_get(builder).extensions.add(safe_get(ip_addr_blocks).copy());
8✔
752
      } catch(Botan::Invalid_Argument&) {
2✔
753
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
2✔
754
      }
2✔
755
      return BOTAN_FFI_SUCCESS;
4✔
756
   });
6✔
757
#else
758
   BOTAN_UNUSED(builder, as_blocks);
759
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
760
#endif
761
}
762

763
int botan_x509_cert_params_builder_add_ext_as_blocks(botan_x509_cert_params_builder_t builder,
6✔
764
                                                     botan_x509_ext_as_blocks_t as_blocks) {
765
#if defined(BOTAN_HAS_X509_CERTIFICATES)
766
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
767
      try {
6✔
768
         safe_get(builder).extensions.add(safe_get(as_blocks).copy());
8✔
769
      } catch(Botan::Invalid_Argument&) {
2✔
770
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
2✔
771
      }
2✔
772
      return BOTAN_FFI_SUCCESS;
4✔
773
   });
6✔
774
#else
775
   BOTAN_UNUSED(builder, as_blocks);
776
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
777
#endif
778
}
779

780
int botan_x509_create_self_signed_cert(botan_x509_cert_t* cert_obj,
4✔
781
                                       botan_privkey_t key,
782
                                       botan_x509_cert_params_builder_t builder,
783
                                       const char* hash_fn,
784
                                       const char* sig_padding,
785
                                       botan_rng_t rng) {
786
   if(cert_obj == nullptr || hash_fn == nullptr || sig_padding == nullptr) {
4✔
787
      return BOTAN_FFI_ERROR_NULL_POINTER;
788
   }
789
#if defined(BOTAN_HAS_X509_CERTIFICATES)
790
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
791
      auto ca_cert = std::make_unique<Botan::X509_Certificate>(
4✔
792
         Botan::X509::create_self_signed_cert(safe_get(builder), safe_get(key), hash_fn, safe_get(rng)));
4✔
793
      return ffi_new_object(cert_obj, std::move(ca_cert));
4✔
794
   });
8✔
795
#else
796
   BOTAN_UNUSED(key, builder, rng);
797
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
798
#endif
799
}
800

801
int botan_x509_pkcs10_req_destroy(botan_x509_pkcs10_req_t req) {
4✔
802
#if defined(BOTAN_HAS_X509_CERTIFICATES)
803
   return BOTAN_FFI_CHECKED_DELETE(req);
4✔
804
#else
805
   BOTAN_UNUSED(req);
806
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
807
#endif
808
}
809

810
int botan_x509_create_pkcs10_req(botan_x509_pkcs10_req_t* req_obj,
4✔
811
                                 botan_x509_cert_params_builder_t builder,
812
                                 botan_privkey_t key,
813
                                 const char* hash_fn,
814
                                 botan_rng_t rng) {
815
   if(req_obj == nullptr || hash_fn == nullptr) {
4✔
816
      return BOTAN_FFI_ERROR_NULL_POINTER;
817
   }
818
#if defined(BOTAN_HAS_X509_CERTIFICATES)
819
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
820
      auto req = std::make_unique<Botan::PKCS10_Request>(
4✔
821
         Botan::X509::create_cert_req(safe_get(builder), safe_get(key), hash_fn, safe_get(rng)));
4✔
822
      return ffi_new_object(req_obj, std::move(req));
8✔
823
   });
8✔
824
#else
825
   BOTAN_UNUSED(builder, key, rng);
826
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
827
#endif
828
}
829

830
int botan_x509_pkcs10_req_view_pem(botan_x509_pkcs10_req_t req, botan_view_ctx ctx, botan_view_str_fn view) {
×
831
#if defined(BOTAN_HAS_X509_CERTIFICATES)
832
   return BOTAN_FFI_VISIT(req, [=](const auto& r) -> int { return invoke_view_callback(view, ctx, r.PEM_encode()); });
×
833
#else
834
   BOTAN_UNUSED(req, ctx, view);
835
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
836
#endif
837
}
838

839
int botan_x509_sign_req(botan_x509_cert_t* subject_cert,
4✔
840
                        botan_x509_pkcs10_req_t subject_req,
841
                        botan_x509_cert_t issuing_cert,
842
                        botan_privkey_t issuing_key,
843
                        botan_rng_t rng,
844
                        uint64_t not_before,
845
                        uint64_t not_after,
846
                        const char* hash_fn,
847
                        const char* padding) {
848
   if(subject_cert == nullptr || hash_fn == nullptr || padding == nullptr) {
4✔
849
      return BOTAN_FFI_ERROR_NULL_POINTER;
850
   }
851
#if defined(BOTAN_HAS_X509_CERTIFICATES)
852
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
853
      Botan::RandomNumberGenerator& rng_ = safe_get(rng);
4✔
854
      auto ca = Botan::X509_CA(safe_get(issuing_cert), safe_get(issuing_key), hash_fn, padding, rng_);
4✔
855

856
      auto cert = std::make_unique<Botan::X509_Certificate>(ca.sign_request(
8✔
857
         safe_get(subject_req), safe_get(rng), time_from_timestamp(not_before), time_from_timestamp(not_after)));
8✔
858
      return ffi_new_object(subject_cert, std::move(cert));
4✔
859
   });
8✔
860
#else
861
   BOTAN_UNUSED(subject_req, issuing_cert, issuing_key, rng, not_before, not_after);
862
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
863
#endif
864
}
865
}
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