Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion doc/api_ref/ffi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2021,6 +2021,52 @@ X.509 Certificate Revocation Lists

Load a CRL from a file.

.. cpp:function:: int botan_x509_crl_create(botan_x509_crl_t* crl_obj, \
botan_rng_t rng, \
botan_x509_cert_t ca_cert, \
botan_privkey_t ca_key, \
uint64_t issue_time, \
uint32_t next_update, \
const char* hash_fn, \
const char* padding)

Create a new CRL. ``issue_time`` is expected to be a UNIX timestamp, in seconds.
``next_update`` is the number of seconds after ``issue_time`` until the CRL expires.
``hash_fn`` and ``padding`` may be NULL.

.. cpp:enum:: botan_x509_crl_reason_code

CRL revocation reason codes. Allowed values: `BOTAN_CRL_ENTRY_UNSPECIFIED`,
`BOTAN_CRL_ENTRY_KEY_COMPROMISE`, `BOTAN_CRL_ENTRY_CA_COMPROMISE`, `BOTAN_CRL_ENTRY_AFFILIATION_CHANGED`,
`BOTAN_CRL_ENTRY_SUPERSEDED`, `BOTAN_CRL_ENTRY_CESSATION_OF_OPERATION`, `BOTAN_CRL_ENTRY_CERTIFICATE_HOLD`,
`BOTAN_CRL_ENTRY_REMOVE_FROM_CRL`, `BOTAN_CRL_ENTRY_PRIVILEGE_WITHDRAWN`, `BOTAN_CRL_ENTRY_AA_COMPROMISE`.

.. cpp:function:: int botan_x509_crl_entry_create(botan_x509_crl_entry_t* entry, botan_x509_cert_t cert, int reason_code)

Create a new CRL entry to be added to a CRL later.

.. cpp:function:: int botan_x509_crl_update(botan_x509_crl_t* crl_obj, \
botan_x509_crl_t last_crl, \
botan_rng_t rng, \
botan_x509_cert_t ca_cert, \
botan_privkey_t ca_key, \
uint64_t issue_time, \
uint32_t next_update, \
const botan_x509_crl_entry_t* new_entries, \
size_t new_entries_len, \
const char* hash_fn, \
const char* padding)

Revoke some certificates. This does not update the given CRL in place.
``issue_time`` is expected to be a UNIX timestamp, in seconds.
``next_update`` is the number of seconds after ``issue_time`` until the CRL expires.
``hash_fn`` and ``padding`` may be NULL.
``new_entries`` is an array of ``botan_x509_crl_entry_t`` objects, ``new_entries_len`` is its length.

.. cpp:function:: int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key)

Verify the signature of a CRL. Returns 1 if the signature is valid, 0 otherwise.

.. cpp:function:: int botan_x509_crl_destroy(botan_x509_crl_t crl)

Destroy the CRL object.
Expand Down Expand Up @@ -2101,7 +2147,7 @@ X.509 Certificate Revocation Lists
.. cpp:function:: int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code)

Get the revocation reason code for the given CRL entry. The reason code is
according to `RFC 5280 - 5.3.1 <https://www.rfc-editor.org/rfc/rfc5280#section-5.3.1>`_.
according to `RFC 5280 - 5.3.1 <https://www.rfc-editor.org/rfc/rfc5280#section-5.3.1>`, see :cpp:enum:`botan_x509_crl_reason_code`.

.. cpp:function:: int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch)

Expand Down
75 changes: 74 additions & 1 deletion src/lib/ffi/ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -2550,6 +2550,79 @@ int botan_x509_crl_load(botan_x509_crl_t* crl_obj, const uint8_t crl_bits[], siz
BOTAN_FFI_EXPORT(3, 11) int botan_x509_crl_this_update(botan_x509_crl_t crl, uint64_t* time_since_epoch);
BOTAN_FFI_EXPORT(3, 11) int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch);

/**
* Create a new CRL
* @param crl_obj The newly created CRL
* @param rng a random number generator object
* @param ca_cert The CA Certificate the CRL belongs to
* @param ca_key The private key of that CA
* @param issue_time The time when the CRL becomes valid
* @param next_update The number of seconds after issue_time until the CRL expires
* @param hash_fn The hash function to use, may be null
* @param padding The padding to use, may be null
*/
BOTAN_FFI_EXPORT(3, 11)
int botan_x509_crl_create(botan_x509_crl_t* crl_obj,
botan_rng_t rng,
botan_x509_cert_t ca_cert,
botan_privkey_t ca_key,
uint64_t issue_time,
uint32_t next_update,
const char* hash_fn,
const char* padding);

