Mercurial > illumos > illumos-gate
changeset 8029:d7695059e7a6
6703956 Solaris cryptographic framework needs a FIPS-186-2 certifiable RNG
author | Hai-May Chao <Hai-May.Chao@Sun.COM> |
---|---|
date | Thu, 06 Nov 2008 16:52:01 -0800 |
parents | cd6790ddf574 |
children | 2b963e8d757a |
files | usr/src/common/crypto/rng/fips_random.c usr/src/common/crypto/rng/fips_random.h usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/crypto/api/kcf_random.c usr/src/uts/common/crypto/io/swrand.c usr/src/uts/common/sys/random.h usr/src/uts/intel/swrand/Makefile usr/src/uts/sparc/swrand/Makefile usr/src/uts/sun4v/io/n2rng/n2rng_provider.c usr/src/uts/sun4v/n2rng/Makefile |
diffstat | 11 files changed, 370 insertions(+), 298 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/common/crypto/rng/fips_random.c Thu Nov 06 16:52:01 2008 -0800 @@ -0,0 +1,137 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <sys/types.h> +#include <rng/fips_random.h> +#include <sys/sha1.h> + +/* + * Adds val1 and val2 and stores result into sum. The various input + * pointers can be exactly aliased. (They cannot be offset and + * overlapping, but no one would ever do that.) Values are big endian + * by words and native byte order within words. The return value's + * 2-bit is 0 if the result is zero, it's 1 bit is carry out. (This + * is reused code. The return code is not used by n2rng.) Thus, + * calling with both carryin and complement_val2 ones does a + * subtraction. A null sum pointer parameter is allowed. The + * subtraction features were required when this code was orginally + * written so it could do a mod q operation. + */ +static int +fips_add160(uint32_t *sum, uint32_t const *val1, uint32_t const *val2, + const unsigned carryin, const int complement_val2) +{ + int i; + uint32_t partialsum; + uint32_t carry = (carryin > 0); + uint32_t non_zero = 0; + + for (i = 4; i >= 0; --i) { + partialsum = val1[i] + (complement_val2 ? ~val2[i] : val2[i]) + + carry; + if (carry) { + carry = (partialsum <= val1[i]); + } else { + carry = (partialsum < val1[i]); + } + if (sum) { + sum[i] = partialsum; + } + non_zero |= partialsum; + } + + return (((non_zero != 0) * 2) | carry); +} + +/* + * Computes a new random value, which is stored in x_j; updates + * XKEY. XSEED_j is additional input. In principle, we should + * protect XKEY, perhaps by putting it on a non-pagable page, but we + * aways clobber XKEY with fresh entropy just before we use it. And + * step 3d irreversibly updates it just after we use it. The only + * risk is that if an attacker captured the state while the entropy + * generator was broken, the attacker could predict future values. + * There are two cases: 1. The attack gets root access to a live + * system. But there is no defense against that. 2. The attacker + * gets access to a crash dump. But by then no values are being + * generated. + * + * Note that XSEEDj is overwritten with sensitive stuff, and must be + * zeroed by the caller. We use two separate symbols (XVAL and + * XSEEDj) to make each step match the notation in FIPS 186-2. + */ +void +fips_random_inner(uint32_t *key, uint32_t *x_j, + uint32_t *XSEED_j) +{ + int i; + SHA1_CTX sha1_context; + /* Alias to preserve terminology from FIPS 186-2 */ +#define XVAL XSEED_j + /* + * K&R section A8.7: If the array has fixed size, the number + * of initializers may not exceed the number of members in the + * array; if there are fewer, the trailing members are + * initialized with 0. + */ + static const char zero[SHA1BLOCKBYTES - SHA1BYTES] = {0}; + + /* + * Step 3b: XVAL = (XKEY + XSEED_sub_j) mod 2^b. The mod is + * implicit in the 160 bit representation. Note that XVAL and + * XSEED_j are actually the same location. + */ + (void) fips_add160(XVAL, key, XSEED_j, 0, 0); + /* + * Step 3c: x_sub_j = G(t, XVAL). + */ + SHA1Init(&sha1_context); + SHA1Update(&sha1_context, (unsigned char *)XVAL, SHA1BYTES); + /* + * Filling to 64 bytes is requried by FIPS 186-2 Appendix 3.3. + * It also triggers SHA1Transform (the steps a-e of the spec). + * + * zero is a const char[], but SHA1update does not declare its + * second parameter const, even though it does not modify it, + * so we cast to suppress a compiler warning. + */ + SHA1Update(&sha1_context, (unsigned char *)zero, + SHA1BLOCKBYTES - SHA1BYTES); + /* + * The code below directly accesses the state field of + * sha1_context, which is of type SHA1_CTX, defined in sha1.h. + */ + /* copy out to x_j */ + for (i = 0; i < 5; i++) { + x_j[i] = sha1_context.state[i]; + } + /* + * Step 3d: XKEY = (1 + XKEY + x_sub_j) mod 2^b. b=160. The + * mod 2^160 is implicit in the 160 bit representation. The + * one is added via the carry-in flag. + */ + (void) fips_add160(key, key, x_j, 1, 0); +#undef XVAL +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usr/src/common/crypto/rng/fips_random.h Thu Nov 06 16:52:01 2008 -0800 @@ -0,0 +1,47 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef _COMMON_CRYPTO_FIPS_RANDOM_H +#define _COMMON_CRYPTO_FIPS_RANDOM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +#define SHA1BLOCKBITS 512 +#define SHA1BLOCKBYTES (SHA1BLOCKBITS >> 3) +#define SHA1WORDS 5 +#define BYTES_IN_WORD 4 +#define SHA1BYTES (BYTES_IN_WORD * SHA1WORDS) + +extern void fips_random_inner(uint32_t *, uint32_t *, uint32_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _COMMON_CRYPTO_FIPS_RANDOM_H */
--- a/usr/src/uts/common/Makefile.files Thu Nov 06 15:40:19 2008 -0800 +++ b/usr/src/uts/common/Makefile.files Thu Nov 06 16:52:01 2008 -0800 @@ -1370,7 +1370,7 @@ kcf_keys.o kcf_mac.o kcf_mech_tabs.o kcf_miscapi.o \ kcf_object.o kcf_policy.o kcf_prov_lib.o kcf_prov_tabs.o \ kcf_sched.o kcf_session.o kcf_sign.o kcf_spi.o kcf_verify.o \ - kcf_random.o modes.o ecb.o cbc.o ctr.o ccm.o gcm.o + kcf_random.o modes.o ecb.o cbc.o ctr.o ccm.o gcm.o fips_random.o CRYPTOADM_OBJS += cryptoadm.o
--- a/usr/src/uts/common/Makefile.rules Thu Nov 06 15:40:19 2008 -0800 +++ b/usr/src/uts/common/Makefile.rules Thu Nov 06 16:52:01 2008 -0800 @@ -60,6 +60,10 @@ $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(COMMONBASE)/crypto/rng/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(COMMONBASE)/crypto/rsa/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -1258,6 +1262,9 @@ $(LINTS_DIR)/%.ln: $(COMMONBASE)/crypto/modes/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(COMMONBASE)/crypto/rng/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(COMMONBASE)/crypto/rsa/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL))
--- a/usr/src/uts/common/crypto/api/kcf_random.c Thu Nov 06 15:40:19 2008 -0800 +++ b/usr/src/uts/common/crypto/api/kcf_random.c Thu Nov 06 16:52:01 2008 -0800 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * This file implements the interfaces that the /dev/random * driver uses for read(2), write(2) and poll(2) on /dev/random or @@ -44,9 +42,9 @@ * kmem-magazine-style, to avoid cache line contention. * * LOCKING HIERARCHY: - * 1) rmp->rm_lock protects the per-cpu pseudo-random generators. + * 1) rmp->rm_mag.rm_lock protects the per-cpu pseudo-random generators. * 2) rndpool_lock protects the high-quality randomness pool. - * It may be locked while a rmp->rm_lock is held. + * It may be locked while a rmp->rm_mag.rm_lock is held. * * A history note: The kernel API and the software-based algorithms in this * file used to be part of the /dev/random driver. @@ -68,6 +66,7 @@ #include <sys/sysmacros.h> #include <sys/cpuvar.h> #include <sys/taskq.h> +#include <rng/fips_random.h> #define RNDPOOLSIZE 1024 /* Pool size in bytes */ #define MINEXTRACTBYTES 20 @@ -95,16 +94,6 @@ /* HMAC-SHA1 */ #define HMAC_KEYSIZE 20 -#define HMAC_BLOCK_SIZE 64 -#define HMAC_KEYSCHED sha1keysched_t -#define SET_ENCRYPT_KEY(k, s, ks) hmac_key((k), (s), (ks)) -#define HMAC_ENCRYPT(ks, p, s, d) hmac_encr((ks), (uint8_t *)(p), s, d) - -/* HMAC-SHA1 "keyschedule" */ -typedef struct sha1keysched_s { - SHA1_CTX ictx; - SHA1_CTX octx; -} sha1keysched_t; /* * Cache of random bytes implemented as a circular buffer. findex and rindex @@ -130,9 +119,6 @@ static void rndc_getbytes(uint8_t *ptr, size_t len); static void rnd_handler(void *); static void rnd_alloc_magazines(); -static void hmac_key(uint8_t *, size_t, void *); -static void hmac_encr(void *, uint8_t *, size_t, uint8_t *); - void kcf_rnd_init() @@ -577,11 +563,9 @@ * of cache-line-padding structures. */ #define RND_CPU_CACHE_SIZE 64 -#define RND_CPU_PAD_SIZE RND_CPU_CACHE_SIZE*5 +#define RND_CPU_PAD_SIZE RND_CPU_CACHE_SIZE*6 #define RND_CPU_PAD (RND_CPU_PAD_SIZE - \ - (sizeof (kmutex_t) + 3*sizeof (uint8_t *) + sizeof (HMAC_KEYSCHED) + \ - sizeof (uint64_t) + 3*sizeof (uint32_t) + sizeof (rnd_stats_t))) - + sizeof (rndmag_t)) /* * Per-CPU random state. Somewhat like like kmem's magazines, this provides * a per-CPU instance of the pseudo-random generator. We have it much easier @@ -599,18 +583,24 @@ uint8_t *rm_buffer; /* Start of buffer */ uint8_t *rm_eptr; /* End of buffer */ uint8_t *rm_rptr; /* Current read pointer */ - HMAC_KEYSCHED rm_ks; /* seed */ - uint64_t rm_counter; /* rotating counter for extracting */ uint32_t rm_oblocks; /* time to rekey? */ uint32_t rm_ofuzz; /* Rekey backoff state */ uint32_t rm_olimit; /* Hard rekey limit */ rnd_stats_t rm_stats; /* Per-CPU Statistics */ - uint8_t rm_pad[RND_CPU_PAD]; + uint32_t rm_key[SHA1WORDS]; /* FIPS XKEY */ + uint32_t rm_seed[SHA1WORDS]; /* seed for rekey */ + uint32_t rm_previous[SHA1WORDS]; /* previous random bytes */ } rndmag_t; +typedef struct rndmag_pad_s +{ + rndmag_t rm_mag; + uint8_t rm_pad[RND_CPU_PAD]; +} rndmag_pad_t; + /* - * Generate random bytes for /dev/urandom by encrypting a - * rotating counter with a key created from bytes extracted + * Generate random bytes for /dev/urandom by applying the + * FIPS 186-2 algorithm with a key created from bytes extracted * from the pool. A maximum of PRNG_MAXOBLOCKS output blocks * is generated before a new key is obtained. * @@ -619,30 +609,32 @@ * Called with rmp locked; releases lock. */ static int -rnd_generate_pseudo_bytes(rndmag_t *rmp, uint8_t *ptr, size_t len) +rnd_generate_pseudo_bytes(rndmag_pad_t *rmp, uint8_t *ptr, size_t len) { size_t bytes = len; int nblock, size; uint32_t oblocks; - uint8_t digest[HASHSIZE]; + uint32_t tempout[SHA1WORDS]; + uint32_t seed[SHA1WORDS]; + int i; + hrtime_t timestamp; + uint8_t *src, *dst; - ASSERT(mutex_owned(&rmp->rm_lock)); + ASSERT(mutex_owned(&rmp->rm_mag.rm_lock)); /* Nothing is being asked */ if (len == 0) { - mutex_exit(&rmp->rm_lock); + mutex_exit(&rmp->rm_mag.rm_lock); return (0); } nblock = howmany(len, HASHSIZE); - rmp->rm_oblocks += nblock; - oblocks = rmp->rm_oblocks; + rmp->rm_mag.rm_oblocks += nblock; + oblocks = rmp->rm_mag.rm_oblocks; do { - if (oblocks >= rmp->rm_olimit) { - hrtime_t timestamp; - uint8_t key[HMAC_KEYSIZE]; + if (oblocks >= rmp->rm_mag.rm_olimit) { /* * Contention-avoiding rekey: see if @@ -650,14 +642,15 @@ * Do an 'exponential back-in' to ensure we don't * run too long without rekey. */ - if (rmp->rm_ofuzz) { + if (rmp->rm_mag.rm_ofuzz) { /* * Decaying exponential back-in for rekey. */ if ((rnbyte_cnt < MINEXTRACTBYTES) || (!mutex_tryenter(&rndpool_lock))) { - rmp->rm_olimit += rmp->rm_ofuzz; - rmp->rm_ofuzz >>= 1; + rmp->rm_mag.rm_olimit += + rmp->rm_mag.rm_ofuzz; + rmp->rm_mag.rm_ofuzz >>= 1; goto punt; } } else { @@ -665,49 +658,71 @@ } /* Get a new chunk of entropy */ - (void) rnd_get_bytes(key, HMAC_KEYSIZE, - ALWAYS_EXTRACT, B_FALSE); - - /* Set up key */ - SET_ENCRYPT_KEY(key, HMAC_KEYSIZE, &rmp->rm_ks); + (void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_key, + HMAC_KEYSIZE, ALWAYS_EXTRACT, B_FALSE); - /* Get new counter value by encrypting timestamp */ - timestamp = gethrtime(); - HMAC_ENCRYPT(&rmp->rm_ks, ×tamp, - sizeof (timestamp), digest); - rmp->rm_olimit = PRNG_MAXOBLOCKS/2; - rmp->rm_ofuzz = PRNG_MAXOBLOCKS/4; - bcopy(digest, &rmp->rm_counter, sizeof (uint64_t)); + rmp->rm_mag.rm_olimit = PRNG_MAXOBLOCKS/2; + rmp->rm_mag.rm_ofuzz = PRNG_MAXOBLOCKS/4; oblocks = 0; - rmp->rm_oblocks = nblock; + rmp->rm_mag.rm_oblocks = nblock; } punt: - /* Hash counter to produce prn stream */ + timestamp = gethrtime(); + + src = (uint8_t *)×tamp; + dst = (uint8_t *)rmp->rm_mag.rm_seed; + + for (i = 0; i < HASHSIZE; i++) { + dst[i] ^= src[i % sizeof (timestamp)]; + } + + bcopy(rmp->rm_mag.rm_seed, seed, HASHSIZE); + + fips_random_inner(rmp->rm_mag.rm_key, tempout, + seed); + if (bytes >= HASHSIZE) { size = HASHSIZE; - HMAC_ENCRYPT(&rmp->rm_ks, &rmp->rm_counter, - sizeof (rmp->rm_counter), ptr); } else { size = min(bytes, HASHSIZE); - HMAC_ENCRYPT(&rmp->rm_ks, &rmp->rm_counter, - sizeof (rmp->rm_counter), digest); - bcopy(digest, ptr, size); } + + /* + * FIPS 140-2: Continuous RNG test - each generation + * of an n-bit block shall be compared with the previously + * generated block. Test shall fail if any two compared + * n-bit blocks are equal. + */ + for (i = 0; i < size/BYTES_IN_WORD; i++) { + if (tempout[i] != rmp->rm_mag.rm_previous[i]) + break; + } + if (i == size/BYTES_IN_WORD) + cmn_err(CE_WARN, "kcf_random: The value of 160-bit " + "block random bytes are same as the previous " + "one.\n"); + + bcopy(tempout, rmp->rm_mag.rm_previous, + HASHSIZE); + + bcopy(tempout, ptr, size); ptr += size; bytes -= size; - rmp->rm_counter++; oblocks++; nblock--; } while (bytes > 0); - mutex_exit(&rmp->rm_lock); + /* Zero out sensitive information */ + bzero(seed, HASHSIZE); + bzero(tempout, HASHSIZE); + mutex_exit(&rmp->rm_mag.rm_lock); return (0); } /* * Per-CPU Random magazines. */ -static rndmag_t *rndmag; +static rndmag_pad_t *rndmag; static uint8_t *rndbuf; static size_t rndmag_total; /* @@ -728,7 +743,7 @@ int kcf_rnd_get_pseudo_bytes(uint8_t *ptr, size_t len) { - rndmag_t *rmp; + rndmag_pad_t *rmp; uint8_t *cptr, *eptr; /* @@ -741,7 +756,7 @@ */ for (;;) { rmp = &rndmag[CPU->cpu_seqid]; - mutex_enter(&rmp->rm_lock); + mutex_enter(&rmp->rm_mag.rm_lock); /* * Big requests bypass buffer and tail-call the @@ -752,27 +767,27 @@ return (rnd_generate_pseudo_bytes(rmp, ptr, len)); } - cptr = rmp->rm_rptr; + cptr = rmp->rm_mag.rm_rptr; eptr = cptr + len; - if (eptr <= rmp->rm_eptr) { - rmp->rm_rptr = eptr; + if (eptr <= rmp->rm_mag.rm_eptr) { + rmp->rm_mag.rm_rptr = eptr; bcopy(cptr, ptr, len); BUMP_CPU_RND_STATS(rmp, rs_urndOut, len); - mutex_exit(&rmp->rm_lock); + mutex_exit(&rmp->rm_mag.rm_lock); return (0); } /* * End fast path. */ - rmp->rm_rptr = rmp->rm_buffer; + rmp->rm_mag.rm_rptr = rmp->rm_mag.rm_buffer; /* * Note: We assume the generate routine always succeeds * in this case (because it does at present..) * It also always releases rm_lock. */ - (void) rnd_generate_pseudo_bytes(rmp, rmp->rm_buffer, + (void) rnd_generate_pseudo_bytes(rmp, rmp->rm_mag.rm_buffer, rndbuf_len); } } @@ -788,8 +803,9 @@ static void rnd_alloc_magazines() { - rndmag_t *rmp; + rndmag_pad_t *rmp; int i; + uint8_t discard_buf[HASHSIZE]; rndbuf_len = roundup(rndbuf_len, HASHSIZE); if (rndmag_size < rndbuf_len) @@ -800,20 +816,40 @@ rndmag_total = rndmag_size * random_max_ncpus; rndbuf = kmem_alloc(rndmag_total, KM_SLEEP); - rndmag = kmem_zalloc(sizeof (rndmag_t) * random_max_ncpus, KM_SLEEP); + rndmag = kmem_zalloc(sizeof (rndmag_pad_t) * random_max_ncpus, + KM_SLEEP); for (i = 0; i < random_max_ncpus; i++) { uint8_t *buf; rmp = &rndmag[i]; - mutex_init(&rmp->rm_lock, NULL, MUTEX_DRIVER, NULL); + mutex_init(&rmp->rm_mag.rm_lock, NULL, MUTEX_DRIVER, NULL); buf = rndbuf + i * rndmag_size; - rmp->rm_buffer = buf; - rmp->rm_eptr = buf + rndbuf_len; - rmp->rm_rptr = buf + rndbuf_len; - rmp->rm_oblocks = 1; + rmp->rm_mag.rm_buffer = buf; + rmp->rm_mag.rm_eptr = buf + rndbuf_len; + rmp->rm_mag.rm_rptr = buf + rndbuf_len; + rmp->rm_mag.rm_oblocks = 1; + + mutex_enter(&rndpool_lock); + /* + * FIPS 140-2: the first n-bit (n > 15) block generated + * after power-up, initialization, or reset shall not + * be used, but shall be saved for comparison. + */ + (void) rnd_get_bytes(discard_buf, + HMAC_KEYSIZE, ALWAYS_EXTRACT, B_FALSE); + bcopy(discard_buf, rmp->rm_mag.rm_previous, + HMAC_KEYSIZE); + /* rnd_get_bytes() will call mutex_exit(&rndpool_lock) */ + mutex_enter(&rndpool_lock); + (void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_key, + HMAC_KEYSIZE, ALWAYS_EXTRACT, B_FALSE); + /* rnd_get_bytes() will call mutex_exit(&rndpool_lock) */ + mutex_enter(&rndpool_lock); + (void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_seed, + HMAC_KEYSIZE, ALWAYS_EXTRACT, B_FALSE); } } @@ -905,71 +941,6 @@ kcf_rnd_schedule_timeout(B_FALSE); } -/* Hashing functions */ - -static void -hmac_key(uint8_t *key, size_t keylen, void *buf) -{ - uint32_t *ip, *op; - uint32_t ipad[HMAC_BLOCK_SIZE/sizeof (uint32_t)]; - uint32_t opad[HMAC_BLOCK_SIZE/sizeof (uint32_t)]; - HASH_CTX *icontext, *ocontext; - int i; - int nints; - - icontext = buf; - ocontext = (SHA1_CTX *)((uint8_t *)buf + sizeof (HASH_CTX)); - - bzero((uchar_t *)ipad, HMAC_BLOCK_SIZE); - bzero((uchar_t *)opad, HMAC_BLOCK_SIZE); - bcopy(key, (uchar_t *)ipad, keylen); - bcopy(key, (uchar_t *)opad, keylen); - - /* - * XOR key with ipad (0x36) and opad (0x5c) as defined - * in RFC 2104. - */ - ip = ipad; - op = opad; - nints = HMAC_BLOCK_SIZE/sizeof (uint32_t); - - for (i = 0; i < nints; i++) { - ip[i] ^= 0x36363636; - op[i] ^= 0x5c5c5c5c; - } - - /* Perform hash with ipad */ - HashInit(icontext); - HashUpdate(icontext, (uchar_t *)ipad, HMAC_BLOCK_SIZE); - - /* Perform hash with opad */ - HashInit(ocontext); - HashUpdate(ocontext, (uchar_t *)opad, HMAC_BLOCK_SIZE); -} - -static void -hmac_encr(void *ctx, uint8_t *ptr, size_t len, uint8_t *digest) -{ - HASH_CTX *saved_contexts; - HASH_CTX icontext; - HASH_CTX ocontext; - - saved_contexts = (HASH_CTX *)ctx; - icontext = saved_contexts[0]; - ocontext = saved_contexts[1]; - - HashUpdate(&icontext, ptr, len); - HashFinal(digest, &icontext); - - /* - * Perform Hash(K XOR OPAD, DIGEST), where DIGEST is the - * Hash(K XOR IPAD, DATA). - */ - HashUpdate(&ocontext, digest, HASHSIZE); - HashFinal(digest, &ocontext); -} - - static void rndc_addbytes(uint8_t *ptr, size_t len) {
--- a/usr/src/uts/common/crypto/io/swrand.c Thu Nov 06 15:40:19 2008 -0800 +++ b/usr/src/uts/common/crypto/io/swrand.c Thu Nov 06 16:52:01 2008 -0800 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Software based random number provider for the Kernel Cryptographic * Framework (KCF). This provider periodically collects unpredictable input @@ -56,6 +54,7 @@ #include <sys/sunddi.h> #include <sys/modctl.h> #include <sys/hold_page.h> +#include <rng/fips_random.h> #define RNDPOOLSIZE 1024 /* Pool size in bytes */ #define HASHBUFSIZE 64 /* Buffer size used for pool mixing */ @@ -95,7 +94,9 @@ static int bstart, bindex; /* Global vars for adding/extracting */ /* from the buffer */ static uint8_t leftover[HASHSIZE]; /* leftover output */ +static uint32_t swrand_XKEY[6]; /* one extra word for getentropy */ static int leftover_bytes; /* leftover length */ +static uint32_t previous_bytes[SHA1WORDS]; /* previous random bytes */ static physmem_entsrc_t entsrc; /* Physical mem as an entropy source */ static timeout_id_t rnd_timeout_id; @@ -253,6 +254,8 @@ mutex_enter(&srndpool_lock); swrand_schedule_timeout(); mutex_exit(&srndpool_lock); + (void) swrand_get_entropy((uint8_t *)swrand_XKEY, HASHSIZE, B_TRUE); + bcopy(swrand_XKEY, previous_bytes, HASHSIZE); return (0); } @@ -303,7 +306,6 @@ return (CRYPTO_SUCCESS); } - /* * Extraction of entropy from the pool. * @@ -318,6 +320,8 @@ int i, bytes; HASH_CTX hashctx; uint8_t digest[HASHSIZE], *pool; + uint32_t tempout[SHA1WORDS]; + int size; mutex_enter(&srndpool_lock); if (leftover_bytes > 0) { @@ -379,25 +383,45 @@ pindex &= (RNDPOOLSIZE - 1); } - /* - * Hash the digest again before output to obscure - * what was fed back to the pool. - */ - HashInit(&hashctx); - HashUpdate(&hashctx, digest, HASHSIZE); - if (len >= HASHSIZE) - HashFinal(ptr, &hashctx); - else { - HashFinal(digest, &hashctx); - bcopy(digest, ptr, bytes); - leftover_bytes = HASHSIZE - bytes; - bcopy(digest + bytes, leftover, leftover_bytes); + /* LINTED E_BAD_PTR_CAST_ALIGN */ + fips_random_inner(swrand_XKEY, tempout, (uint32_t *)digest); + + if (len >= HASHSIZE) { + size = HASHSIZE; + } else { + size = min(bytes, HASHSIZE); } - len -= bytes; - ptr += bytes; - BUMP_SWRAND_STATS(ss_bytesOut, bytes); + /* + * FIPS 140-2: Continuous RNG test - each generation + * of an n-bit block shall be compared with the previously + * generated block. Test shall fail if any two compared + * n-bit blocks are equal. + */ + for (i = 0; i < size/BYTES_IN_WORD; i++) { + if (tempout[i] != previous_bytes[i]) + break; + } + if (i == size/BYTES_IN_WORD) + cmn_err(CE_WARN, "swrand: The value of 160-bit block " + "random bytes are same as the previous one.\n"); + + bcopy(tempout, previous_bytes, HASHSIZE); + + bcopy(tempout, ptr, size); + if (len < HASHSIZE) { + leftover_bytes = HASHSIZE - bytes; + bcopy(tempout + bytes, leftover, leftover_bytes); + } + + ptr += size; + len -= size; + BUMP_SWRAND_STATS(ss_bytesOut, size); } + + /* Zero out sensitive information */ + bzero(digest, HASHSIZE); + bzero(tempout, HASHSIZE); mutex_exit(&srndpool_lock); return (0); }
--- a/usr/src/uts/common/sys/random.h Thu Nov 06 15:40:19 2008 -0800 +++ b/usr/src/uts/common/sys/random.h Thu Nov 06 16:52:01 2008 -0800 @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_RANDOM_H #define _SYS_RANDOM_H -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/atomic.h> @@ -54,7 +52,7 @@ #ifdef _KERNEL -#define BUMP_CPU_RND_STATS(rm, x, v) (((rm)->rm_stats).x += (v)) +#define BUMP_CPU_RND_STATS(rm, x, v) (((rm)->rm_mag.rm_stats).x += (v)) #define BUMP_RND_STATS(x, v) atomic_add_64(&(rnd_stats).x, (v)) #define BUMP_SWRAND_STATS(x, v) atomic_add_64(&(swrand_stats).x, (v))
--- a/usr/src/uts/intel/swrand/Makefile Thu Nov 06 15:40:19 2008 -0800 +++ b/usr/src/uts/intel/swrand/Makefile Thu Nov 06 16:52:01 2008 -0800 @@ -19,10 +19,9 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" # # This makefile drives the production of the swrand KEF provider. # @@ -33,6 +32,7 @@ # Path to the base of the uts directory tree (usually /usr/src/uts). # UTSBASE = ../.. +COM_DIR = $(COMMONBASE)/crypto # # Define the module and object file sets. @@ -58,7 +58,8 @@ # # lint pass one enforcement # -CFLAGS += $(CCVERBOSE) +CFLAGS += $(CCVERBOSE) -I$(COM_DIR) +LINTFLAGS += -I$(COM_DIR) # # Linkage dependencies
--- a/usr/src/uts/sparc/swrand/Makefile Thu Nov 06 15:40:19 2008 -0800 +++ b/usr/src/uts/sparc/swrand/Makefile Thu Nov 06 16:52:01 2008 -0800 @@ -19,10 +19,9 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -#ident "%Z%%M% %I% %E% SMI" # # This makefile drives the production of the swrand KEF provider. # @@ -33,6 +32,7 @@ # Path to the base of the uts directory tree (usually /usr/src/uts). # UTSBASE = ../.. +COM_DIR = $(COMMONBASE)/crypto # # Define the module and object file sets. @@ -57,7 +57,8 @@ # # lint pass one enforcement # -CFLAGS += $(CCVERBOSE) +CFLAGS += $(CCVERBOSE) -I$(COM_DIR) +LINTFLAGS += -I$(COM_DIR) # # Linkage dependencies
--- a/usr/src/uts/sun4v/io/n2rng/n2rng_provider.c Thu Nov 06 15:40:19 2008 -0800 +++ b/usr/src/uts/sun4v/io/n2rng/n2rng_provider.c Thu Nov 06 16:52:01 2008 -0800 @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <sys/sysmacros.h> #include <sys/modctl.h> @@ -45,14 +43,10 @@ #include <sys/sha1.h> #include <sys/ddi.h> /* near end to get min and max macros right */ #include <sys/sunddi.h> +#include <rng/fips_random.h> /* n must be a power of 2 */ #define ROUNDUP(k, n) (((k) + (n) - 1) & ~((n) - 1)) -#define SHA1BLOCKBITS 512 -#define SHA1BLOCKBYTES (SHA1BLOCKBITS / 8) -#define SHA1WORDS 5 -#define SHA1BYTES (4 * SHA1WORDS) - /* * Policy. ENTROPY_STARVATION is the maximum number of calls each @@ -68,119 +62,6 @@ */ #define ENTROPY_STARVATION 10000ULL -/* - * Adds val1 and val2 and stores result into sum. The various input - * pointers can be exactly aliased. (They cannot be offset and - * overlapping, but no one would ever do that.) Values are big endian - * by words and native byte order within words. The return value's - * 2-bit is 0 if the result is zero, it's 1 bit is carry out. (This - * is reused code. The return code is not used by n2rng.) Thus, - * calling with both carryin and complement_val2 ones does a - * subtraction. A null sum pointer parameter is allowed. The - * subtraction features were required when this code was orginally - * written so it could do a mod q operation. - */ -static int -add160(uint32_t *sum, uint32_t const *val1, uint32_t const *val2, - const unsigned carryin, const int complement_val2) -{ - int i; - uint32_t partialsum; - uint32_t carry = (carryin > 0); - uint32_t non_zero = 0; - - for (i = 4; i >= 0; --i) { - partialsum = val1[i] + (complement_val2 ? ~val2[i] : val2[i]) + - carry; - if (carry) { - carry = (partialsum <= val1[i]); - } else { - carry = (partialsum < val1[i]); - } - if (sum) { - sum[i] = partialsum; - } - non_zero |= partialsum; - } - - return (((non_zero != 0) * 2) | carry); -} - - - -/* - * Computes a new random value, which is stored in x_j; updates XKEY - * in the *rs. XSEED_j is additional input. In principle, we should - * protect XKEY, perhaps by putting it on a non-pagable page, but we - * aways clobber XKEY with fresh entropy just before we use it. And - * step 3d irreversibly updates it just after we use it. The only - * risk is that if an attacker captured the state while the entropy - * generator was broken, the attacker could predict future values. - * There are two cases: 1. The attack gets root access to a live - * system. But there is no defense against that. 2. The attacker - * gets access to a crash dump. But by then no values are being - * generated. - * - * Note that XSEEDj is overwritten with sensitive stuff, and must be - * zeroed by the caller. We use two separate symbols (XVAL and - * XSEEDj) to make each step match the notation in FIPS 186-2. - */ -static void -fips_random_inner(fipsrandomstruct_t *frsp, uint32_t *x_j, - uint32_t *XSEED_j) -{ - int i; - SHA1_CTX sha1_context; - /* Alias to preserve terminology from FIPS 186-2 */ -#define XVAL XSEED_j - /* - * K&R section A8.7: If the array has fixed size, the number - * of initializers may not exceed the number of members in the - * array; if there are fewer, the trailing members are - * initialized with 0. - */ - static const char zero[SHA1BLOCKBYTES - SHA1BYTES] = {0}; - - /* - * Step 3b: XVAL = (XKEY + XSEED_sub_j) mod 2^b. The mod is - * implicit in the 160 bit representation. Note that XVAL and - * XSEED_j are actually the same location. - */ - (void) add160(XVAL, frsp->XKEY, XSEED_j, 0, 0); - /* - * Step 3c: x_sub_j = G(t, XVAL) - */ - SHA1Init(&sha1_context); - SHA1Update(&sha1_context, (unsigned char *)XVAL, SHA1BYTES); - /* - * Filling to 64 bytes is requried by FIPS 186-2 Appendix 3.3. - * It also triggers SHA1Transform (the steps a-e of the spec). - * - * zero is a const char[], but SHA1update does not declare its - * second parameter const, even though it does not modify it, - * so we cast to suppress a compiler warning. - */ - SHA1Update(&sha1_context, (unsigned char *)zero, - SHA1BLOCKBYTES - SHA1BYTES); - /* - * The code below directly accesses the state field of - * sha1_context, which is of type SHA1_CTX, defined in sha1.h. - * This has been deemed acceptable, because that typedef is - * Consolidation Private, and n2rng is in the same - * consolidation. - */ - /* copy out to x_j */ - for (i = 0; i < 5; i++) { - x_j[i] = sha1_context.state[i]; - } - /* - * Step 3d: XKEY = (1 + XKEY + x_sub_j) mod 2^b. b=160. The - * mod 2^160 is implicit in the 160 bit representation. The - * one is added via the carry-in flag. - */ - (void) add160(frsp->XKEY, frsp->XKEY, x_j, 1, 0); -#undef XVAL -} int fips_random(n2rng_t *n2rng, uint8_t *out, size_t nbytes) @@ -259,7 +140,7 @@ } /* nbytes - i is bytes to go */ - fips_random_inner(frsp, tempout, entropy.as32); + fips_random_inner(frsp->XKEY, tempout, entropy.as32); bcopy(tempout, &out[i], min(nbytes - i, SHA1BYTES)); mutex_exit(&frsp->mtx);
--- a/usr/src/uts/sun4v/n2rng/Makefile Thu Nov 06 15:40:19 2008 -0800 +++ b/usr/src/uts/sun4v/n2rng/Makefile Thu Nov 06 16:52:01 2008 -0800 @@ -20,11 +20,10 @@ # # uts/sun4v/n2rng/Makefile # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # -#ident "%Z%%M% %I% %E% SMI" # # This makefile drives the production of the n2rng driver kernel module. # @@ -35,6 +34,7 @@ # Path to the base of the uts directory tree (usually /usr/src/uts). # UTSBASE = ../.. +COM_DIR = $(COMMONBASE)/crypto # # Define the module and object file sets. @@ -67,8 +67,13 @@ # # lint pass one enforcement # -CFLAGS += -v -DN2 -LINTFLAGS += -DN2 +CFLAGS += -v -DN2 -I$(COM_DIR) +LINTFLAGS += -DN2 -I$(COM_DIR) + +# +# module dependencies +# +LDFLAGS += -dy -Nmisc/kcf # # Default build targets.