Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 2 Jul 2015 12:28:19 -0700
From:      Arthur Mesh <amesh@juniper.net>
To:        Mark R V Murray <markm@freebsd.org>
Cc:        "Simon J. Gerraty" <sjg@juniper.net>, <src-committers@freebsd.org>, <svn-src-all@freebsd.org>, <svn-src-head@freebsd.org>, <stevek@juniper.net>
Subject:   Re: svn commit: r284959 - in head: . share/man/man4 share/man/man9 sys/conf sys/dev/glxsb sys/dev/hifn sys/dev/random sys/dev/rndtest sys/dev/safe sys/dev/syscons sys/dev/ubsec sys/dev/virtio/random sy...
Message-ID:  <20150702192819.GL90166@juniper.net>
In-Reply-To: <0B29F349-FB7C-4B71-A792-CE304FF72206@FreeBSD.org>
References:  <201506301700.t5UH0jPq001498@svn.freebsd.org> <13981.1435792025@chaos> <5238A439-F25E-40F1-96D4-140460003982@FreeBSD.org> <22423.1435862187@chaos> <20150702184255.GH90166@juniper.net> <0B29F349-FB7C-4B71-A792-CE304FF72206@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
--Og24Z7r1sh+tVSZX
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Thu, Jul 02, 2015 at 08:21:31PM +0100, Mark R V Murray wrote:
> > I.e., if the box is configured to boot in FIPS mode, it should use NIST
> > SP800-90 HMAC-DRBG adaptor. Otherwise, it uses the default FreeBSD
> > adaptor (Fortuna I guess).
>=20
> No problem!
>=20
> Could you please let me know your implementation???s API? If I have that,
> or at least an approximation, I can make a framework in which you can
> insert your code.

Sure, Here is the shim between HMAC_DRBG and struct random_adaptor (that
used to plug-in before removal on 2015/6/30).

/*
 * $Id: $
 *
 * Copyright (c) 2014, Juniper Networks, Inc.
 * All rights reserved.
 */

#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/poll.h>
#include <sys/random.h>
#include <sys/sysctl.h>
#include <sys/selinfo.h>

#include <opencrypto/cryptodev.h>
#include <opencrypto/xform.h>
#include <dev/random/randomdev.h>
#include <dev/random/randomdev_soft.h>
#include <dev/random/random_harvestq.h>
#include <dev/random/random_adaptors.h>

#include "hmac.h"
#include "hmac_shim.h"
#include "hmac_drbg.h"
#include "hmac_drbg_adaptor.h"
#include "health_tests.h"
#include "debug.h"

/*
 * The context mutex protects the consistency of the hmac_drbg state
 */
struct mtx drbg_mtx;

static int hmac_drbg_security_level =3D 256;

/*
 * hmac_drbg context
 */
static struct random_hmac_drbg_s drbg_ctx;

static void random_hmac_drbg_init(void);
static void random_hmac_drbg_deinit(void);
static int random_hmac_drbg_block(int);
static int random_hmac_drbg_read(void *, int);
static void random_hmac_drbg_write(void *, int);
static int random_hmac_drbg_poll(int, struct thread *);
static void random_hmac_drbg_reseed(void);
void random_hmac_drbg_unblock(void);

struct random_adaptor random_hmac_drbg =3D {
	.ident =3D "Software, HMAC DRBG, NIST 800-90A",
	.init =3D random_hmac_drbg_init,
	.deinit =3D random_hmac_drbg_deinit,
	.block =3D random_hmac_drbg_block,
	.read =3D random_hmac_drbg_read,
	.poll =3D random_hmac_drbg_poll,
	.reseed =3D random_hmac_drbg_reseed,
	.seeded =3D 0,
};

/* entropy bit counter */
uint64_t random_hmac_drbg_ecount;

void
random_hmac_drbg_unblock(void)
{

	if (!random_hmac_drbg.seeded) {
		random_hmac_drbg.seeded =3D 1;
		selwakeuppri(&random_hmac_drbg.rsel, PUSER);
		wakeup(&random_hmac_drbg);
	}
}

static void
hmac_drbg_process_event(struct harvest *event)
{

	/* If entropy health test fails, discard the entropy */
	if (entropy_health_test(event) !=3D 0) {
		return;
	}

	/*
	 * Feed noise in to our DRBG.
	 * Performance optimization: even though not all fields in event are
	 * entropic, it's much faster to call random_hmac_drbg_write() on the
	 * whole struct, vs calling random_hmac_drbg_write() separately for
	 * event->somecounter and event->entropy.
	 */
	random_hmac_drbg_write(event, sizeof(*event));

	random_hmac_drbg_ecount +=3D event->bits;

	if (random_hmac_drbg_ecount >=3D hmac_drbg_security_level)
		random_hmac_drbg_unblock(); /* Unblock random(4) */
}