/* Must match values of CRL_Code in pkix_enums.h */
enum botan_x509_crl_reason_code /* NOLINT(*-enum-size) */ {
BOTAN_CRL_ENTRY_UNSPECIFIED = 0,
BOTAN_CRL_ENTRY_KEY_COMPROMISE = 1,
BOTAN_CRL_ENTRY_CA_COMPROMISE = 2,
BOTAN_CRL_ENTRY_AFFILIATION_CHANGED = 3,
BOTAN_CRL_ENTRY_SUPERSEDED = 4,
BOTAN_CRL_ENTRY_CESSATION_OF_OPERATION = 5,
BOTAN_CRL_ENTRY_CERTIFICATE_HOLD = 6,
BOTAN_CRL_ENTRY_REMOVE_FROM_CRL = 8,
BOTAN_CRL_ENTRY_PRIVILEGE_WITHDRAWN = 9,
BOTAN_CRL_ENTRY_AA_COMPROMISE = 10
};
Comment thread
arckoor marked this conversation as resolved.

/**
* Create a new CRL entry that marks @p cert as revoked
* @param entry The newly created CRL entry
* @param cert The certificate to mark as revoked
* @param reason_code The reason code for revocation
*/
BOTAN_FFI_EXPORT(3, 11)
int botan_x509_crl_entry_create(botan_x509_crl_entry_t* entry, botan_x509_cert_t cert, int reason_code);

/**
* Update a CRL with new revoked entries. This does not modify the old crl, and instead creates a new one.
* @param crl_obj The newly created CRL
* @param last_crl The CRL to update
* @param rng a random number generator object
* @param ca_cert The CA Certificate the CRL belongs to
* @param ca_key The private key of that CA
* @param issue_time The time when the CRL becomes valid
* @param next_update The number of seconds after issue_time until the CRL expires
* @param new_entries The entries to add to the CRL
* @param new_entries_len The number of entries
* @param hash_fn The hash function to use, may be null
* @param padding The padding to use, may be null
*/
BOTAN_FFI_EXPORT(3, 11)
int botan_x509_crl_update(botan_x509_crl_t* crl_obj,
botan_x509_crl_t last_crl,
botan_rng_t rng,
botan_x509_cert_t ca_cert,
botan_privkey_t ca_key,
uint64_t issue_time,
uint32_t next_update,
const botan_x509_crl_entry_t* new_entries,
size_t new_entries_len,
const char* hash_fn,
const char* padding);
Comment thread
arckoor marked this conversation as resolved.

BOTAN_FFI_EXPORT(3, 11) int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key);

BOTAN_FFI_EXPORT(2, 13) int botan_x509_crl_destroy(botan_x509_crl_t crl);

/**
Expand Down Expand Up @@ -2612,7 +2685,7 @@ BOTAN_FFI_EXPORT(3, 11) int botan_x509_crl_entries_count(botan_x509_crl_t crl, s

/**
* Return the revocation reason code for the given CRL @p entry.
* See RFC 5280 - 5.3.1 for possible reason codes.
* See `botan_x509_crl_reason_code` and RFC 5280 - 5.3.1 for possible reason codes.
*/
BOTAN_FFI_EXPORT(3, 11) int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code);

Expand Down
118 changes: 104 additions & 14 deletions src/lib/ffi/ffi_cert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
#include <botan/ffi.h>

#include <botan/assert.h>
#include <botan/internal/ffi_cert.h>
Comment thread
randombit marked this conversation as resolved.
#include <botan/internal/ffi_pkey.h>
#include <botan/internal/ffi_rng.h>
#include <botan/internal/ffi_util.h>
#include <memory>

Expand Down Expand Up @@ -142,6 +144,18 @@ int enumerator_count_values(size_t* count, EnumeratorT fn) {
}
}

std::chrono::system_clock::time_point timepoint_from_timestamp(uint64_t time_since_epoch) {
return std::chrono::system_clock::time_point(std::chrono::seconds(time_since_epoch));
}

