mbedtls: add

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2025-06-17 16:45:29 +02:00
parent 7aa64cb625
commit 214e307486

219
include/stdex/mbedtls.hpp Normal file
View File

@ -0,0 +1,219 @@
/*
SPDX-License-Identifier: MIT
Copyright © 2016-2025 Amebis
*/
#pragma once
#include "compat.hpp"
#include "exception.hpp"
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdocumentation-deprecated-sync"
#endif
#include <mbedtls/bignum.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/pk.h>
#include <mbedtls/x509_crt.h>
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#ifdef MBEDTLS_USE_PSA_CRYPTO
#include <psa/crypto.h>
#endif
#if !defined(_WIN32)
#include <stdio.h>
#include <unistd.h>
#endif
#include <stdexcept>
namespace stdex
{
namespace mbedtls
{
///
/// MbedTLS runtime error
///
class runtime_error : public stdex::num_runtime_error<int>
{
public:
///
/// Constructs an exception
///
/// \param[in] num MbedTLS error code
///
runtime_error(error_type num) : stdex::num_runtime_error<int>(num, message(num))
{
}
///
/// Constructs an exception
///
/// \param[in] num MbedTLS error code
/// \param[in] msg Error message
///
runtime_error(error_type num, const std::string &msg) : stdex::num_runtime_error<int>(num, msg + ": " + message(num))
{
}
///
/// Constructs an exception
///
/// \param[in] num MbedTLS error code
/// \param[in] msg Error message
///
runtime_error(error_type num, const char *msg) : stdex::num_runtime_error<int>(num, std::string(msg) + ": " + message(num))
{
}
protected:
///
/// Returns a string explaining the meaning of a security result code
///
/// \sa [mbedtls_strerror function](https://mbed-ce.github.io/mbed-os/group__mbedtls__errors.html#ga8c41c149b77a4807115b19c2af858558)
///
static std::string message(error_type num)
{
char buf[1024];
memset(buf, 0, sizeof(buf));
mbedtls_strerror(num, buf, sizeof(buf));
return buf;
}
};
///
/// MbedTLS entropy context
///
class entropy_context : public mbedtls_entropy_context
{
public:
///
/// Initializes MbedTLS entropy context
///
/// \sa [mbedtls_entropy_init](https://mbed-ce.github.io/mbed-os/group__mbedtls__entropy__module.html#gaa901e027093c6fe65dee5760db78aced)
///
entropy_context()
{
mbedtls_entropy_init(this);
#if !defined(_WIN32) && defined(MBEDTLS_FS_IO)
int ret = mbedtls_entropy_add_source(this, dev_random_entropy_poll, NULL, 32, MBEDTLS_ENTROPY_SOURCE_STRONG);
if (ret != 0)
throw runtime_error(ret, "mbedtls_entropy_add_source failed");
#endif
}
///
/// Frees MbedTLS entropy context
///
/// \sa [mbedtls_entropy_free](https://mbed-ce.github.io/mbed-os/group__mbedtls__entropy__module.html#ga06778439f8a0e2daa2d3b444e06ad8dd)
///
~entropy_context()
{
mbedtls_entropy_free(this);
}
protected:
#if !defined(_WIN32) && defined(MBEDTLS_FS_IO)
static int dev_random_entropy_poll(void* data, unsigned char* output, size_t len, size_t* olen)
{
_Unreferenced_(data);
*olen = 0;
FILE* file = fopen("/dev/random", "rb");
if (file == NULL)
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
size_t left = len;
unsigned char* p = output;
while (left) {
// /dev/random can return much less than requested. If so, try again.
size_t ret = fread(p, 1, left, file);
if (ret == 0 && ferror(file)) {
fclose(file);
return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
}
p += ret;
left -= ret;
if (!left)
break;
sleep(1);
}
fclose(file);
*olen = len;
return 0;
}
#endif
};
///
/// The MbedTLS CTR_DRBG context structure
///
struct ctr_drbg_context : public mbedtls_ctr_drbg_context
{
ctr_drbg_context() { mbedtls_ctr_drbg_init(this); }
~ctr_drbg_context() { mbedtls_ctr_drbg_free(this); }
};
///
/// MbedTLS MPI
///
struct mpi : public mbedtls_mpi
{
mpi() { mbedtls_mpi_init(this); }
~mpi() { mbedtls_mpi_free(this); }
};
///
/// MbedTLS public key container
///
struct pk_context : public mbedtls_pk_context
{
pk_context() { mbedtls_pk_init(this); }
~pk_context() { mbedtls_pk_free(this); }
};
///
/// MbedTLS container for an X.509 certificate
///
struct x509_crt : public mbedtls_x509_crt
{
x509_crt() { mbedtls_x509_crt_init(this); }
~x509_crt() { mbedtls_x509_crt_free(this); }
};
///
/// MbedTLS Container for writing a certificate (CRT)
///
struct x509write_cert : public mbedtls_x509write_cert
{
x509write_cert() { mbedtls_x509write_crt_init(this); }
~x509write_cert() { mbedtls_x509write_crt_free(this); }
};
///
/// MbedTLS global initializer
///
class initializer
{
public:
///
/// Initializes MbedTLS library
///
initializer()
{
#ifdef MBEDTLS_USE_PSA_CRYPTO
auto status = psa_crypto_init();
if (status != PSA_SUCCESS)
throw runtime_error("Failed to initialize PSA Crypto implementation");
#endif
}
~initializer()
{
#ifdef MBEDTLS_USE_PSA_CRYPTO
mbedtls_psa_crypto_free();
#endif
}
};
}
}