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

randombit / botan / 16679948655

01 Aug 2025 04:17PM UTC coverage: 90.676% (-0.006%) from 90.682%
16679948655

Pull #4877

github

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

100548 of 110887 relevant lines covered (90.68%)

12277433.11 hits per line

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

87.73
/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
std::chrono::system_clock::time_point timepoint_from_timestamp(uint64_t time_since_epoch) {
12✔
20
   return std::chrono::system_clock::time_point(std::chrono::seconds(time_since_epoch));
12✔
21
}
22

23
Botan::X509_Time time_from_timestamp(uint64_t time_since_epoch) {
8✔
24
   return Botan::X509_Time(timepoint_from_timestamp(time_since_epoch));
12✔
25
}
26
}  // namespace
27

28
extern "C" {
29

30
using namespace Botan_FFI;
31

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

37
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
38

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

44
#else
45
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
46
#endif
47
}
48

49
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
1✔
50
   if(cert_obj == nullptr) {
1✔
51
      return BOTAN_FFI_ERROR_NULL_POINTER;
52
   }
53

54
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
55

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

61
#else
62
   BOTAN_UNUSED(cert);
63
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
64
#endif
65
}
66

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

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

84
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
2✔
85
   if(key == nullptr) {
2✔
86
      return BOTAN_FFI_ERROR_NULL_POINTER;
87
   }
88

89
   *key = nullptr;
2✔
90

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

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

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

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

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

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

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

