[BACK]Return to misc.c CVS log [TXT][DIR] Up to [local] / acopm / lib / utils

File: [local] / acopm / lib / utils / misc.c (download)

Revision 1.1, Sat May 8 15:42:18 2021 UTC (3 years ago) by bountyht
Branch point for: MAIN

Initial revision

/*
 * Copyright (C) 2017 Aaron M. D. Jones <aaronmdjones@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "acopm-common.h"

#include <assert.h> /* assert() */
#include <errno.h> /* errno */
#include <fcntl.h> /* open() */
#include <string.h> /* strerror() */
#include <unistd.h> /* close() */

#ifdef BUILD_WITH_MBEDTLS
#  ifdef MBEDTLS_CONFIG_FILE
#    include MBEDTLS_CONFIG_FILE
#  else
#    include <mbedtls/config.h> /* MBEDTLS_*_C */
#  endif
#  ifdef MBEDTLS_CTR_DRBG_C
#    include <mbedtls/ctr_drbg.h> /* mbedtls_ctr_drbg_context, mbedtls_ctr_drbg_*() */
#  endif
#  ifdef MBEDTLS_HMAC_DRBG_C
#    include <mbedtls/hmac_drbg.h> /* mbedtls_hmac_drbg_context, mbedtls_hmac_drbg_*() */
#  endif
#  include <mbedtls/entropy.h> /* mbedtls_entropy_context, mbedtls_entropy_*() */
#  include <mbedtls/error.h> /* mbedtls_strerror() */
#endif /* BUILD_WITH_MBEDTLS */

#include "utils/log.h" /* acopm_log_*() */
#include "utils/misc.h" /* decls for own functions */

static const char acopm_rng_randchars[62] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
static bool acopm_rng_init_done = false;



#ifdef BUILD_WITH_MBEDTLS

#if !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_HMAC_DRBG_C)
#  error "When using MbedTLS, at least one of CTR-DRBG or HMAC-DRBG must be enabled"
#endif

#if !defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C)
#  error "When using MbedTLS without CTR-DRBG, at least one of SHA-2/256 or SHA-2/512 must be enabled"
#endif

#ifdef MBEDTLS_CTR_DRBG_C
#  define ACOPM_RNG_STR_MAX MBEDTLS_CTR_DRBG_MAX_REQUEST
#else
#  define ACOPM_RNG_STR_MAX MBEDTLS_HMAC_DRBG_MAX_REQUEST
#endif

static const unsigned char acopm_drbg_pstring[] = "ACOPM/RNG DRBG Personalisation String";

#ifdef MBEDTLS_CTR_DRBG_C
static mbedtls_ctr_drbg_context acopm_rng_drbg_ctx;
#else
static mbedtls_hmac_drbg_context acopm_rng_drbg_ctx;
#endif

static mbedtls_entropy_context acopm_rng_ent_ctx;

bool
acopm_rng_init(void)
{
	assert(acopm_rng_init_done == false);

	(void) acopm_log_debug("%s: initialising random number generator", __func__);

	(void) mbedtls_entropy_init(&acopm_rng_ent_ctx);

#ifdef MBEDTLS_CTR_DRBG_C
	(void) mbedtls_ctr_drbg_init(&acopm_rng_drbg_ctx);

	const int ret = mbedtls_ctr_drbg_seed(
		&acopm_rng_drbg_ctx, mbedtls_entropy_func, &acopm_rng_ent_ctx,
		acopm_drbg_pstring, sizeof acopm_drbg_pstring
	);
#else

#  ifdef MBEDTLS_SHA512_C
	const mbedtls_md_type_t md_type = MBEDTLS_MD_SHA512;
#  else
	const mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
#  endif

	const mbedtls_md_info_t *const md_info = mbedtls_md_info_from_type(md_type);

	if (! md_info)
	{
		(void) acopm_log_error("%s: md_info_from_type(%u) failed", __func__, (unsigned int) md_type);
		return false;
	}

	(void) mbedtls_hmac_drbg_init(&acopm_rng_drbg_ctx);

	const int ret = mbedtls_hmac_drbg_seed(
		&acopm_rng_drbg_ctx, md_info, mbedtls_entropy_func, &acopm_rng_ent_ctx,
		acopm_drbg_pstring, sizeof acopm_drbg_pstring
	);
#endif

	if (ret != 0)
	{
		(void) acopm_log_error("%s: drbg_seed: %s", __func__, acopm_mbed_strerror(ret));
		return false;
	}

	acopm_rng_init_done = true;
	return true;
}

void
acopm_rng_free(void)
{
	assert(acopm_rng_init_done == true);

	(void) acopm_log_debug("%s: destroying random number generator", __func__);

#ifdef MBEDTLS_CTR_DRBG_C
	(void) mbedtls_ctr_drbg_free(&acopm_rng_drbg_ctx);
#else
	(void) mbedtls_hmac_drbg_free(&acopm_rng_drbg_ctx);
#endif
	(void) mbedtls_entropy_free(&acopm_rng_ent_ctx);

	acopm_rng_init_done = false;
}

