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

randombit / botan / 13021208024

28 Jan 2025 11:07PM UTC coverage: 91.241% (-0.02%) from 91.258%
13021208024

push

github

web-flow
Merge pull request #4604 from randombit/jack/support-minimal-curves

Avoid requiring legacy_ec_group in order to run the tests

94137 of 103174 relevant lines covered (91.24%)

11291073.45 hits per line

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

93.13
/src/lib/ffi/ffi_cert.cpp
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);
24✔
27

28
#endif
29

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

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

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

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

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

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

55
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
56
      auto c = std::make_unique<Botan::X509_Certificate>(safe_get(cert));
1✔
57
      *cert_obj = new botan_x509_cert_struct(std::move(c));
1✔
58
      return BOTAN_FFI_SUCCESS;
1✔
59
   });
1✔
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 || !cert_bits) {
×
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
      *cert_obj = new botan_x509_cert_struct(std::move(c));
×
77
      return BOTAN_FFI_SUCCESS;
×
78
   });
×
79
#else
80
   BOTAN_UNUSED(cert_bits_len);
81
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
82
#endif
83
}
84

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

90
   *key = nullptr;
2✔
91

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

104
int botan_x509_cert_get_issuer_dn(
8✔
105
   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, [=](const auto& c) -> int {
16✔
108
      auto issuer_info = c.issuer_info(key);
109
      if(index < issuer_info.size()) {
110
         return write_str_output(out, out_len, c.issuer_info(key).at(index));
111
      } else {
112
         return BOTAN_FFI_ERROR_BAD_PARAMETER;
113
      }
114
   });
115
#else
116
   BOTAN_UNUSED(cert, key, index, out, out_len);
117
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
118
#endif
119
}
120

121
int botan_x509_cert_get_subject_dn(
8✔
122
   botan_x509_cert_t cert, const char* key, size_t index, uint8_t out[], size_t* out_len) {
123
#if defined(BOTAN_HAS_X509_CERTIFICATES)
124
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) -> int {
16✔
125
      auto subject_info = c.subject_info(key);
126
      if(index < subject_info.size()) {
127
         return write_str_output(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
   return copy_view_str(reinterpret_cast<uint8_t*>(out), out_len, botan_x509_cert_view_as_string, cert);
2✔
140
}
141

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

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

166
int botan_x509_cert_destroy(botan_x509_cert_t cert) {
24✔
167
#if defined(BOTAN_HAS_X509_CERTIFICATES)
168
   return BOTAN_FFI_CHECKED_DELETE(cert);
24✔
169
#else
170
   BOTAN_UNUSED(cert);
171
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
172
#endif
173
}
174

175
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) {
3✔
176
#if defined(BOTAN_HAS_X509_CERTIFICATES)
177
   return BOTAN_FFI_VISIT(cert,
6✔
178
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_before().to_string()); });
179
#else
180
   BOTAN_UNUSED(cert, out, out_len);
181
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
182
#endif
183
}
184

185
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) {
2✔
186
#if defined(BOTAN_HAS_X509_CERTIFICATES)
187
   return BOTAN_FFI_VISIT(cert,
4✔
188
                          [=](const auto& c) { return write_str_output(out, out_len, c.not_after().to_string()); });
189
#else
190
   BOTAN_UNUSED(cert, out, out_len);
191
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
192
#endif
193
}
194

195
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
196
#if defined(BOTAN_HAS_X509_CERTIFICATES)
197
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_before().time_since_epoch(); });
4✔
198
#else
199
   BOTAN_UNUSED(cert, time_since_epoch);
200
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
201
#endif
202
}
203

204
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch) {
2✔
205
#if defined(BOTAN_HAS_X509_CERTIFICATES)
206
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { *time_since_epoch = c.not_after().time_since_epoch(); });
4✔
207
#else
208
   BOTAN_UNUSED(cert, time_since_epoch);
209
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
210
#endif
211
}
212

213
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
214
#if defined(BOTAN_HAS_X509_CERTIFICATES)
215
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.serial_number()); });
6✔
216
#else
217
   BOTAN_UNUSED(cert, out, out_len);
218
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
219
#endif
220
}
221

222
int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) {
3✔
223
#if defined(BOTAN_HAS_X509_CERTIFICATES)
224
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_str_output(out, out_len, c.fingerprint(hash)); });
6✔
225
#else
226
   BOTAN_UNUSED(cert, hash, out, out_len);
227
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
228
#endif
229
}
230

231
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
1✔
232
#if defined(BOTAN_HAS_X509_CERTIFICATES)
233
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.authority_key_id()); });
2✔
234
#else
235
   BOTAN_UNUSED(cert, out, out_len);
236
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
237
#endif
238
}
239