180
int botan_x509_get_basic_constraints(botan_x509_cert_t cert, int* is_ca, size_t* limit) {
×
181
   if(is_ca == nullptr || limit == nullptr) {
×
182
      return BOTAN_FFI_ERROR_NULL_POINTER;
183
   }
184

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

202
int botan_x509_get_key_constraints(botan_x509_cert_t cert, uint32_t* usage) {
2✔
203
   if(usage == nullptr) {
2✔
204
      return BOTAN_FFI_ERROR_NULL_POINTER;
205
   }
206

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

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

228
int botan_x509_is_self_signed(botan_x509_cert_t cert, int* out) {
2✔
229
   if(out == nullptr) {
2✔
230
      return BOTAN_FFI_ERROR_NULL_POINTER;
231
   }
232

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

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

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

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

286
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
3✔
287
#if defined(BOTAN_HAS_X509_CERTIFICATES)
288
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
6✔
289
#else
290
   BOTAN_UNUSED(cert, time_since_epoch);
291
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
292
#endif
293
}
294

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

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

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

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

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

335
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
336
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
337
}
338

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

349
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
350
   if(hostname == nullptr) {
6✔
351
      return BOTAN_FFI_ERROR_NULL_POINTER;
352
   }
353

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

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

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

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

390
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
6✔
391
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
6✔
392
      std::vector<Botan::Certificate_Store*> trusted_roots;
6✔
393

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

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

407
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
12✔
408

409
      auto validation_result =
6✔
410
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
6✔
411

412
      if(result_code) {
6✔
413
         *result_code = static_cast<int>(validation_result.result());
6✔
414
      }
415

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

429
const char* botan_x509_cert_validation_status(int code) {
11✔
430
   if(code < 0) {
11✔
431
      return nullptr;
432
   }
433

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

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

447
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
448

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

454
#else
455
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
456
#endif
457
}
458

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

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

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

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

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

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

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

525
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
14✔
526
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
14✔
527
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
14✔
528
      std::vector<Botan::Certificate_Store*> trusted_roots;
14✔
529

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

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

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

551
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
28✔
552

553
      auto validation_result =
14✔
554
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
14✔
555

556
      if(result_code) {
14✔
557
         *result_code = static_cast<int>(validation_result.result());
14✔
558
      }
559

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

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

582
int botan_x509_create_cert_params_builder(botan_x509_cert_params_builder_t* builder_obj) {
8✔
583
   if(builder_obj == nullptr) {
8✔
584
      return BOTAN_FFI_ERROR_NULL_POINTER;
585
   }
586

587
#if defined(BOTAN_HAS_X509_CERTIFICATES)
588
   return ffi_guard_thunk(__func__, [=]() -> int {
8✔
589
      auto co = std::make_unique<Botan::CertificateParametersBuilder>();
8✔
590
      return ffi_new_object(builder_obj, std::move(co));
16✔
591
   });
16✔
592
#else
593
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
594
#endif
595
}
596

597
#if defined(BOTAN_HAS_X509_CERTIFICATES)
598
   // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
599
   #define X509_GET_CERT_PARAMS_BUILDER_STRING(FIELD_NAME)                                          \
600
      int botan_x509_cert_params_builder_add_##FIELD_NAME(botan_x509_cert_params_builder_t builder, \
601
                                                          const char* value) {                      \
602
         if(value == nullptr) {                                                                     \
603
            return BOTAN_FFI_ERROR_NULL_POINTER;                                                    \
604
         }                                                                                          \
605
         return BOTAN_FFI_VISIT(builder, [=](auto& o) { o.add_##FIELD_NAME(value); });              \
606
      }
607
#else
608
   // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
609
   #define X509_GET_CERT_PARAMS_BUILDER_STRING(FIELD_NAME)                                          \
610
      int botan_x509_cert_params_builder_add_##FIELD_NAME(botan_x509_cert_params_builder_t builder, \
611
                                                          const char* value) {                      \
612
         if(value == nullptr) {                                                                     \
613
            return BOTAN_FFI_ERROR_NULL_POINTER;                                                    \
614
         }                                                                                          \
615
         BOTAN_UNUSED(builder);                                                                     \
616
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;                                                    \
617
      }
618
#endif
619

620
X509_GET_CERT_PARAMS_BUILDER_STRING(common_name)
4✔
621
X509_GET_CERT_PARAMS_BUILDER_STRING(country)
4✔
622
X509_GET_CERT_PARAMS_BUILDER_STRING(state)
×
623
X509_GET_CERT_PARAMS_BUILDER_STRING(locality)
×
624
X509_GET_CERT_PARAMS_BUILDER_STRING(serial_number)
×
625
X509_GET_CERT_PARAMS_BUILDER_STRING(organization)
4✔
626
X509_GET_CERT_PARAMS_BUILDER_STRING(organizational_unit)
4✔
627
X509_GET_CERT_PARAMS_BUILDER_STRING(email)
×
628
X509_GET_CERT_PARAMS_BUILDER_STRING(dns)
12✔
629
X509_GET_CERT_PARAMS_BUILDER_STRING(uri)
4✔
630
X509_GET_CERT_PARAMS_BUILDER_STRING(xmpp)
×
631

632
int botan_x509_cert_params_builder_add_ipv4(botan_x509_cert_params_builder_t builder, uint32_t ipv4) {
×
633
#if defined(BOTAN_HAS_X509_CERTIFICATES)
634
   return BOTAN_FFI_VISIT(builder, [=](auto& o) { o.add_ipv4(ipv4); });
×
635
#else
636
   BOTAN_UNUSED(builder, ipv4);
637
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
638
#endif
639
}
640

641
int botan_x509_cert_params_builder_add_allowed_usage(botan_x509_cert_params_builder_t builder, uint32_t usage) {
1✔
642
#if defined(BOTAN_HAS_X509_CERTIFICATES)
643
   return BOTAN_FFI_VISIT(builder, [=](auto& o) { o.add_allowed_usage(Botan::Key_Constraints(usage)); });
2✔
644
#else
645
   BOTAN_UNUSED(builder, usage);
646
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
647
#endif
648
}
649

650
int botan_x509_cert_params_builder_add_allowed_extended_usage(botan_x509_cert_params_builder_t builder,
×
651
                                                              botan_asn1_oid_t oid) {
652
#if defined(BOTAN_HAS_X509_CERTIFICATES)
653
   return ffi_guard_thunk(__func__, [=]() -> int {
×
654
      safe_get(builder).add_allowed_extended_usage(safe_get(oid));
×
655
      return BOTAN_FFI_SUCCESS;
×
656
   });
×
657
#else
658
   BOTAN_UNUSED(builder, oid);
659
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
660
#endif
661
}
662

663
int botan_x509_cert_params_builder_set_as_ca_certificate(botan_x509_cert_params_builder_t builder, size_t limit) {
4✔
664
#if defined(BOTAN_HAS_X509_CERTIFICATES)
665
   return BOTAN_FFI_VISIT(builder, [=](auto& o) { o.set_as_ca_certificate(limit); });
8✔
666
#else
667
   BOTAN_UNUSED(builder, limit);
668
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
669
#endif
670
}
671

672
int botan_x509_cert_params_builder_add_ext_ip_addr_blocks(botan_x509_cert_params_builder_t builder,
6✔
673
                                                          botan_x509_ext_ip_addr_blocks_t ip_addr_blocks,
674
                                                          int is_critical) {
675
#if defined(BOTAN_HAS_X509_CERTIFICATES)
676
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
677
      if(is_critical != 0 && is_critical != 1) {
6✔
678
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
679
      }
680
      try {
6✔
681
         safe_get(builder).add_extension(safe_get(ip_addr_blocks).copy(), is_critical);
8✔
682
      } catch(Botan::Invalid_Argument&) {
2✔
683
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
2✔
684
      }
2✔
685
      return BOTAN_FFI_SUCCESS;
4✔
686
   });