std::string default_from_ptr(const char* value) {
std::string ret;
if(value != nullptr) {
ret = value;
}
return ret;
}
Comment thread
arckoor marked this conversation as resolved.

} // namespace

} // namespace Botan_FFI
Expand All @@ -152,13 +166,6 @@ extern "C" {

using namespace Botan_FFI;

#if defined(BOTAN_HAS_X509_CERTIFICATES)

BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
BOTAN_FFI_DECLARE_STRUCT(botan_x509_general_name_struct, Botan::GeneralName, 0x563654FD);

#endif

int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) {
if(cert_obj == nullptr || cert_path == nullptr) {
return BOTAN_FFI_ERROR_NULL_POINTER;
Expand Down Expand Up @@ -1028,13 +1035,6 @@ const char* botan_x509_cert_validation_status(int code) {
#endif
}

#if defined(BOTAN_HAS_X509_CERTIFICATES)

BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_entry_struct, Botan::CRL_Entry, 0x4EAA5346);

#endif

int botan_x509_crl_load_file(botan_x509_crl_t* crl_obj, const char* crl_path) {
if(crl_obj == nullptr || crl_path == nullptr) {
return BOTAN_FFI_ERROR_NULL_POINTER;
Expand Down Expand Up @@ -1105,6 +1105,96 @@ int botan_x509_crl_next_update(botan_x509_crl_t crl, uint64_t* time_since_epoch)
#endif
}

int botan_x509_crl_create(botan_x509_crl_t* crl_obj,
botan_rng_t rng,
botan_x509_cert_t ca_cert,
botan_privkey_t ca_key,
uint64_t issue_time,
uint32_t next_update,
const char* hash_fn,
const char* padding) {
if(Botan::any_null_pointers(crl_obj)) {
return BOTAN_FFI_ERROR_NULL_POINTER;
}
#if defined(BOTAN_HAS_X509_CERTIFICATES)
return ffi_guard_thunk(__func__, [=]() -> int {
auto& rng_ = safe_get(rng);
auto ca = Botan::X509_CA(
safe_get(ca_cert), safe_get(ca_key), default_from_ptr(hash_fn), default_from_ptr(padding), rng_);
auto crl = std::make_unique<Botan::X509_CRL>(
ca.new_crl(rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
return ffi_new_object(crl_obj, std::move(crl));
});
#else
BOTAN_UNUSED(rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update);
return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
}

int botan_x509_crl_entry_create(botan_x509_crl_entry_t* entry, botan_x509_cert_t cert, int reason_code) {
if(Botan::any_null_pointers(entry)) {
return BOTAN_FFI_ERROR_NULL_POINTER;
}
#if defined(BOTAN_HAS_X509_CERTIFICATES)
return ffi_guard_thunk(__func__, [=]() -> int {
return ffi_new_object(
entry, std::make_unique<Botan::CRL_Entry>(safe_get(cert), static_cast<Botan::CRL_Code>(reason_code)));
});
#else
BOTAN_UNUSED(cert, reason_code);
return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
}

int botan_x509_crl_update(botan_x509_crl_t* crl_obj,
botan_x509_crl_t last_crl,
botan_rng_t rng,
botan_x509_cert_t ca_cert,
botan_privkey_t ca_key,
uint64_t issue_time,
uint32_t next_update,
const botan_x509_crl_entry_t* new_entries,
size_t new_entries_len,
const char* hash_fn,
const char* padding) {
if(Botan::any_null_pointers(crl_obj)) {
return BOTAN_FFI_ERROR_NULL_POINTER;
}
if(new_entries_len > 0 && Botan::any_null_pointers(new_entries)) {
return BOTAN_FFI_ERROR_NULL_POINTER;
}
#if defined(BOTAN_HAS_X509_CERTIFICATES)
return ffi_guard_thunk(__func__, [=]() -> int {
auto& rng_ = safe_get(rng);
auto ca = Botan::X509_CA(
safe_get(ca_cert), safe_get(ca_key), default_from_ptr(hash_fn), default_from_ptr(padding), rng_);

std::vector<Botan::CRL_Entry> entries;
entries.reserve(new_entries_len);
for(size_t i = 0; i < new_entries_len; i++) {
entries.push_back(safe_get(new_entries[i]));
}

auto crl = std::make_unique<Botan::X509_CRL>(ca.update_crl(
safe_get(last_crl), entries, rng_, timepoint_from_timestamp(issue_time), std::chrono::seconds(next_update)));
return ffi_new_object(crl_obj, std::move(crl));
});
#else
BOTAN_UNUSED(
last_crl, rng, ca_cert, ca_key, hash_fn, padding, issue_time, next_update, new_entries, new_entries_len);
return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
}

int botan_x509_crl_verify_signature(botan_x509_crl_t crl, botan_pubkey_t key) {
#if defined(BOTAN_HAS_X509_CERTIFICATES)
return BOTAN_FFI_VISIT(crl, [=](const auto& c) -> int { return c.check_signature(safe_get(key)) ? 1 : 0; });
#else
BOTAN_UNUSED(crl, key);
return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
#endif
}

int botan_x509_crl_destroy(botan_x509_crl_t crl) {
#if defined(BOTAN_HAS_X509_CERTIFICATES)
return BOTAN_FFI_CHECKED_DELETE(crl);
Expand Down
31 changes: 31 additions & 0 deletions src/lib/ffi/ffi_cert.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* (C) 2026 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#ifndef BOTAN_FFI_CERT_H_
#define BOTAN_FFI_CERT_H_

#include <botan/internal/ffi_util.h>

#if defined(BOTAN_HAS_X509_CERTIFICATES)
#include <botan/data_src.h>
#include <botan/x509_ca.h>
#include <botan/x509_crl.h>
#include <botan/x509cert.h>
#include <botan/x509path.h>
#endif

extern "C" {
#if defined(BOTAN_HAS_X509_CERTIFICATES)

BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937);
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_struct, Botan::X509_CRL, 0x2C628910);
BOTAN_FFI_DECLARE_STRUCT(botan_x509_crl_entry_struct, Botan::CRL_Entry, 0x4EAA5346);
BOTAN_FFI_DECLARE_STRUCT(botan_x509_general_name_struct, Botan::GeneralName, 0x563654FD);

#endif
}

#endif
1 change: 1 addition & 0 deletions src/lib/ffi/info.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ brief -> "C API for Botan's functionality"
</module_info>

<header:internal>
ffi_cert.h
ffi_ec.h
ffi_mp.h
ffi_oid.h
Expand Down
Loading
Loading