void
random_hmac_drbg_init(void)
{
	int error;

	mtx_init(&drbg_mtx, "hmac_drbg context mutex", NULL, MTX_DEF);
	error =3D hmac_drbg_init(&drbg_ctx, NULL);
	KASSERT(error =3D=3D 0, ("hmac_drbg_init() failure: %d\n", error));

	random_harvestq_init(hmac_drbg_process_event);

	/* Register the randomness harvesting routine */
	randomdev_init_harvester(random_harvestq_internal,
	    random_hmac_drbg_read);
}

static void
random_hmac_drbg_deinit(void)
{

	mtx_destroy(&drbg_mtx);
}

static int
random_hmac_drbg_block(int flag)
{
	int error =3D 0;

	mtx_lock(&drbg_mtx);

	while (!random_hmac_drbg.seeded && !error) {
		if (flag & O_NONBLOCK)
			error =3D EWOULDBLOCK;
		else {
			printf("Entropy device is blocking.\n");
			error =3D msleep(&random_hmac_drbg,
			    &drbg_mtx, PUSER | PCATCH, "block", 0);
		}
	}

	mtx_unlock(&drbg_mtx);

	return (error);
}

static int
random_hmac_drbg_read(void *buf, int count)
{
	int error;

	mtx_lock(&drbg_mtx);

	error =3D hmac_drbg_get_bytes(&drbg_ctx, buf, count);
	KASSERT(error !=3D -1, ("hmac_drbg_get_bytes() failure: %d\n",
	    error));

	mtx_unlock(&drbg_mtx);

	return(error !=3D -1 ? count : 0);
}

static void
random_hmac_drbg_write(void *buf, int count)
{
	int error;

	mtx_lock(&drbg_mtx);

	error =3D hmac_drbg_update(&drbg_ctx, buf, count);
	KASSERT(error =3D=3D 0, ("hmac_drbg_update() failure: %d\n", error));

	mtx_unlock(&drbg_mtx);
}

static int
random_hmac_drbg_poll(int events, struct thread *td)
{
	int revents =3D 0;
	mtx_lock(&drbg_mtx);

	if (random_hmac_drbg.seeded)
		revents =3D events & (POLLIN | POLLRDNORM);
	else
		selrecord(td, &random_hmac_drbg.rsel);

	mtx_unlock(&drbg_mtx);

	return (revents);
}

static void
random_hmac_drbg_reseed(void)
{

	/* Command a entropy queue flush and wait for it to finish */
	random_kthread_control =3D 1;
	while (random_kthread_control)
		pause("-", hz / 10);

}

static int
random_hmac_drbg_modevent(module_t mod, int type, void *unused)
{
	switch(type) {
	case MOD_LOAD:
		/* Initialize health tests */
		health_tests_init();

		random_adaptor_register("hmac-drbg", &random_hmac_drbg);
		/*
		 * For statically built kernels that contain both device
		 * random and options PADLOCK_RNG/RDRAND_RNG/etc..,
		 * this event handler will do nothing, since the random
		 * driver-specific handlers are loaded after these HW
		 * consumers, and hence hasn't yet registered for this event.
		 *
		 * In case where both the random driver and RNG's are built
		 * as seperate modules, random.ko is loaded prior to *_rng.ko's
		 * (by dependency). This event handler is there to delay
		 * creation of /dev/{u,}random and attachment of this *_rng.ko.
		 */
		EVENTHANDLER_INVOKE(random_adaptor_attach, &random_hmac_drbg);

		return (0);
	}

	return (EINVAL);
}

RANDOM_ADAPTOR_MODULE(random_hmac_drbg, random_hmac_drbg_modevent, 1);

--=20
Arthur Mesh <amesh@juniper.net>
Juniper Networks
+1 408 936-4968

--Og24Z7r1sh+tVSZX
Content-Type: application/pgp-signature

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iQGcBAABCAAGBQJVlZDSAAoJEAi6IWerhQY4CtwMAJQZR9oh8NW1lfEwiG7OL8j4
ntEbj1OGN8sZlkicYd5ak8VHElMi3zISEBrg3P9ayYyvHXte4fSpAP9mWin7UIHk
7IRHeYwJVc7HwnAhfoAY7dFa3s2OLmK7vSJ45OpqDR9UFHOXoxP6xYfBE+1G5Wqj
oZ+5zV0BUquH7BmS8yuItSdP3uediudFkHr4umMfxzCC9Dxkt2gC6UVKryATezr/
4QfVNsxMFvZJMowAt0tbJzZdFvRY+EcvlNLeRQadqeK4fIJKuQjtav84AA6YibyI
egJ1e03qp2O0FRrUQi8zinNV7DslTCQYpRrWO2x9nNR3tfyz2ZWJQBdYSAzklGhE
3PKJJrx7TGQFYgbyj0qzz0fAFvcHYqnp13zcTdflPjfLywgWzK/LzezJUmFWYrPA
H+UMHSSptYhb9WXNGRSmcwiV9ZQhReehOiyx00t+De/1GBJF/k5glSeG+3eUqR9S
jRpH8apyUNvRhQW2uc2dOjQd1mUmnTJ+TEidR43c2g==
=wkT8
-----END PGP SIGNATURE-----

--Og24Z7r1sh+tVSZX--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150702192819.GL90166>