summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHai-May Chao <Hai-May.Chao@Sun.COM>2008-11-06 16:52:01 -0800
committerHai-May Chao <Hai-May.Chao@Sun.COM>2008-11-06 16:52:01 -0800
commitfe54a78e1aacf39261ad56e9903bce02e3fb6d21 (patch)
tree4357efd88c8d3f44e772f80444d8fc584aa96707
parent3eea75d7fe911f13703d0937e65c6023aac827ab (diff)
downloadillumos-joyent-fe54a78e1aacf39261ad56e9903bce02e3fb6d21.tar.gz
6703956 Solaris cryptographic framework needs a FIPS-186-2 certifiable RNG
-rw-r--r--usr/src/common/crypto/rng/fips_random.c137
-rw-r--r--usr/src/common/crypto/rng/fips_random.h47
-rw-r--r--usr/src/uts/common/Makefile.files2
-rw-r--r--usr/src/uts/common/Makefile.rules7
-rw-r--r--usr/src/uts/common/crypto/api/kcf_random.c255
-rw-r--r--usr/src/uts/common/crypto/io/swrand.c58
-rw-r--r--usr/src/uts/common/sys/random.h6
-rw-r--r--usr/src/uts/intel/swrand/Makefile7
-rw-r--r--usr/src/uts/sparc/swrand/Makefile7
-rw-r--r--usr/src/uts/sun4v/io/n2rng/n2rng_provider.c125
-rw-r--r--usr/src/uts/sun4v/n2rng/Makefile13
11 files changed, 368 insertions, 296 deletions
diff --git a/usr/src/common/crypto/rng/fips_random.c b/usr/src/common/crypto/rng/fips_random.c
new file mode 100644
index 0000000000..a01394ccc8
--- /dev/null
+++ b/usr/src/common/crypto/rng/fips_random.c
@@ -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
+}
diff --git a/usr/src/common/crypto/rng/fips_random.h b/usr/src/common/crypto/rng/fips_random.h
new file mode 100644
index 0000000000..c1fcb0ff1d
--- /dev/null
+++ b/usr/src/common/crypto/rng/fips_random.h
@@ -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 */
diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files
index 7b4357de66..1d28772d6d 100644
--- a/usr/src/uts/common/Makefile.files
+++ b/usr/src/uts/common/Makefile.files
@@ -1370,7 +1370,7 @@ KCF_OBJS += kcf.o kcf_callprov.o kcf_cbufcall.o kcf_cipher.o kcf_crypto.o \
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
diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules
index e623f79a7a..d1678f46cb 100644
--- a/usr/src/uts/common/Makefile.rules
+++ b/usr/src/uts/common/Makefile.rules
@@ -60,6 +60,10 @@ $(OBJS_DIR)/%.o: $(COMMONBASE)/crypto/modes/%.c
$(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/ecc/%.c
$(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))
diff --git a/usr/src/uts/common/crypto/api/kcf_random.c b/usr/src/uts/common/crypto/api/kcf_random.c
index 62bf0ca3a6..9efc310785 100644
--- a/usr/src/uts/common/crypto/api/kcf_random.c
+++ b/usr/src/uts/common/crypto/api/kcf_random.c
@@ -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 @@ typedef enum extract_type {
/* 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_addbytes(uint8_t *, size_t);
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 @@ kcf_rnd_get_bytes(uint8_t *ptr, size_t len, boolean_t noblock,
* 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 @@ typedef struct rndmag_s
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 @@ typedef struct rndmag_s
* 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 @@ rnd_generate_pseudo_bytes(rndmag_t *rmp, uint8_t *ptr, size_t len)
* 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 @@ rnd_generate_pseudo_bytes(rndmag_t *rmp, uint8_t *ptr, size_t len)
}
/* 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);
-
- /* Get new counter value by encrypting timestamp */
- timestamp = gethrtime();
- HMAC_ENCRYPT(&rmp->rm_ks, &timestamp,
- sizeof (timestamp), digest);
- rmp->rm_olimit = PRNG_MAXOBLOCKS/2;
- rmp->rm_ofuzz = PRNG_MAXOBLOCKS/4;
- bcopy(digest, &rmp->rm_counter, sizeof (uint64_t));
+ (void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_key,
+ HMAC_KEYSIZE, ALWAYS_EXTRACT, B_FALSE);
+
+ 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 *)&timestamp;
+ 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 @@ size_t rndmag_size = 1280;
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 @@ kcf_rnd_get_pseudo_bytes(uint8_t *ptr, size_t len)
*/
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 @@ kcf_rnd_get_pseudo_bytes(uint8_t *ptr, size_t len)
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 @@ kcf_rnd_get_pseudo_bytes(uint8_t *ptr, size_t len)
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 @@ rnd_alloc_magazines()
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 @@ rnd_handler(void *arg)
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)
{
diff --git a/usr/src/uts/common/crypto/io/swrand.c b/usr/src/uts/common/crypto/io/swrand.c
index 0731ed5010..553eb215b2 100644
--- a/usr/src/uts/common/crypto/io/swrand.c
+++ b/usr/src/uts/common/crypto/io/swrand.c
@@ -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 pindex; /* Global index for adding/extracting */
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 @@ _init(void)
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 @@ swrand_generate_random(crypto_provider_handle_t provider,
return (CRYPTO_SUCCESS);
}
-
/*
* Extraction of entropy from the pool.
*
@@ -318,6 +320,8 @@ swrand_get_entropy(uint8_t *ptr, size_t len, boolean_t nonblock)
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 @@ swrand_get_entropy(uint8_t *ptr, size_t len, boolean_t nonblock)
pindex &= (RNDPOOLSIZE - 1);
}
+ /* 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);
+ }
+
/*
- * Hash the digest again before output to obscure
- * what was fed back to the pool.
+ * 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.
*/
- HashInit(&hashctx);
- HashUpdate(&hashctx, digest, HASHSIZE);
- if (len >= HASHSIZE)
- HashFinal(ptr, &hashctx);
- else {
- HashFinal(digest, &hashctx);
- bcopy(digest, ptr, bytes);
+ 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(digest + bytes, leftover, leftover_bytes);
+ bcopy(tempout + bytes, leftover, leftover_bytes);
}
- len -= bytes;
- ptr += bytes;
- BUMP_SWRAND_STATS(ss_bytesOut, 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);
}
diff --git a/usr/src/uts/common/sys/random.h b/usr/src/uts/common/sys/random.h
index 919e50fb31..5436094f9d 100644
--- a/usr/src/uts/common/sys/random.h
+++ b/usr/src/uts/common/sys/random.h
@@ -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 @@ typedef struct swrand_stats {
#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))
diff --git a/usr/src/uts/intel/swrand/Makefile b/usr/src/uts/intel/swrand/Makefile
index 8833dc3d0a..2d98dddb34 100644
--- a/usr/src/uts/intel/swrand/Makefile
+++ b/usr/src/uts/intel/swrand/Makefile
@@ -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 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
# lint pass one enforcement
#
-CFLAGS += $(CCVERBOSE)
+CFLAGS += $(CCVERBOSE) -I$(COM_DIR)
+LINTFLAGS += -I$(COM_DIR)
#
# Linkage dependencies
diff --git a/usr/src/uts/sparc/swrand/Makefile b/usr/src/uts/sparc/swrand/Makefile
index 821e4870d5..9f81e3ae39 100644
--- a/usr/src/uts/sparc/swrand/Makefile
+++ b/usr/src/uts/sparc/swrand/Makefile
@@ -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 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
# lint pass one enforcement
#
-CFLAGS += $(CCVERBOSE)
+CFLAGS += $(CCVERBOSE) -I$(COM_DIR)
+LINTFLAGS += -I$(COM_DIR)
#
# Linkage dependencies
diff --git a/usr/src/uts/sun4v/io/n2rng/n2rng_provider.c b/usr/src/uts/sun4v/io/n2rng/n2rng_provider.c
index e2415f3986..3a596d5e63 100644
--- a/usr/src/uts/sun4v/io/n2rng/n2rng_provider.c
+++ b/usr/src/uts/sun4v/io/n2rng/n2rng_provider.c
@@ -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 @@ fips_random(n2rng_t *n2rng, uint8_t *out, size_t nbytes)
}
/* 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);
diff --git a/usr/src/uts/sun4v/n2rng/Makefile b/usr/src/uts/sun4v/n2rng/Makefile
index 58f2d75a51..7f448c0e20 100644
--- a/usr/src/uts/sun4v/n2rng/Makefile
+++ b/usr/src/uts/sun4v/n2rng/Makefile
@@ -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 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
#
# 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.