From 8c3dd90284b3394a93edb67592a5e959d6cdc74a Mon Sep 17 00:00:00 2001 From: Rene Meusel Date: Sun, 11 Jan 2026 17:35:08 +0100 Subject: [PATCH] FFI: get serial numbers as botan_mp_t for certs and CRL entries --- doc/api_ref/ffi.rst | 12 ++++++++++-- src/lib/ffi/ffi.h | 7 +++++++ src/lib/ffi/ffi_cert.cpp | 33 +++++++++++++++++++++++++++++++++ src/tests/test_ffi.cpp | 14 +++++++++++++- 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/doc/api_ref/ffi.rst b/doc/api_ref/ffi.rst index f797b0d6e15..e0e250c7ba4 100644 --- a/doc/api_ref/ffi.rst +++ b/doc/api_ref/ffi.rst @@ -1701,7 +1701,11 @@ X.509 Certificates .. cpp:function:: int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) - Return the serial number of the certificate. + Return the serial number of the certificate as big-endian encoded bytes. + +.. cpp:function:: int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) + + Return the serial number of the certificate as a multi-precision integer. .. cpp:function:: int botan_x509_cert_is_ca(botan_x509_cert_t cert) @@ -1985,9 +1989,13 @@ X.509 Certificate Revocation Lists Get the revocation date for the given CRL entry, as seconds since epoch. +.. cpp:function:: int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) + + Get the serial number for the given CRL entry as a multi-precision integer. + .. cpp:function:: int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) - View the serial number for the given CRL entry. + View the serial number for the given CRL entry, as big-endian encoded bytes. .. cpp:function:: int botan_x509_crl_entry_destroy(botan_x509_crl_entry_t entry) diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index 0fa22566799..7d96f26a93d 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -2161,6 +2161,7 @@ BOTAN_FFI_EXPORT(2, 0) int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len); BOTAN_FFI_EXPORT(2, 0) int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); +BOTAN_FFI_EXPORT(3, 11) int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number); BOTAN_FFI_EXPORT(2, 0) int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); BOTAN_FFI_EXPORT(2, 0) int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); @@ -2415,6 +2416,12 @@ BOTAN_FFI_EXPORT(3, 11) int botan_x509_crl_entry_reason(botan_x509_crl_entry_t e BOTAN_FFI_EXPORT(3, 11) int botan_x509_crl_entry_revocation_date(botan_x509_crl_entry_t entry, uint64_t* time_since_epoch); +/** +* Return the serial number associated with the given CRL @p entry. +*/ +BOTAN_FFI_EXPORT(3, 11) +int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number); + /** * View the serial number associated with the given CRL @p entry. */ diff --git a/src/lib/ffi/ffi_cert.cpp b/src/lib/ffi/ffi_cert.cpp index 7709ab04334..96b7e977fa9 100644 --- a/src/lib/ffi/ffi_cert.cpp +++ b/src/lib/ffi/ffi_cert.cpp @@ -15,6 +15,7 @@ #include #include #include + #include #include #endif @@ -273,6 +274,22 @@ int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], siz #endif } +int botan_x509_cert_serial_number(botan_x509_cert_t cert, botan_mp_t* serial_number) { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_VISIT(cert, [=](const Botan::X509_Certificate& c) { + if(Botan::any_null_pointers(serial_number)) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + + auto serial_bn = Botan::BigInt::from_bytes(c.serial_number()); + return ffi_new_object(serial_number, std::make_unique(std::move(serial_bn))); + }); +#else + BOTAN_UNUSED(cert, serial_number); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif +} + int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) { #if defined(BOTAN_HAS_X509_CERTIFICATES) // TODO(Botan4) change the type of out and remove this cast @@ -887,6 +904,22 @@ int botan_x509_crl_entry_reason(botan_x509_crl_entry_t entry, int* reason_code) #endif } +int botan_x509_crl_entry_serial_number(botan_x509_crl_entry_t entry, botan_mp_t* serial_number) { +#if defined(BOTAN_HAS_X509_CERTIFICATES) + return BOTAN_FFI_VISIT(entry, [=](const Botan::CRL_Entry& e) { + if(Botan::any_null_pointers(serial_number)) { + return BOTAN_FFI_ERROR_NULL_POINTER; + } + + auto serial_bn = Botan::BigInt::from_bytes(e.serial_number()); + return ffi_new_object(serial_number, std::make_unique(std::move(serial_bn))); + }); +#else + BOTAN_UNUSED(entry, serial_number); + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif +} + int botan_x509_crl_entry_view_serial_number(botan_x509_crl_entry_t entry, botan_view_ctx ctx, botan_view_bin_fn view) { #if defined(BOTAN_HAS_X509_CERTIFICATES) return BOTAN_FFI_VISIT( diff --git a/src/tests/test_ffi.cpp b/src/tests/test_ffi.cpp index 0ad8bf206eb..e6244aa7d10 100644 --- a/src/tests/test_ffi.cpp +++ b/src/tests/test_ffi.cpp @@ -732,6 +732,7 @@ class FFI_CRL_Test final : public FFI_Test { botan_x509_cert_t cert2; std::vector cert2_serial; + botan_mp_t cert2_serial_bn; size_t cert2_serial_len = 0; REQUIRE_FFI_OK(botan_x509_cert_load_file, (&cert2, Test::data_file("x509/nist/test20/int.crt").c_str())); TEST_FFI_RC(0, botan_x509_is_revoked, (crl, cert2)); @@ -741,6 +742,7 @@ class FFI_CRL_Test final : public FFI_Test { (cert2, nullptr, &cert2_serial_len)); cert2_serial.resize(cert2_serial_len); TEST_FFI_OK(botan_x509_cert_get_serial_number, (cert2, cert2_serial.data(), &cert2_serial_len)); + TEST_FFI_OK(botan_x509_cert_serial_number, (cert2, &cert2_serial_bn)); TEST_FFI_OK(botan_x509_cert_destroy, (cert2)); size_t entries; @@ -749,14 +751,20 @@ class FFI_CRL_Test final : public FFI_Test { TEST_FFI_OK(botan_x509_crl_entries_count, (bytecrl, &entries)); result.test_eq("no revoked cert", entries, 0); + ViewBytesSink serial; + TEST_FFI_OK(botan_mp_view_bin, (cert2_serial_bn, serial.delegate(), serial.callback())); + result.test_eq("serial == serial_bn", serial.get(), cert2_serial); + TEST_FFI_OK(botan_mp_destroy, (cert2_serial_bn)); + botan_x509_crl_entry_t entry; TEST_FFI_OK(botan_x509_crl_entries, (crl, 0, &entry)); - ViewBytesSink serial; uint64_t ts; int reason; + botan_mp_t entry_serial_bn; TEST_FFI_OK(botan_x509_crl_entry_view_serial_number, (entry, serial.delegate(), serial.callback())); + TEST_FFI_OK(botan_x509_crl_entry_serial_number, (entry, &entry_serial_bn)); TEST_FFI_OK(botan_x509_crl_entry_revocation_date, (entry, &ts)); TEST_FFI_OK(botan_x509_crl_entry_reason, (entry, &reason)); TEST_FFI_OK(botan_x509_crl_entry_destroy, (entry)); @@ -766,6 +774,10 @@ class FFI_CRL_Test final : public FFI_Test { result.test_is_eq("Revocation time", ts, Botan::calendar_point(1999, 1, 1, 12, 0, 0).seconds_since_epoch()); result.test_eq("Revoked cert serial", serial.get(), cert2_serial); + TEST_FFI_OK(botan_mp_view_bin, (entry_serial_bn, serial.delegate(), serial.callback())); + result.test_eq("Revoked cert serial_bn", serial.get(), cert2_serial); + TEST_FFI_OK(botan_mp_destroy, (entry_serial_bn)); + TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE, botan_x509_crl_entries, (crl, 1, &entry)); TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE, botan_x509_crl_entries, (bytecrl, 0, &entry));