Botan  2.15.0
Crypto and TLS for C++11
ffi_cert.cpp
Go to the documentation of this file.
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 #include <botan/internal/ffi_util.h>
9 #include <botan/internal/ffi_pkey.h>
10 
11 #if defined(BOTAN_HAS_X509_CERTIFICATES)
12  #include <botan/x509cert.h>
13  #include <botan/x509path.h>
14  #include <botan/x509_crl.h>
15  #include <botan/data_src.h>
16 #endif
17 
18 extern "C" {
19 
20 using namespace Botan_FFI;
21 
22 #if defined(BOTAN_HAS_X509_CERTIFICATES)
23 
24 BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
25 
26 #endif
27 
28 int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path)
29  {
30  if(!cert_obj || !cert_path)
32 
33 #if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
34 
35  return ffi_guard_thunk(__func__, [=]() -> int {
36  std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(cert_path));
37  *cert_obj = new botan_x509_cert_struct(c.release());
38  return BOTAN_FFI_SUCCESS;
39  });
40 
41 #else
43 #endif
44  }
45 
47  {
48  if(!cert_obj)
50 
51 #if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
52 
53  return ffi_guard_thunk(__func__, [=]() -> int {
54  std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(safe_get(cert)));
55  *cert_obj = new botan_x509_cert_struct(c.release());
56  return BOTAN_FFI_SUCCESS;
57  });
58 
59 #else
60  BOTAN_UNUSED(cert);
62 #endif
63  }
64 
65 int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len)
66  {
67  if(!cert_obj || !cert_bits)
69 
70 #if defined(BOTAN_HAS_X509_CERTIFICATES)
71  return ffi_guard_thunk(__func__, [=]() -> int {
72  Botan::DataSource_Memory bits(cert_bits, cert_bits_len);
73  std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(bits));
74  *cert_obj = new botan_x509_cert_struct(c.release());
75  return BOTAN_FFI_SUCCESS;
76  });
77 #else
78  BOTAN_UNUSED(cert_bits_len);
80 #endif
81  }
82 
84  {
85  if(key == nullptr)
87 
88  *key = nullptr;
89 
90 #if defined(BOTAN_HAS_X509_CERTIFICATES)
91  return ffi_guard_thunk(__func__, [=]() -> int {
92  std::unique_ptr<Botan::Public_Key> publicKey = safe_get(cert).load_subject_public_key();
93  *key = new botan_pubkey_struct(publicKey.release());
94  return BOTAN_FFI_SUCCESS;
95  });
96 #else
97  BOTAN_UNUSED(cert);
99 #endif
100  }
101 
103  const char* key, size_t index,
104  uint8_t out[], size_t* out_len)
105  {
106 #if defined(BOTAN_HAS_X509_CERTIFICATES)
107  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.issuer_info(key).at(index)); });
108 #else
109  BOTAN_UNUSED(cert, key, index, out, out_len);
111 #endif
112  }
113 
115  const char* key, size_t index,
116  uint8_t out[], size_t* out_len)
117  {
118 #if defined(BOTAN_HAS_X509_CERTIFICATES)
119  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.subject_info(key).at(index)); });
120 #else
121  BOTAN_UNUSED(cert, key, index, out, out_len);
123 #endif
124  }
125 
126 int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len)
127  {
128 #if defined(BOTAN_HAS_X509_CERTIFICATES)
129  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.to_string()); });
130 #else
131  BOTAN_UNUSED(cert, out, out_len);
133 #endif
134  }
135 
136 int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage)
137  {
138 #if defined(BOTAN_HAS_X509_CERTIFICATES)
140  const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage);
141  if(c.allowed_usage(k))
142  return BOTAN_FFI_SUCCESS;
143  return 1;
144  });
145 #else
146  BOTAN_UNUSED(cert, key_usage);
148 #endif
149  }
150 
152  {
153 #if defined(BOTAN_HAS_X509_CERTIFICATES)
154  return BOTAN_FFI_CHECKED_DELETE(cert);
155 #else
156  BOTAN_UNUSED(cert);
158 #endif
159  }
160 
161 int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len)
162  {
163 #if defined(BOTAN_HAS_X509_CERTIFICATES)
164  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.not_before().to_string()); });
165 #else
166  BOTAN_UNUSED(cert, out, out_len);
168 #endif
169  }
170 
171 int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len)
172  {
173 #if defined(BOTAN_HAS_X509_CERTIFICATES)
174  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.not_after().to_string()); });
175 #else
176  BOTAN_UNUSED(cert, out, out_len);
178 #endif
179  }
180 
181 int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t* time_since_epoch)
182  {
183 #if defined(BOTAN_HAS_X509_CERTIFICATES)
184  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, {
185  *time_since_epoch = c.not_before().time_since_epoch();
186  });
187 #else
188  BOTAN_UNUSED(cert, time_since_epoch);
190 #endif
191  }
192 
193 int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t* time_since_epoch)
194  {
195 #if defined(BOTAN_HAS_X509_CERTIFICATES)
196  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, {
197  *time_since_epoch = c.not_after().time_since_epoch();
198  });
199 #else
200  BOTAN_UNUSED(cert, time_since_epoch);
202 #endif
203  }
204 
205 int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
206  {
207 #if defined(BOTAN_HAS_X509_CERTIFICATES)
208  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.serial_number()); });
209 #else
210  BOTAN_UNUSED(cert, out, out_len);
212 #endif
213  }
214 
215 int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len)
216  {
217 #if defined(BOTAN_HAS_X509_CERTIFICATES)
218  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_str_output(out, out_len, c.fingerprint(hash)); });
219 #else
220  BOTAN_UNUSED(cert, hash, out, out_len);
222 #endif
223  }
224 
225 int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
226  {
227 #if defined(BOTAN_HAS_X509_CERTIFICATES)
228  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.authority_key_id()); });
229 #else
230  BOTAN_UNUSED(cert, out, out_len);
232 #endif
233  }
234 
235 int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
236  {
237 #if defined(BOTAN_HAS_X509_CERTIFICATES)
238  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_key_id()); });
239 #else
240  BOTAN_UNUSED(cert, out, out_len);
242 #endif
243  }
244 
245 int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len)
246  {
247 #if defined(BOTAN_HAS_X509_CERTIFICATES)
248  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c, { return write_vec_output(out, out_len, c.subject_public_key_bits()); });
249 #else
250  BOTAN_UNUSED(cert, out, out_len);
252 #endif
253  }
254 
255 int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char* hostname)
256  {
257  if(hostname == nullptr)
259 
260 #if defined(BOTAN_HAS_X509_CERTIFICATES)
261  return BOTAN_FFI_DO(Botan::X509_Certificate, cert, c,
262  { return c.matches_dns_name(hostname) ? 0 : -1; });
263 #else
264  BOTAN_UNUSED(cert);
266 #endif
267  }
268 
269 int botan_x509_cert_verify(int* result_code,
270  botan_x509_cert_t cert,
271  const botan_x509_cert_t* intermediates,
272  size_t intermediates_len,
273  const botan_x509_cert_t* trusted,
274  size_t trusted_len,
275  const char* trusted_path,
276  size_t required_strength,
277  const char* hostname_cstr,
278  uint64_t reference_time)
279  {
280  if(required_strength == 0)
281  required_strength = 110;
282 
283 #if defined(BOTAN_HAS_X509_CERTIFICATES)
284  return ffi_guard_thunk(__func__, [=]() -> int {
285  const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
287  const auto validation_time = reference_time == 0 ?
288  std::chrono::system_clock::now() :
289  std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
290 
291  std::vector<Botan::X509_Certificate> end_certs;
292  end_certs.push_back(safe_get(cert));
293  for(size_t i = 0; i != intermediates_len; ++i)
294  end_certs.push_back(safe_get(intermediates[i]));
295 
296  std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
297  std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
298  std::vector<Botan::Certificate_Store*> trusted_roots;
299 
300  if(trusted_path && *trusted_path)
301  {
302  trusted_from_path.reset(new Botan::Certificate_Store_In_Memory(trusted_path));
303  trusted_roots.push_back(trusted_from_path.get());
304  }
305 
306  if(trusted_len > 0)
307  {
308  trusted_extra.reset(new Botan::Certificate_Store_In_Memory);
309  for(size_t i = 0; i != trusted_len; ++i)
310  {
311  trusted_extra->add_certificate(safe_get(trusted[i]));
312  }
313  trusted_roots.push_back(trusted_extra.get());
314  }
315 
316  Botan::Path_Validation_Restrictions restrictions(false, required_strength);
317 
318  auto validation_result = Botan::x509_path_validate(end_certs,
319  restrictions,
320  trusted_roots,
321  hostname,
322  usage,
323  validation_time);
324 
325  if(result_code)
326  *result_code = static_cast<int>(validation_result.result());
327 
328  if(validation_result.successful_validation())
329  return 0;
330  else
331  return 1;
332  });
333 #else
334  BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
335  BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time);
337 #endif
338  }
339 
341  {
342  if(code < 0)
343  return nullptr;
344 
345 #if defined(BOTAN_HAS_X509_CERTIFICATES)
347  return Botan::to_string(sc);
348 #else
349  return nullptr;
350 #endif
351  }
352 
353 #if defined(BOTAN_HAS_X509_CERTIFICATES)
354 
355 BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
356 
357 #endif
358 
359 int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path)
360  {
361  if(!crl_obj || !crl_path)
363 
364 #if defined(BOTAN_HAS_X509_CERTIFICATES) && defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
365 
366  return ffi_guard_thunk(__func__, [=]() -> int {
367  std::unique_ptr<Botan::X509_CRL> c(new Botan::X509_CRL(crl_path));
368  *crl_obj = new botan_x509_crl_struct(c.release());
369  return BOTAN_FFI_SUCCESS;
370  });
371 
372 #else
374 #endif
375  }
376 
377 int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], size_t crl_bits_len)
378  {
379  if(!crl_obj || !crl_bits)
381 
382 #if defined(BOTAN_HAS_X509_CERTIFICATES)
383  return ffi_guard_thunk(__func__, [=]() -> int {
384  Botan::DataSource_Memory bits(crl_bits, crl_bits_len);
385  std::unique_ptr<Botan::X509_CRL> c(new Botan::X509_CRL(bits));
386  *crl_obj = new botan_x509_crl_struct(c.release());
387  return BOTAN_FFI_SUCCESS;
388  });
389 #else
390  BOTAN_UNUSED(crl_bits_len);
392 #endif
393  }
394 
396  {
397 #if defined(BOTAN_HAS_X509_CERTIFICATES)
398  return BOTAN_FFI_CHECKED_DELETE(crl);
399 #else
400  BOTAN_UNUSED(crl);
402 #endif
403  }
404 
406  {
407 #if defined(BOTAN_HAS_X509_CERTIFICATES)
408  return BOTAN_FFI_RETURNING(Botan::X509_CRL, crl, c, {
409  return c.is_revoked(safe_get(cert)) ? 0 : -1;
410  });
411 #else
412  BOTAN_UNUSED(cert);
413  BOTAN_UNUSED(crl);
415 #endif
416  }
417 
419  int* result_code,
420  botan_x509_cert_t cert,
421  const botan_x509_cert_t* intermediates,
422  size_t intermediates_len,
423  const botan_x509_cert_t* trusted,
424  size_t trusted_len,
425  const botan_x509_crl_t* crls,
426  size_t crls_len,
427  const char* trusted_path,
428  size_t required_strength,
429  const char* hostname_cstr,
430  uint64_t reference_time)
431  {
432  if(required_strength == 0)
433  required_strength = 110;
434 
435 #if defined(BOTAN_HAS_X509_CERTIFICATES)
436  return ffi_guard_thunk(__func__, [=]() -> int {
437  const std::string hostname((hostname_cstr == nullptr) ? "" : hostname_cstr);
439  const auto validation_time = reference_time == 0 ?
440  std::chrono::system_clock::now() :
441  std::chrono::system_clock::from_time_t(static_cast<time_t>(reference_time));
442 
443  std::vector<Botan::X509_Certificate> end_certs;
444  end_certs.push_back(safe_get(cert));
445  for(size_t i = 0; i != intermediates_len; ++i)
446  end_certs.push_back(safe_get(intermediates[i]));
447 
448  std::unique_ptr<Botan::Certificate_Store> trusted_from_path;
449  std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_extra;
450  std::unique_ptr<Botan::Certificate_Store_In_Memory> trusted_crls;
451  std::vector<Botan::Certificate_Store*> trusted_roots;
452 
453  if(trusted_path && *trusted_path)
454  {
455  trusted_from_path.reset(new Botan::Certificate_Store_In_Memory(trusted_path));
456  trusted_roots.push_back(trusted_from_path.get());
457  }
458 
459  if(trusted_len > 0)
460  {
461  trusted_extra.reset(new Botan::Certificate_Store_In_Memory);
462  for(size_t i = 0; i != trusted_len; ++i)
463  {
464  trusted_extra->add_certificate(safe_get(trusted[i]));
465  }
466  trusted_roots.push_back(trusted_extra.get());
467  }
468 
469  if(crls_len > 0)
470  {
471  trusted_crls.reset(new Botan::Certificate_Store_In_Memory);
472  for(size_t i = 0; i != crls_len; ++i)
473  {
474  trusted_crls->add_crl(safe_get(crls[i]));
475  }
476  trusted_roots.push_back(trusted_crls.get());
477  }
478 
479  Botan::Path_Validation_Restrictions restrictions(false, required_strength);
480 
481  auto validation_result = Botan::x509_path_validate(end_certs,
482  restrictions,
483  trusted_roots,
484  hostname,
485  usage,
486  validation_time);
487 
488  if(result_code)
489  *result_code = static_cast<int>(validation_result.result());
490 
491  if(validation_result.successful_validation())
492  return 0;
493  else
494  return 1;
495  });
496 #else
497  BOTAN_UNUSED(result_code, cert, intermediates, intermediates_len, trusted);
498  BOTAN_UNUSED(trusted_len, trusted_path, hostname_cstr, reference_time, crls, crls_len);
500 #endif
501  }
502 
503 }
int ffi_guard_thunk(const char *func_name, std::function< int()> thunk)
Definition: ffi.cpp:89
int botan_x509_cert_destroy(botan_x509_cert_t cert)
Definition: ffi_cert.cpp:151
int botan_x509_cert_load(botan_x509_cert_t *cert_obj, const uint8_t cert_bits[], size_t cert_bits_len)
Definition: ffi_cert.cpp:65
int botan_x509_is_revoked(botan_x509_crl_t crl, botan_x509_cert_t cert)
Definition: ffi_cert.cpp:405
int botan_x509_crl_load(botan_x509_crl_t *crl_obj, const uint8_t crl_bits[], size_t crl_bits_len)
Definition: ffi_cert.cpp:377
int botan_x509_cert_not_before(botan_x509_cert_t cert, uint64_t *time_since_epoch)
Definition: ffi_cert.cpp:181
int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t *out_len)
Definition: ffi_cert.cpp:225
int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t *out_len)
Definition: ffi_cert.cpp:161
int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t *out_len)
Definition: ffi_cert.cpp:245
int botan_x509_cert_verify_with_crl(int *result_code, botan_x509_cert_t cert, const botan_x509_cert_t *intermediates, size_t intermediates_len, const botan_x509_cert_t *trusted, size_t trusted_len, const botan_x509_crl_t *crls, size_t crls_len, const char *trusted_path, size_t required_strength, const char *hostname_cstr, uint64_t reference_time)
Definition: ffi_cert.cpp:418
int write_vec_output(uint8_t out[], size_t *out_len, const std::vector< uint8_t, Alloc > &buf)
Definition: ffi_util.h:155
bool matches_dns_name(const std::string &name) const
Definition: x509cert.cpp:780
int botan_x509_cert_dup(botan_x509_cert_t *cert_obj, botan_x509_cert_t cert)
Definition: ffi_cert.cpp:46
std::string to_string(ErrorType type)
Convert an ErrorType to string.
Definition: exceptn.cpp:11
int write_str_output(uint8_t out[], size_t *out_len, const std::string &str)
Definition: ffi_util.h:160
int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t *key)
Definition: ffi_cert.cpp:83
int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t *out_len)
Definition: ffi_cert.cpp:235
const X509_Time & not_after() const
Definition: x509cert.cpp:406
struct botan_x509_cert_struct * botan_x509_cert_t
Definition: ffi.h:1506
int botan_x509_cert_load_file(botan_x509_cert_t *cert_obj, const char *cert_path)
Definition: ffi_cert.cpp:28
int botan_x509_crl_destroy(botan_x509_crl_t crl)
Definition: ffi_cert.cpp:395
int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t *out_len)
Definition: ffi_cert.cpp:205
struct botan_x509_crl_struct * botan_x509_crl_t
Definition: ffi.h:1600
#define BOTAN_FFI_RETURNING(T, obj, param, block)
Definition: ffi_util.h:101
#define BOTAN_FFI_CHECKED_DELETE(o)
Definition: ffi_util.h:129
Path_Validation_Result x509_path_validate(const std::vector< X509_Certificate > &end_certs, const Path_Validation_Restrictions &restrictions, const std::vector< Certificate_Store *> &trusted_roots, const std::string &hostname, Usage_Type usage, std::chrono::system_clock::time_point ref_time, std::chrono::milliseconds ocsp_timeout, const std::vector< std::shared_ptr< const OCSP::Response >> &ocsp_resp)
Definition: x509path.cpp:846
#define BOTAN_UNUSED(...)
Definition: assert.h:142
int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char *hash, uint8_t out[], size_t *out_len)
Definition: ffi_cert.cpp:215
int botan_x509_cert_verify(int *result_code, botan_x509_cert_t cert, const botan_x509_cert_t *intermediates, size_t intermediates_len, const botan_x509_cert_t *trusted, size_t trusted_len, const char *trusted_path, size_t required_strength, const char *hostname_cstr, uint64_t reference_time)
Definition: ffi_cert.cpp:269
T & safe_get(botan_struct< T, M > *p)
Definition: ffi_util.h:61
int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert, const char *key, size_t index, uint8_t out[], size_t *out_len)
Definition: ffi_cert.cpp:114
const X509_Time & not_before() const
Definition: x509cert.cpp:401
uint64_t time_since_epoch() const
Return time since epoch.
Definition: asn1_time.cpp:266
#define BOTAN_FFI_DECLARE_STRUCT(NAME, TYPE, MAGIC)
Definition: ffi_util.h:53
int botan_x509_cert_not_after(botan_x509_cert_t cert, uint64_t *time_since_epoch)
Definition: ffi_cert.cpp:193
int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage)
Definition: ffi_cert.cpp:136
int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t *out_len)
Definition: ffi_cert.cpp:126
int botan_x509_crl_load_file(botan_x509_crl_t *crl_obj, const char *crl_path)
Definition: ffi_cert.cpp:359
Certificate_Status_Code
Definition: cert_status.h:18
struct botan_pubkey_struct * botan_pubkey_t
Definition: ffi.h:1098
int botan_x509_cert_hostname_match(botan_x509_cert_t cert, const char *hostname)
Definition: ffi_cert.cpp:255
#define BOTAN_FFI_DO(T, obj, param, block)
Definition: ffi_util.h:92
MechanismType hash
int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t *out_len)
Definition: ffi_cert.cpp:171
Usage_Type
Definition: x509cert.h:25
bool is_revoked(const X509_Certificate &cert) const
Definition: x509_crl.cpp:76
const char * botan_x509_cert_validation_status(int code)
Definition: ffi_cert.cpp:340
int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert, const char *key, size_t index, uint8_t out[], size_t *out_len)
Definition: ffi_cert.cpp:102