240
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
3✔
241
#if defined(BOTAN_HAS_X509_CERTIFICATES)
242
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return write_vec_output(out, out_len, c.subject_key_id()); });
6✔
243
#else
244
   BOTAN_UNUSED(cert, out, out_len);
245
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
246
#endif
247
}
248

249
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) {
2✔
250
   return copy_view_bin(out, out_len, botan_x509_cert_view_public_key_bits, cert);
2✔
251
}
252

253
int botan_x509_cert_view_public_key_bits(botan_x509_cert_t cert, botan_view_ctx ctx, botan_view_bin_fn view) {
3✔
254
#if defined(BOTAN_HAS_X509_CERTIFICATES)
255
   return BOTAN_FFI_VISIT(cert,
6✔
256
                          [=](const auto& c) { return invoke_view_callback(view, ctx, c.subject_public_key_bits()); });
257
#else
258
   BOTAN_UNUSED(cert, ctx, view);
259
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
260
#endif
261
}
262

263
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname) {
6✔
264
   if(hostname == nullptr) {
6✔
265
      return BOTAN_FFI_ERROR_NULL_POINTER;
266
   }
267

268
#if defined(BOTAN_HAS_X509_CERTIFICATES)
269
   return BOTAN_FFI_VISIT(cert, [=](const auto& c) { return c.matches_dns_name(hostname) ? 0 : -1; });
12✔
270
#else
271
   BOTAN_UNUSED(cert);
272
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
273
#endif
274
}
275

276
int botan_x509_cert_verify(int* result_code,
4✔
277
                           botan_x509_cert_t cert,
278
                           const botan_x509_cert_t* intermediates,
279
                           size_t intermediates_len,
280
                           const botan_x509_cert_t* trusted,
281
                           size_t trusted_len,
282
                           const char* trusted_path,
283
                           size_t required_strength,
284
                           const char* hostname_cstr,
285
                           uint64_t reference_time) {
286
   if(required_strength == 0) {
4✔
287
      required_strength = 110;
3✔
288
   }
289

290
#if defined(BOTAN_HAS_X509_CERTIFICATES)
291
   return ffi_guard_thunk(__func__, [=]() -> int {
4✔
292
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
4✔
293
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
4✔
294
      const auto validation_time = reference_time == 0
4✔
295
                                      ? std::chrono::system_clock::now()
4✔
296
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
×
297

298
      std::vector<Botan::X509_Certificate> end_certs;
4✔
299
      end_certs.push_back(safe_get(cert));
4✔
300
      for(size_t i = 0; i != intermediates_len; ++i) {
9✔
301
         end_certs.push_back(safe_get(intermediates[i]));
5✔
302
      }
303

304
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
4✔
305
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
4✔
306
      std::vector<Botan::Certificate_Store*> trusted_roots;
4✔
307

308
      if(trusted_path && *trusted_path) {
4✔
309
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
×
310
         trusted_roots.push_back(trusted_from_path.get());
×
311
      }
312

313
      if(trusted_len > 0) {
4✔
314
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
8✔
315
         for(size_t i = 0; i != trusted_len; ++i) {
8✔
316
            trusted_extra->add_certificate(safe_get(trusted[i]));
4✔
317
         }
318
         trusted_roots.push_back(trusted_extra.get());
4✔
319
      }
320

321
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
8✔
322

323
      auto validation_result =
4✔
324
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
4✔
325

326
      if(result_code) {
4✔
327
         *result_code = static_cast<int>(validation_result.result());
4✔
328
      }
329

330
      if(validation_result.successful_validation()) {
4✔
331
         return 0;
332
      } else {
333
         return 1;
3✔
334
      }
335
   });
8✔
336
#else
337
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
338
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
339
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
340
#endif
341
}
342

343
const char* botan_x509_cert_validation_status(int code) {
11✔
344
   if(code < 0) {
11✔
345
      return nullptr;
346
   }
347

348
#if defined(BOTAN_HAS_X509_CERTIFICATES)
349
   Botan::Certificate_Status_Code sc = static_cast<Botan::Certificate_Status_Code>(code);
11✔
350
   return Botan::to_string(sc);
11✔
351
#else
352
   return nullptr;
353
#endif
354
}
355

356
#if defined(BOTAN_HAS_X509_CERTIFICATES)
357

358
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
7✔
359

360
#endif
361

362
int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
6✔
363
   if(!crl_obj || !crl_path) {
6✔
364
      return BOTAN_FFI_ERROR_NULL_POINTER;
365
   }
366

367
#if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
368

369
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
370
      auto c = std::make_unique<Botan::X509_CRL>(crl_path);
6✔
371
      *crl_obj = new botan_x509_crl_struct(std::move(c));
6✔
372
      return BOTAN_FFI_SUCCESS;
6✔
373
   });