6✔
687
#else
688
   BOTAN_UNUSED(builder, ip_addr_blocks, is_critical);
689
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
690
#endif
691
}
692

693
int botan_x509_cert_params_builder_add_ext_as_blocks(botan_x509_cert_params_builder_t builder,
6✔
694
                                                     botan_x509_ext_as_blocks_t as_blocks,
695
                                                     int is_critical) {
696
#if defined(BOTAN_HAS_X509_CERTIFICATES)
697
   return ffi_guard_thunk(__func__, [=]() -> int {
6✔
698
      if(is_critical != 0 && is_critical != 1) {
6✔
699
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
700
      }
701
      try {
6✔
702
         safe_get(builder).add_extension(safe_get(as_blocks).copy(), is_critical);
8✔
703
      } catch(Botan::Invalid_Argument&) {
2✔
704
         return BOTAN_FFI_ERROR_INVALID_OBJECT_STATE;
2✔
705
      }
2✔
706
      return BOTAN_FFI_SUCCESS;
4✔
707
   });
6✔
708
#else
709
   BOTAN_UNUSED(builder, as_blocks, is_critical);
710
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
711
#endif
712
}
713

714
int botan_x509_create_self_signed_cert(botan_x509_cert_t* cert_obj,
4✔
715
                                       botan_privkey_t key,
716
                                       botan_x509_cert_params_builder_t builder,
717
                                       botan_rng_t rng,
718
                                       uint64_t not_before,
719
                                       uint64_t not_after,
720
                                       const char* hash_fn,
721
                                       const char* padding) {
722
   if(cert_obj == nullptr) {
4✔
723
      return BOTAN_FFI_ERROR_NULL_POINTER;
724
   }
725
#if defined(BOTAN_HAS_X509_CERTIFICATES)
726
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
727
      std::optional<std::string> hash_fn_;
4✔
728
      std::optional<std::string> padding_;
4✔
729
      if(hash_fn != nullptr) {
4✔
730
         hash_fn_ = hash_fn;
4✔
731
      }
732
      if(padding != nullptr) {
4✔
733
         padding_ = padding;
1✔
734
      }
735

736
      auto cert = std::make_unique<Botan::X509_Certificate>(
4✔
737
         safe_get(builder).into_self_signed_cert(timepoint_from_timestamp(not_before),
17✔
738
                                                 timepoint_from_timestamp(not_after),
739
                                                 safe_get(key),
4✔
740
                                                 safe_get(rng),
741
                                                 hash_fn_,
742
                                                 padding_));
4✔
743

744
      return ffi_new_object(cert_obj, std::move(cert));
4✔
745
   });
13✔
746
#else
747
   BOTAN_UNUSED(key, builder, rng, not_before, not_after, hash_fn, padding);
748
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
749
#endif
750
}
751

