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). > > No problem! > > 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 = 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 = { .ident = "Software, HMAC DRBG, NIST 800-90A", .init = random_hmac_drbg_init, .deinit = random_hmac_drbg_deinit, .block = random_hmac_drbg_block, .read = random_hmac_drbg_read, .poll = random_hmac_drbg_poll, .reseed = random_hmac_drbg_reseed, .seeded = 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 = 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) != 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 += event->bits; if (random_hmac_drbg_ecount >= 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 = hmac_drbg_init(&drbg_ctx, NULL); KASSERT(error == 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 = 0; mtx_lock(&drbg_mtx); while (!random_hmac_drbg.seeded && !error) { if (flag & O_NONBLOCK) error = EWOULDBLOCK; else { printf("Entropy device is blocking.\n"); error = 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 = hmac_drbg_get_bytes(&drbg_ctx, buf, count); KASSERT(error != -1, ("hmac_drbg_get_bytes() failure: %d\n", error)); mtx_unlock(&drbg_mtx); return(error != -1 ? count : 0); } static void random_hmac_drbg_write(void *buf, int count) { int error; mtx_lock(&drbg_mtx); error = hmac_drbg_update(&drbg_ctx, buf, count); KASSERT(error == 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 = 0; mtx_lock(&drbg_mtx); if (random_hmac_drbg.seeded) revents = 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 = 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); -- Arthur Mesh <am...@juniper.net> Juniper Networks +1 408 936-4968
pgp_tB5_CRwr2.pgp
Description: PGP signature