6✔
374

375
#else
376
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
377
#endif
378
}
379

380
int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len) {
1✔
381
   if(!crl_obj || !crl_bits) {
1✔
382
      return BOTAN_FFI_ERROR_NULL_POINTER;
383
   }
384

385
#if defined(BOTAN_HAS_X509_CERTIFICATES)
386
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
387
      Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
1✔
388
      auto c = std::make_unique<Botan::X509_CRL>(bits);
1✔
389
      *crl_obj = new botan_x509_crl_struct(std::move(c));
1✔
390
      return BOTAN_FFI_SUCCESS;
2✔
391
   });
2✔
392
#else
393
   BOTAN_UNUSED(crl_bits_len);
394
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
395
#endif
396
}
397

398
int botan_x509_crl_destroy(botan_x509_crl_t crl) {
7✔
399
#if defined(BOTAN_HAS_X509_CERTIFICATES)
400
   return BOTAN_FFI_CHECKED_DELETE(crl);
7✔
401
#else
402
   BOTAN_UNUSED(crl);
403
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
404
#endif
405
}
406

407
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert) {
6✔
408
#if defined(BOTAN_HAS_X509_CERTIFICATES)
409
   return BOTAN_FFI_VISIT(crl, [=](const auto& c) { return c.is_revoked(safe_get(cert)) ? 0 : -1; });
12✔
410
#else
411
   BOTAN_UNUSED(cert);
412
   BOTAN_UNUSED(crl);
413
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
414
#endif
415
}
416

417
int botan_x509_cert_verify_with_crl(int* result_code,
12✔
418
                                    botan_x509_cert_t cert,
419
                                    const botan_x509_cert_t* intermediates,
420
                                    size_t intermediates_len,
421
                                    const botan_x509_cert_t* trusted,
422
                                    size_t trusted_len,
423
                                    const botan_x509_crl_t* crls,
424
                                    size_t crls_len,
425
                                    const char* trusted_path,
426
                                    size_t required_strength,
427
                                    const char* hostname_cstr,
428
                                    uint64_t reference_time) {
429
   if(required_strength == 0) {
12✔
430
      required_strength = 110;
2✔
431
   }
432

433
#if defined(BOTAN_HAS_X509_CERTIFICATES)
434
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
435
      const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
14✔
436
      const Botan::Usage_Type usage = Botan::Usage_Type::UNSPECIFIED;
12✔
437
      const auto validation_time = reference_time == 0
12✔
438
                                      ? std::chrono::system_clock::now()
12✔
439
                                      : std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
1✔
440

441
      std::vector<Botan::X509_Certificate> end_certs;
12✔
442
      end_certs.push_back(safe_get(cert));
12✔
443
      for(size_t i = 0; i != intermediates_len; ++i) {
30✔
444
         end_certs.push_back(safe_get(intermediates[i]));
18✔
445
      }
446

447
      std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
12✔
448
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
12✔
449
      std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
12✔
450
      std::vector<Botan::Certificate_Store*> trusted_roots;
12✔
451

452
      if(trusted_path && *trusted_path) {
12✔
453
         trusted_from_path = std::make_unique<Botan::Certificate_Store_In_Memory>(trusted_path);
2✔
454
         trusted_roots.push_back(trusted_from_path.get());
2✔
455
      }
456

457
      if(trusted_len > 0) {
12✔
458
         trusted_extra = std::make_unique<Botan::Certificate_Store_In_Memory>();
18✔
459
         for(size_t i = 0; i != trusted_len; ++i) {
18✔
460
            trusted_extra->add_certificate(safe_get(trusted[i]));
9✔
461
         }
462
         trusted_roots.push_back(trusted_extra.get());
9✔
463
      }
464

465
      if(crls_len > 0) {
12✔
466
         trusted_crls = std::make_unique<Botan::Certificate_Store_In_Memory>();
10✔
467
         for(size_t i = 0; i != crls_len; ++i) {
13✔
468
            trusted_crls->add_crl(safe_get(crls[i]));
8✔
469
         }
470
         trusted_roots.push_back(trusted_crls.get());
5✔
471
      }
472

473
      Botan::Path_Validation_Restrictions restrictions(false, required_strength);
24✔
474

475
      auto validation_result =
12✔
476
         Botan::x509_path_validate(end_certs, restrictions, trusted_roots, hostname, usage, validation_time);
12✔
477

478
      if(result_code) {
12✔
479
         *result_code = static_cast<int>(validation_result.result());
12✔
480
      }
481

482
      if(validation_result.successful_validation()) {
12✔
483
         return 0;
484
      } else {
485
         return 1;
8✔
486
      }
487
   });
26✔
488
#else
489
   BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
490
   BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
491
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
492
#endif
493
}
494
}
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