bool
acopm_rng_buf(void *const restrict buf, const size_t len)
{
	assert(acopm_rng_init_done == true);
	assert(buf != NULL);
	assert(len > 0);

	assert(len <= ACOPM_RNG_STR_MAX);

#ifdef MBEDTLS_CTR_DRBG_C
	const int ret = mbedtls_ctr_drbg_random(&acopm_rng_drbg_ctx, buf, len);
#else
	const int ret = mbedtls_hmac_drbg_random(&acopm_rng_drbg_ctx, buf, len);
#endif

	if (ret != 0)
	{
		(void) acopm_log_error("%s: ctr_drbg_random: %s", __func__, acopm_mbed_strerror(ret));
		return false;
	}

	return true;
}

bool
acopm_rng_str(char *const restrict buf, const size_t len)
{
	assert(acopm_rng_init_done == true);
	assert(buf != NULL);
	assert(len > 0);
	assert(len <= ACOPM_RNG_STR_MAX);

	unsigned char tmp[ACOPM_RNG_STR_MAX];

	if (! acopm_rng_buf(tmp, len))
		return false;

	for (size_t x = 0; x < len; x++)
		buf[x] = acopm_rng_randchars[tmp[x] % sizeof acopm_rng_randchars];

	buf[len] = 0x00;
	return true;
}

int
acopm_rng_tls(void *const restrict context, unsigned char *const restrict buf, const size_t len)
{
	(void) context;

	assert(acopm_rng_init_done == true);
	assert(context == NULL);
	assert(buf != NULL);
	assert(len > 0);
	assert(len <= ACOPM_RNG_STR_MAX);

#ifdef MBEDTLS_CTR_DRBG_C
	const int ret = mbedtls_ctr_drbg_random(&acopm_rng_drbg_ctx, buf, len);
#else
	const int ret = mbedtls_hmac_drbg_random(&acopm_rng_drbg_ctx, buf, len);
#endif

	if (ret != 0)
		(void) acopm_log_error("%s: ctr_drbg_random: %s", __func__, acopm_mbed_strerror(ret));

	return ret;
}

const char *
acopm_mbed_strerror(const int err)
{
	const unsigned int err_pos = ((err < 0) ? (unsigned int) -err : (unsigned int) err);

	static char buf[4096];

#ifdef MBEDTLS_ERROR_C
	char tmp[1024];
	(void) mbedtls_strerror(err, tmp, sizeof tmp);
	(void) snprintf(buf, sizeof buf, "-0x%X (%s)", err_pos, tmp);
#else
	(void) snprintf(buf, sizeof buf, "-0x%X", err_pos);
#endif

	return buf;
}



#else /* BUILD_WITH_MBEDTLS */



#define ACOPM_RNG_STR_MAX 64

static int random_fd = -1;

bool
acopm_rng_init(void)
{
	assert(acopm_rng_init_done == false);

	(void) acopm_log_debug("%s: initialising random number generator", __func__);

	if (random_fd == -1 && (random_fd = open("/dev/urandom", O_RDONLY)) == -1)
	{
		(void) acopm_log_error("%s: open: %s", __func__, strerror(errno));
		return false;
	}

	acopm_rng_init_done = true;
	return true;
}

void
acopm_rng_free(void)
{
	assert(acopm_rng_init_done == true);

	(void) acopm_log_debug("%s: destroying random number generator", __func__);

	(void) close(random_fd);
	random_fd = -1;

	acopm_rng_init_done = false;
}

bool
acopm_rng_buf(void *const restrict buf, const size_t len)
{
	assert(acopm_rng_init_done == true);
	assert(buf != NULL);
	assert(len > 0);

	unsigned char *dest = (unsigned char *) buf;
	size_t done = 0;
	ssize_t result = 0;

	while ((done < len) && (result = read(random_fd, dest, (len - done))) > 0)
	{
		dest += (size_t) result;
		done += (size_t) result;
	}
	if (result == -1)
	{
		(void) acopm_log_error("%s: read: %s", __func__, strerror(errno));
		return false;
	}
	if (result == 0)
	{
		(void) acopm_log_error("%s: read: EOF", __func__);
		return false;
	}

	return true;
}

bool
acopm_rng_str(char *const restrict buf, const size_t len)
{
	assert(acopm_rng_init_done == true);
	assert(buf != NULL);
	assert(len > 0);
	assert(len <= ACOPM_RNG_STR_MAX);

	unsigned char tmp[ACOPM_RNG_STR_MAX];

	if (! acopm_rng_buf(tmp, len))
		return false;

	for (size_t x = 0; x < len; x++)
		buf[x] = acopm_rng_randchars[tmp[x] % sizeof acopm_rng_randchars];

	buf[len] = 0x00;
	return true;
}



#endif /* BUILD_WITH_MBEDTLS */