752
int botan_x509_pkcs10_req_destroy(botan_x509_pkcs10_req_t req) {
4✔
753
#if defined(BOTAN_HAS_X509_CERTIFICATES)
754
   return BOTAN_FFI_CHECKED_DELETE(req);
4✔
755
#else
756
   BOTAN_UNUSED(req);
757
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
758
#endif
759
}
760

761
int botan_x509_create_pkcs10_req(botan_x509_pkcs10_req_t* req_obj,
4✔
762
                                 botan_privkey_t key,
763
                                 botan_x509_cert_params_builder_t builder,
764
                                 botan_rng_t rng,
765
                                 const char* hash_fn,
766
                                 const char* padding,
767
                                 const char* challenge_password) {
768
   if(req_obj == nullptr) {
4✔
769
      return BOTAN_FFI_ERROR_NULL_POINTER;
770
   }
771
#if defined(BOTAN_HAS_X509_CERTIFICATES)
772
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
773
      std::optional<std::string> hash_fn_;
4✔
774
      std::optional<std::string> padding_;
4✔
775
      std::optional<std::string> challenge_password_;
4✔
776
      if(hash_fn != nullptr) {
4✔
777
         hash_fn_ = hash_fn;
4✔
778
      }
779
      if(padding != nullptr) {
4✔
780
         padding_ = padding;
×
781
      }
782
      if(challenge_password != nullptr) {
4✔
783
         challenge_password_ = challenge_password;
×
784
      }
785

786
      auto req = std::make_unique<Botan::PKCS10_Request>(
4✔
787
         safe_get(builder).into_pkcs10_request(safe_get(key), safe_get(rng), hash_fn_, padding_, challenge_password_));
8✔
788
      return ffi_new_object(req_obj, std::move(req));
4✔
789
   });
12✔
790
#else
791
   BOTAN_UNUSED(key, builder, rng, padding, hash_fn, challenge_password);
792
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
793
#endif
794
}
795

796
int botan_x509_pkcs10_req_view_pem(botan_x509_pkcs10_req_t req, botan_view_ctx ctx, botan_view_str_fn view) {
×
797
#if defined(BOTAN_HAS_X509_CERTIFICATES)
798
   return BOTAN_FFI_VISIT(req, [=](const auto& r) -> int { return invoke_view_callback(view, ctx, r.PEM_encode()); });
×
799
#else
800
   BOTAN_UNUSED(req, ctx, view);
801
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
802
#endif
803
}
804

805
// req_load
806
// view functions for req
807

808
int botan_x509_sign_req(botan_x509_cert_t* subject_cert,
4✔
809
                        botan_x509_pkcs10_req_t subject_req,
810
                        botan_x509_cert_t issuing_cert,
811
                        botan_privkey_t issuing_key,
812
                        botan_rng_t rng,
813
                        uint64_t not_before,
814
                        uint64_t not_after,
815
                        const char* hash_fn,
816
                        const char* padding) {
817
   if(subject_cert == nullptr) {
4✔
818
      return BOTAN_FFI_ERROR_NULL_POINTER;
819
   }
820
#if defined(BOTAN_HAS_X509_CERTIFICATES)
821
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
822
      auto& rng_ = safe_get(rng);
4✔
823
      std::string hash_fn_;
4✔
824
      std::string padding_;
4✔
825
      if(hash_fn != nullptr) {
4✔
826
         hash_fn_ = hash_fn;
4✔
827
      }
828
      if(padding != nullptr) {
4✔
829
         padding_ = padding;
2✔
830
      }
831

832
      auto ca = Botan::X509_CA(safe_get(issuing_cert), safe_get(issuing_key), hash_fn_, padding_, rng_);
4✔
833

834
      std::unique_ptr<Botan::X509_Certificate> cert = std::make_unique<Botan::X509_Certificate>(
4✔
835
         ca.sign_request(safe_get(subject_req), rng_, time_from_timestamp(not_before), time_from_timestamp(not_after)));
4✔
836

837
      return ffi_new_object(subject_cert, std::move(cert));
4✔
838
   });
8✔
839
#else
840
   BOTAN_UNUSED(subject_req, issuing_cert, issuing_key, rng, not_before, not_after, hash_fn, padding);
841
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
842
#endif
843
}
844
}
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