Coverage Report

Created: 2025-11-11 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/Botan-3.4.0/src/lib/ffi/ffi_cert.cpp
Line
Count
Source
1
/*
2
* (C) 2015,2017,2018 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6
7
#include <botan/ffi.h>
8
9
#include <botan/internal/ffi_pkey.h>
10
#include <botan/internal/ffi_util.h>
11
#include <memory>
12
13
#if defined(BOTAN_HAS_X509_CERTIFICATES)
14
   #include <botan/data_src.h>
15
   #include <botan/x509_crl.h>
16
   #include <botan/x509cert.h>
17
   #include <botan/x509path.h>
18
#endif
19
20
extern "C" {
21
22
using namespace Botan_FFI;
23
24
#if defined(BOTAN_HAS_X509_CERTIFICATES)
25
26
BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
27
28
#endif
29
30
0
int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
31
0
   if(!cert_obj || !cert_path) {
32
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
33
0
   }
34
35
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
36
37
   return ffi_guard_thunk(__func__, [=]() -> int {
38
      auto c = std::make_unique<Botan::X509_Certificate>(cert_path);
39
      *cert_obj = new botan_x509_cert_struct(std::move(c));
40
      return BOTAN_FFI_SUCCESS;
41
   });
42
43
#else
44
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
45
0
#endif
46
0
}
47
48
0
int botan_x509_cert_dup(botan_x509_cert_t* cert_obj, botan_x509_cert_t cert) {
49
0
   if(!cert_obj) {
50
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
51
0
   }
52
53
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
54
55
   return ffi_guard_thunk(__func__, [=]() -> int {
56
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
57
      *cert_obj = new botan_x509_cert_struct(std::move(c));
58
      return BOTAN_FFI_SUCCESS;
59
   });
60
61
#else
62
0
   BOTAN_UNUSED(cert);
63
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
64
0
#endif
65
0
}
66
67
0
int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) {
68
0
   if(!cert_obj || !cert_bits) {
69
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
70
0
   }
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
      *cert_obj = new botan_x509_cert_struct(std::move(c));
77
      return BOTAN_FFI_SUCCESS;
78
   });
79
#else
80
0
   BOTAN_UNUSED(cert_bits_len);
81
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
82
0
#endif
83
0
}
84
85
0
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) {
86
0
   if(key == nullptr) {
87
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
88
0
   }
89
90
0
   *key = nullptr;
91
92
#if defined(BOTAN_HAS_X509_CERTIFICATES)
93
   return ffi_guard_thunk(__func__, [=]() -> int {
94
      auto public_key = safe_get(cert).subject_public_key();
95
      *key = new botan_pubkey_struct(std::move(public_key));
96
      return BOTAN_FFI_SUCCESS;
97
   });
98
#else
99
0
   BOTAN_UNUSED(cert);
100
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
101
0
#endif
102
0
}
103
104
int botan_x509_cert_get_issuer_dn(
105
0
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
106
#if defined(BOTAN_HAS_X509_CERTIFICATES)
107
   return BOTAN_FFI_VISIT(cert,
108
                          [=](const auto& c) { return write_str_output(out, out_len, c.issuer_info(key).at(index)); });
109
#else
110
0
   BOTAN_UNUSED(cert, key, index, out, out_len);
111
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
112
0
#endif
113
0
}
114
115
int botan_x509_cert_get_subject_dn(
116
0
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
117
#if defined(BOTAN_HAS_X509_CERTIFICATES)
118
   return BOTAN_FFI_VISIT(cert,
119
                          [=](const auto& c) { return write_str_output(out, out_len, c.subject_info(key).at(index)); });
120
#else
121
0
   BOTAN_UNUSED(cert, key, index, out, out_len);
122
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
123
0
#endif
124
0
}
125
126
0
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) {
127
0
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
128
0
}
129
130
0
int botan_x509_cert_view_as_string(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_str_fn view) {
131
#if defined(BOTAN_HAS_X509_CERTIFICATES)
132
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return invoke_view_callback(view, ctx, c.to_string()); });
133
#else
134
0
   BOTAN_UNUSED(cert, ctx, view);
135
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
136
0
#endif
137
0
}
138
139
0
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) {
140
#if defined(BOTAN_HAS_X509_CERTIFICATES)
141
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
142
      const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
143
      if(c.allowed_usage(k))
144
         return BOTAN_FFI_SUCCESS;
145
      return 1;
146
   });
147
#else
148
0
   BOTAN_UNUSED(cert, key_usage);
149
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
150
0
#endif
151
0
}
152
153
0
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
154
#if defined(BOTAN_HAS_X509_CERTIFICATES)
155
   return BOTAN_FFI_CHECKED_DELETE(cert);
156
#else
157
0
   BOTAN_UNUSED(cert);
158
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
159
0
#endif
160
0
}
161
162
0
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
163
#if defined(BOTAN_HAS_X509_CERTIFICATES)
164
   return BOTAN_FFI_VISIT(cert,
165
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
166
#else
167
0
   BOTAN_UNUSED(cert, out, out_len);
168
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
169
0
#endif
170
0
}
171
172
0
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
173
#if defined(BOTAN_HAS_X509_CERTIFICATES)
174
   return BOTAN_FFI_VISIT(cert,
175
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
176
#else
177
0
   BOTAN_UNUSED(cert, out, out_len);
178
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
179
0
#endif
180
0
}
181
182
0
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
183
#if defined(BOTAN_HAS_X509_CERTIFICATES)
184
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
185
#else
186
0
   BOTAN_UNUSED(cert, time_since_epoch);
187
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
188
0
#endif
189
0
}
190
191
0
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
192
#if defined(BOTAN_HAS_X509_CERTIFICATES)
193
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
194
#else
195
0
   BOTAN_UNUSED(cert, time_since_epoch);
196
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
197
0
#endif
198
0
}
199
200
0
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
201
#if defined(BOTAN_HAS_X509_CERTIFICATES)
202
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
203
#else
204
0
   BOTAN_UNUSED(cert, out, out_len);
205
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
206
0
#endif
207
0
}
208
209
0
int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) {
210
#if defined(BOTAN_HAS_X509_CERTIFICATES)
211
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_str_output(out, out_len, c.fingerprint(hash)); });
212
#else
213
0
   BOTAN_UNUSED(cert, hash, out, out_len);
214
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
215
0
#endif
216
0
}
217
218
0
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
219
#if defined(BOTAN_HAS_X509_CERTIFICATES)
220
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
221
#else
222
0
   BOTAN_UNUSED(cert, out, out_len);
223
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
224
0
#endif
225
0
}
226
227
0
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
228
#if defined(BOTAN_HAS_X509_CERTIFICATES)
229
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
230
#else
231
0
   BOTAN_UNUSED(cert, out, out_len);
232
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
233
0
#endif
234
0
}
235
236
0
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
237
0
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
238
0
}
239
240
0
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
241
#if defined(BOTAN_HAS_X509_CERTIFICATES)
242
   return BOTAN_FFI_VISIT(cert,
243
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
244
#else
245
0
   BOTAN_UNUSED(cert, ctx, view);
246
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
247
0
#endif
248
0
}
249
250
0
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
251
0
   if(hostname == nullptr) {
252
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
253
0
   }
254
255
#if defined(BOTAN_HAS_X509_CERTIFICATES)
256
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
257
#else
258
0
   BOTAN_UNUSED(cert);
259
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
260
0
#endif
261
0
}
262
263
int botan_x509_cert_verify(int* result_code,
264
                           botan_x509_cert_t cert,
265
                           const botan_x509_cert_t* intermediates,
266
                           size_t intermediates_len,
267
                           const botan_x509_cert_t* trusted,
268
                           size_t trusted_len,
269
                           const char* trusted_path,
270
                           size_t required_strength,
271
                           const char* hostname_cstr,
272
0
                           uint64_t reference_time) {
273
0
   if(required_strength == 0) {
274
0
      required_strength = 110;
275
0
   }
276
277
#if defined(BOTAN_HAS_X509_CERTIFICATES)
278
   return ffi_guard_thunk(__func__, [=]() -> int {
279
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
280
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
281
      const auto validation_time = reference_time == 0
282
                                      ? std::chrono::system_clock::now()
283
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
284
285
      std::vector<Botan::X509_Certificate> end_certs;
286
      end_certs.push_back(safe_get(cert));
287
      for(size_t i = 0; i != intermediates_len; ++i) {
288
         end_certs.push_back(safe_get(intermediates[i]));
289
      }
290
291
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
292
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
293
      std::vector<Botan::Certificate_Store*> trusted_roots;
294
295
      if(trusted_path && *trusted_path) {
296
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
297
         trusted_roots.push_back(trusted_from_path.get());
298
      }
299
300
      if(trusted_len > 0) {
301
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
302
         for(size_t i = 0; i != trusted_len; ++i) {
303
            trusted_extra->add_certificate(safe_get(trusted[i]));
304
         }
305
         trusted_roots.push_back(trusted_extra.get());
306
      }
307
308
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
309
310
      auto validation_result =
311
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
312
313
      if(result_code) {
314
         *result_code = static_cast<int>(validation_result.result());
315
      }
316
317
      if(validation_result.successful_validation()) {
318
         return 0;
319
      } else {
320
         return 1;
321
      }
322
   });
323
#else
324
0
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
325
0
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
326
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
327
0
#endif
328
0
}
329
330
0
const char* botan_x509_cert_validation_status(int code) {
331
0
   if(code < 0) {
332
0
      return nullptr;
333
0
   }
334
335
#if defined(BOTAN_HAS_X509_CERTIFICATES)
336
   Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
337
   return Botan::to_string(sc);
338
#else
339
0
   return nullptr;
340
0
#endif
341
0
}
342
343
#if defined(BOTAN_HAS_X509_CERTIFICATES)
344
345
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
346
347
#endif
348
349
0
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
350
0
   if(!crl_obj || !crl_path) {
351
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
352
0
   }
353
354
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
355
356
   return ffi_guard_thunk(__func__, [=]() -> int {
357
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
358
      *crl_obj = new botan_x509_crl_struct(std::move(c));
359
      return BOTAN_FFI_SUCCESS;
360
   });
361
362
#else
363
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
364
0
#endif
365
0
}
366
367
0
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
368
0
   if(!crl_obj || !crl_bits) {
369
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
370
0
   }
371
372
#if defined(BOTAN_HAS_X509_CERTIFICATES)
373
   return ffi_guard_thunk(__func__, [=]() -> int {
374
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
375
      auto c = std::make_unique<Botan::X509_CRL>(bits);
376
      *crl_obj = new botan_x509_crl_struct(std::move(c));
377
      return BOTAN_FFI_SUCCESS;
378
   });
379
#else
380
0
   BOTAN_UNUSED(crl_bits_len);
381
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
382
0
#endif
383
0
}
384
385
0
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
386
#if defined(BOTAN_HAS_X509_CERTIFICATES)
387
   return BOTAN_FFI_CHECKED_DELETE(crl);
388
#else
389
0
   BOTAN_UNUSED(crl);
390
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
391
0
#endif
392
0
}
393
394
0
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
395
#if defined(BOTAN_HAS_X509_CERTIFICATES)
396
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
397
#else
398
0
   BOTAN_UNUSED(cert);
399
0
   BOTAN_UNUSED(crl);
400
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
401
0
#endif
402
0
}
403
404
int botan_x509_cert_verify_with_crl(int* result_code,
405
                                    botan_x509_cert_t cert,
406
                                    const botan_x509_cert_t* intermediates,
407
                                    size_t intermediates_len,
408
                                    const botan_x509_cert_t* trusted,
409
                                    size_t trusted_len,
410
                                    const botan_x509_crl_t* crls,
411
                                    size_t crls_len,
412
                                    const char* trusted_path,
413
                                    size_t required_strength,
414
                                    const char* hostname_cstr,
415
0
                                    uint64_t reference_time) {
416
0
   if(required_strength == 0) {
417
0
      required_strength = 110;
418
0
   }
419
420
#if defined(BOTAN_HAS_X509_CERTIFICATES)
421
   return ffi_guard_thunk(__func__, [=]() -> int {
422
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
423
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
424
      const auto validation_time = reference_time == 0
425
                                      ? std::chrono::system_clock::now()
426
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
427
428
      std::vector<Botan::X509_Certificate> end_certs;
429
      end_certs.push_back(safe_get(cert));
430
      for(size_t i = 0; i != intermediates_len; ++i) {
431
         end_certs.push_back(safe_get(intermediates[i]));
432
      }
433
434
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
435
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
436
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
437
      std::vector<Botan::Certificate_Store*> trusted_roots;
438
439
      if(trusted_path && *trusted_path) {
440
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
441
         trusted_roots.push_back(trusted_from_path.get());
442
      }
443
444
      if(trusted_len > 0) {
445
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
446
         for(size_t i = 0; i != trusted_len; ++i) {
447
            trusted_extra->add_certificate(safe_get(trusted[i]));
448
         }
449
         trusted_roots.push_back(trusted_extra.get());
450
      }
451
452
      if(crls_len > 0) {
453
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
454
         for(size_t i = 0; i != crls_len; ++i) {
455
            trusted_crls->add_crl(safe_get(crls[i]));
456
         }
457
         trusted_roots.push_back(trusted_crls.get());
458
      }
459
460
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
461
462
      auto validation_result =
463
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
464
465
      if(result_code) {
466
         *result_code = static_cast<int>(validation_result.result());
467
      }
468
469
      if(validation_result.successful_validation()) {
470
         return 0;
471
      } else {
472
         return 1;
473
      }
474
   });
475
#else
476
0
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
477
0
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
478
0
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
479
0
#endif
480
0
}
481
}