Blame lib/nettle/rnd-fips.c

Packit Service 4684c1
/*
Packit Service 4684c1
 * Copyright (C) 2013-2017 Red Hat
Packit Service 4684c1
 *
Packit Service 4684c1
 * This file is part of GnuTLS.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Libgcrypt is free software; you can redistribute it and/or modify
Packit Service 4684c1
 * it under the terms of the GNU Lesser General Public License as
Packit Service 4684c1
 * published by the Free Software Foundation; either version 2.1 of
Packit Service 4684c1
 * the License, or (at your option) any later version.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Libgcrypt is distributed in the hope that it will be useful,
Packit Service 4684c1
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 4684c1
 * GNU Lesser General Public License for more details.
Packit Service 4684c1
 *
Packit Service 4684c1
 * You should have received a copy of the GNU Lesser General Public
Packit Service 4684c1
 * License along with this program; if not, see <https://www.gnu.org/licenses/>.
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
#include <config.h>
Packit Service 4684c1
#include <stdio.h>
Packit Service 4684c1
#include <stdlib.h>
Packit Service 4684c1
#include <errno.h>
Packit Service 4684c1
#include <sys/types.h>
Packit Service 4684c1
#include <drbg-aes.h>
Packit Service 4684c1
#include <fips.h>
Packit Service 4684c1
Packit Service 4684c1
#include "gnutls_int.h"
Packit Service 4684c1
#include "errors.h"
Packit Service 4684c1
#include <nettle/sha2.h>
Packit Service 4684c1
#include <atfork.h>
Packit Service 4684c1
#include <rnd-common.h>
Packit Service 4684c1
Packit Service 4684c1
/* The block size is chosen arbitrarily */
Packit Service 4684c1
#define ENTROPY_BLOCK_SIZE SHA256_DIGEST_SIZE
Packit Service 4684c1
Packit Service 4684c1
/* This provides a random generator for gnutls. It uses
Packit Service 4684c1
 * two instances of the DRBG-AES-CTR generator, one for
Packit Service 4684c1
 * nonce level and another for the other levels of randomness.
Packit Service 4684c1
 */
Packit Service 4684c1
struct fips_ctx {
Packit Service 4684c1
	struct drbg_aes_ctx nonce_context;
Packit Service 4684c1
	struct drbg_aes_ctx normal_context;
Packit Service 4684c1
	unsigned int forkid;
Packit Service 4684c1
	uint8_t entropy_hash[SHA256_DIGEST_SIZE];
Packit Service 4684c1
};
Packit Service 4684c1
Packit Service 4684c1
static int _rngfips_ctx_reinit(struct fips_ctx *fctx);
Packit Service 4684c1
static int _rngfips_ctx_init(struct fips_ctx *fctx);
Packit Service 4684c1
static int drbg_reseed(struct fips_ctx *fctx, struct drbg_aes_ctx *ctx);
Packit Service 4684c1
static int get_entropy(struct fips_ctx *fctx, uint8_t *buffer, size_t length);
Packit Service 4684c1
Packit Service 4684c1
static int get_random(struct drbg_aes_ctx *ctx, struct fips_ctx *fctx,
Packit Service 4684c1
		      void *buffer, size_t length)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	if ( _gnutls_detect_fork(fctx->forkid) != 0) {
Packit Service 4684c1
		ret = _rngfips_ctx_reinit(fctx);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	if (ctx->reseed_counter > DRBG_AES_RESEED_TIME) {
Packit Service 4684c1
		ret = drbg_reseed(fctx, ctx);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = drbg_aes_random(ctx, length, buffer);
Packit Service 4684c1
	if (ret == 0)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int get_entropy(struct fips_ctx *fctx, uint8_t *buffer, size_t length)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	uint8_t block[ENTROPY_BLOCK_SIZE];
Packit Service 4684c1
	uint8_t hash[SHA256_DIGEST_SIZE];
Packit Service 4684c1
	struct sha256_ctx ctx;
Packit Service 4684c1
	size_t total = 0;
Packit Service 4684c1
Packit Service 4684c1
	/* For FIPS 140-2 4.9.2 continuous random number generator
Packit Service 4684c1
	 * test, iteratively fetch fixed sized block from the system
Packit Service 4684c1
	 * RNG and compare consecutive blocks.
Packit Service 4684c1
	 *
Packit Service 4684c1
	 * Note that we store the hash of the entropy block rather
Packit Service 4684c1
	 * than the block itself for backward secrecy.
Packit Service 4684c1
	 */
Packit Service 4684c1
	while (total < length) {
Packit Service 4684c1
		ret = _rnd_get_system_entropy(block, ENTROPY_BLOCK_SIZE);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
		sha256_init(&ctx;;
Packit Service 4684c1
		sha256_update(&ctx, sizeof(block), block);
Packit Service 4684c1
		sha256_digest(&ctx, sizeof(hash), hash);
Packit Service 4684c1
Packit Service 4684c1
		if (memcmp(hash, fctx->entropy_hash, sizeof(hash)) == 0) {
Packit Service 4684c1
			_gnutls_switch_lib_state(LIB_STATE_ERROR);
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
Packit Service 4684c1
		}
Packit Service 4684c1
		memcpy(fctx->entropy_hash, hash, sizeof(hash));
Packit Service 4684c1
Packit Service 4684c1
		memcpy(buffer, block, MIN(length - total, sizeof(block)));
Packit Service 4684c1
		total += sizeof(block);
Packit Service 4684c1
		buffer += sizeof(block);
Packit Service 4684c1
	}
Packit Service 4684c1
	zeroize_key(block, sizeof(block));
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
#define PSTRING "gnutls-rng"
Packit Service 4684c1
#define PSTRING_SIZE (sizeof(PSTRING)-1)
Packit Service 4684c1
static int drbg_init(struct fips_ctx *fctx, struct drbg_aes_ctx *ctx)
Packit Service 4684c1
{
Packit Service 4684c1
	uint8_t buffer[DRBG_AES_SEED_SIZE];
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	ret = get_entropy(fctx, buffer, sizeof(buffer));
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	ret = drbg_aes_init(ctx, sizeof(buffer), buffer,
Packit Service 4684c1
			    PSTRING_SIZE, (void*)PSTRING);
Packit Service 4684c1
	zeroize_key(buffer, sizeof(buffer));
Packit Service 4684c1
	if (ret == 0)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
Packit Service 4684c1
Packit Service 4684c1
	return GNUTLS_E_SUCCESS;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Reseed a generator. */
Packit Service 4684c1
static int drbg_reseed(struct fips_ctx *fctx, struct drbg_aes_ctx *ctx)
Packit Service 4684c1
{
Packit Service 4684c1
	uint8_t buffer[DRBG_AES_SEED_SIZE];
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	ret = get_entropy(fctx, buffer, sizeof(buffer));
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	ret = drbg_aes_reseed(ctx, sizeof(buffer), buffer, 0, NULL);
Packit Service 4684c1
	zeroize_key(buffer, sizeof(buffer));
Packit Service 4684c1
	if (ret == 0)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
Packit Service 4684c1
Packit Service 4684c1
	return GNUTLS_E_SUCCESS;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int _rngfips_ctx_init(struct fips_ctx *fctx)
Packit Service 4684c1
{
Packit Service 4684c1
	uint8_t block[ENTROPY_BLOCK_SIZE];
Packit Service 4684c1
	struct sha256_ctx ctx;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	/* For FIPS 140-2 4.9.2 continuous random number generator
Packit Service 4684c1
	 * test, get the initial entropy from the system RNG and keep
Packit Service 4684c1
	 * it for comparison.
Packit Service 4684c1
	 *
Packit Service 4684c1
	 * Note that we store the hash of the entropy block rather
Packit Service 4684c1
	 * than the block itself for backward secrecy.
Packit Service 4684c1
	 */
Packit Service 4684c1
	ret = _rnd_get_system_entropy(block, sizeof(block));
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
	sha256_init(&ctx;;
Packit Service 4684c1
	sha256_update(&ctx, sizeof(block), block);
Packit Service 4684c1
	zeroize_key(block, sizeof(block));
Packit Service 4684c1
	sha256_digest(&ctx, sizeof(fctx->entropy_hash), fctx->entropy_hash);
Packit Service 4684c1
Packit Service 4684c1
	/* normal */
Packit Service 4684c1
	ret = drbg_init(fctx, &fctx->normal_context);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	/* nonce */
Packit Service 4684c1
	ret = drbg_init(fctx, &fctx->nonce_context);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	fctx->forkid = _gnutls_get_forkid();
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int _rngfips_ctx_reinit(struct fips_ctx *fctx)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	/* normal */
Packit Service 4684c1
	ret = drbg_reseed(fctx, &fctx->normal_context);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	/* nonce */
Packit Service 4684c1
	ret = drbg_reseed(fctx, &fctx->nonce_context);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	fctx->forkid = _gnutls_get_forkid();
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/* Initialize this random subsystem. */
Packit Service 4684c1
static int _rngfips_init(void **_ctx)
Packit Service 4684c1
{
Packit Service 4684c1
/* Basic initialization is required to
Packit Service 4684c1
   do a few checks on the implementation.  */
Packit Service 4684c1
	struct fips_ctx *ctx;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	ctx = gnutls_calloc(1, sizeof(*ctx));
Packit Service 4684c1
	if (ctx == NULL)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit Service 4684c1
Packit Service 4684c1
	ret = _rngfips_ctx_init(ctx);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_free(ctx);
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	*_ctx = ctx;
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int _rngfips_rnd(void *_ctx, int level, void *buffer, size_t length)
Packit Service 4684c1
{
Packit Service 4684c1
	struct fips_ctx *ctx = _ctx;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	switch (level) {
Packit Service 4684c1
	case GNUTLS_RND_RANDOM:
Packit Service 4684c1
	case GNUTLS_RND_KEY:
Packit Service 4684c1
		/* Unlike the chacha generator in rnd.c we do not need
Packit Service 4684c1
		 * to explicitly protect against backtracking in GNUTLS_RND_KEY
Packit Service 4684c1
		 * level. This protection is part of the DRBG generator. */
Packit Service 4684c1
		ret = get_random(&ctx->normal_context, ctx, buffer, length);
Packit Service 4684c1
		break;
Packit Service 4684c1
	default:
Packit Service 4684c1
		ret = get_random(&ctx->nonce_context, ctx, buffer, length);
Packit Service 4684c1
		break;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static void _rngfips_deinit(void *_ctx)
Packit Service 4684c1
{
Packit Service 4684c1
	struct fips_ctx *ctx = _ctx;
Packit Service 4684c1
Packit Service 4684c1
	zeroize_key(ctx, sizeof(*ctx));
Packit Service 4684c1
	free(ctx);
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static void _rngfips_refresh(void *_ctx)
Packit Service 4684c1
{
Packit Service 4684c1
	/* this is predictable RNG. Don't refresh */
Packit Service 4684c1
	return;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int selftest_kat(void)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	ret = drbg_aes_self_test();
Packit Service 4684c1
Packit Service 4684c1
	if (ret == 0) {
Packit Service 4684c1
		_gnutls_debug_log("DRBG-AES self test failed\n");
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_RANDOM_FAILED);
Packit Service 4684c1
	} else
Packit Service 4684c1
		_gnutls_debug_log("DRBG-AES self test succeeded\n");
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
gnutls_crypto_rnd_st _gnutls_fips_rnd_ops = {
Packit Service 4684c1
	.init = _rngfips_init,
Packit Service 4684c1
	.deinit = _rngfips_deinit,
Packit Service 4684c1
	.rnd = _rngfips_rnd,
Packit Service 4684c1
	.rnd_refresh = _rngfips_refresh,
Packit Service 4684c1
	.self_test = selftest_kat,
Packit Service 4684c1
};
Packit Service 4684c1