1 /* $NetBSD: subr_cprng.c,v 1.15 2013/01/26 16:05:34 tls Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Thor Lancelot Simon. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/types.h> 33 #include <sys/time.h> 34 #include <sys/param.h> 35 #include <sys/kernel.h> 36 #include <sys/systm.h> 37 #include <sys/kmem.h> 38 #include <sys/mutex.h> 39 #include <sys/rngtest.h> 40 #include <sys/rnd.h> 41 #include <dev/rnd_private.h> 42 43 #if defined(__HAVE_CPU_COUNTER) 44 #include <machine/cpu_counter.h> 45 #endif 46 47 #include <sys/cprng.h> 48 49 __KERNEL_RCSID(0, "$NetBSD: subr_cprng.c,v 1.15 2013/01/26 16:05:34 tls Exp $"); 50 51 void 52 cprng_init(void) 53 { 54 nist_ctr_initialize(); 55 } 56 57 static inline uint32_t 58 cprng_counter(void) 59 { 60 struct timeval tv; 61 62 #if defined(__HAVE_CPU_COUNTER) 63 if (cpu_hascounter()) 64 return cpu_counter32(); 65 #endif 66 if (__predict_false(cold)) { 67 /* microtime unsafe if clock not running yet */ 68 return 0; 69 } 70 microtime(&tv); 71 return (tv.tv_sec * 1000000 + tv.tv_usec); 72 } 73 74 static void 75 cprng_strong_doreseed(cprng_strong_t *const c) 76 { 77 uint32_t cc = cprng_counter(); 78 79 KASSERT(mutex_owned(&c->mtx)); 80 KASSERT(mutex_owned(&c->reseed.mtx)); 81 KASSERT(c->reseed.len == NIST_BLOCK_KEYLEN_BYTES); 82 83 if (nist_ctr_drbg_reseed(&c->drbg, c->reseed.data, c->reseed.len, 84 &cc, sizeof(cc))) { 85 panic("cprng %s: nist_ctr_drbg_reseed failed.", c->name); 86 } 87 memset(c->reseed.data, 0, c->reseed.len); 88 89 #ifdef RND_VERBOSE 90 printf("cprng %s: reseeded with rnd_filled = %d\n", c->name, 91 rnd_filled); 92 #endif 93 c->entropy_serial = rnd_filled; 94 c->reseed.state = RSTATE_IDLE; 95 if (c->flags & CPRNG_USE_CV) { 96 cv_broadcast(&c->cv); 97 } 98 selnotify(&c->selq, 0, 0); 99 } 100 101 static void 102 cprng_strong_sched_reseed(cprng_strong_t *const c) 103 { 104 KASSERT(mutex_owned(&c->mtx)); 105 if (mutex_tryenter(&c->reseed.mtx)) { 106 switch (c->reseed.state) { 107 case RSTATE_IDLE: 108 c->reseed.state = RSTATE_PENDING; 109 c->reseed.len = NIST_BLOCK_KEYLEN_BYTES; 110 rndsink_attach(&c->reseed); 111 break; 112 case RSTATE_HASBITS: 113 /* Just rekey the underlying generator now. */ 114 cprng_strong_doreseed(c); 115 break; 116 case RSTATE_PENDING: 117 if (c->entropy_serial != rnd_filled) { 118 rndsink_detach(&c->reseed); 119 rndsink_attach(&c->reseed); 120 } 121 break; 122 default: 123 panic("cprng %s: bad reseed state %d", 124 c->name, c->reseed.state); 125 break; 126 } 127 mutex_spin_exit(&c->reseed.mtx); 128 } 129 #ifdef RND_VERBOSE 130 else { 131 printf("cprng %s: skipping sched_reseed, sink busy\n", 132 c->name); 133 } 134 #endif 135 } 136 137 static void 138 cprng_strong_reseed(void *const arg) 139 { 140 cprng_strong_t *c = arg; 141 142 KASSERT(mutex_owned(&c->reseed.mtx)); 143 KASSERT(RSTATE_HASBITS == c->reseed.state); 144 145 if (!mutex_tryenter(&c->mtx)) { 146 #ifdef RND_VERBOSE 147 printf("cprng: sink %s cprng busy, no reseed\n", c->reseed.name); 148 #endif 149 if (c->flags & CPRNG_USE_CV) { /* XXX if flags change? */ 150 cv_broadcast(&c->cv); 151 } 152 return; 153 } 154 155 cprng_strong_doreseed(c); 156 mutex_exit(&c->mtx); 157 } 158 159 static size_t 160 cprng_entropy_try(uint8_t *key, size_t keylen, int hard) 161 { 162 int r; 163 r = rnd_extract_data(key, keylen, RND_EXTRACT_GOOD); 164 if (r != keylen && !hard) { 165 rnd_extract_data(key + r, keylen - r, RND_EXTRACT_ANY); 166 } 167 return r; 168 } 169 170 cprng_strong_t * 171 cprng_strong_create(const char *const name, int ipl, int flags) 172 { 173 cprng_strong_t *c; 174 uint8_t key[NIST_BLOCK_KEYLEN_BYTES]; 175 int r, getmore = 0, hard = 0; 176 uint32_t cc; 177 178 c = kmem_alloc(sizeof(*c), KM_NOSLEEP); 179 if (c == NULL) { 180 return NULL; 181 } 182 c->flags = flags; 183 strlcpy(c->name, name, sizeof(c->name)); 184 c->reseed.state = RSTATE_IDLE; 185 c->reseed.cb = cprng_strong_reseed; 186 c->reseed.arg = c; 187 c->entropy_serial = rnd_initial_entropy ? rnd_filled : -1; 188 mutex_init(&c->reseed.mtx, MUTEX_DEFAULT, IPL_VM); 189 strlcpy(c->reseed.name, name, sizeof(c->reseed.name)); 190 191 mutex_init(&c->mtx, MUTEX_DEFAULT, ipl); 192 193 if (c->flags & CPRNG_USE_CV) { 194 cv_init(&c->cv, (const char *)c->name); 195 } 196 197 selinit(&c->selq); 198 199 r = cprng_entropy_try(key, sizeof(key), c->flags & CPRNG_INIT_ANY); 200 if (r != sizeof(key)) { 201 if (c->flags & CPRNG_INIT_ANY) { 202 #ifdef DEBUG 203 printf("cprng %s: WARNING insufficient " 204 "entropy at creation.\n", name); 205 #endif 206 } else { 207 hard++; 208 } 209 getmore++; 210 } 211 212 if (nist_ctr_drbg_instantiate(&c->drbg, key, sizeof(key), 213 &cc, sizeof(cc), name, strlen(name))) { 214 panic("cprng %s: instantiation failed.", name); 215 } 216 217 if (getmore) { 218 /* Cause readers to wait for rekeying. */ 219 if (hard) { 220 c->drbg.reseed_counter = 221 NIST_CTR_DRBG_RESEED_INTERVAL + 1; 222 } else { 223 c->drbg.reseed_counter = 224 (NIST_CTR_DRBG_RESEED_INTERVAL / 2) + 1; 225 } 226 } 227 return c; 228 } 229 230 size_t 231 cprng_strong(cprng_strong_t *const c, void *const p, size_t len, int flags) 232 { 233 uint32_t cc = cprng_counter(); 234 #ifdef DEBUG 235 int testfail = 0; 236 #endif 237 if (len > CPRNG_MAX_LEN) { /* XXX should we loop? */ 238 len = CPRNG_MAX_LEN; /* let the caller loop if desired */ 239 } 240 mutex_enter(&c->mtx); 241 242 /* If we were initialized with the pool empty, rekey ASAP */ 243 if (__predict_false(c->entropy_serial == -1) && rnd_initial_entropy) { 244 c->entropy_serial = 0; 245 goto rekeyany; /* We have _some_ entropy, use it. */ 246 } 247 248 if (nist_ctr_drbg_generate(&c->drbg, p, len, &cc, sizeof(cc))) { 249 /* A generator failure really means we hit the hard limit. */ 250 rekeyany: 251 if (c->flags & CPRNG_REKEY_ANY) { 252 uint8_t key[NIST_BLOCK_KEYLEN_BYTES]; 253 254 if (cprng_entropy_try(key, sizeof(key), 0) != 255 sizeof(key)) { 256 printf("cprng %s: WARNING " 257 "pseudorandom rekeying.\n", c->name); 258 } 259 cc = cprng_counter(); 260 if (nist_ctr_drbg_reseed(&c->drbg, key, sizeof(key), 261 &cc, sizeof(cc))) { 262 panic("cprng %s: nist_ctr_drbg_reseed " 263 "failed.", c->name); 264 } 265 memset(key, 0, sizeof(key)); 266 } else { 267 int wr; 268 269 do { 270 cprng_strong_sched_reseed(c); 271 if ((flags & FNONBLOCK) || 272 !(c->flags & CPRNG_USE_CV)) { 273 len = 0; 274 break; 275 } 276 /* 277 * XXX There's a race with the cv_broadcast 278 * XXX in cprng_strong_sched_reseed, because 279 * XXX of the use of tryenter in that function. 280 * XXX This "timedwait" hack works around it, 281 * XXX at the expense of occasionaly polling 282 * XXX for success on a /dev/random rekey. 283 */ 284 wr = cv_timedwait_sig(&c->cv, &c->mtx, 285 mstohz(100)); 286 if (wr == ERESTART) { 287 mutex_exit(&c->mtx); 288 return 0; 289 } 290 } while (nist_ctr_drbg_generate(&c->drbg, p, 291 len, &cc, 292 sizeof(cc))); 293 } 294 } 295 296 #ifdef DEBUG 297 /* 298 * If the generator has just been keyed, perform 299 * the statistical RNG test. 300 */ 301 if (__predict_false(c->drbg.reseed_counter == 1) && 302 (flags & FASYNC) == 0) { 303 rngtest_t *rt = kmem_intr_alloc(sizeof(*rt), KM_NOSLEEP); 304 305 if (rt) { 306 307 strncpy(rt->rt_name, c->name, sizeof(rt->rt_name)); 308 309 if (nist_ctr_drbg_generate(&c->drbg, rt->rt_b, 310 sizeof(rt->rt_b), NULL, 0)) { 311 panic("cprng %s: nist_ctr_drbg_generate " 312 "failed!", c->name); 313 314 } 315 testfail = rngtest(rt); 316 317 if (testfail) { 318 printf("cprng %s: failed statistical RNG " 319 "test.\n", c->name); 320 c->drbg.reseed_counter = 321 NIST_CTR_DRBG_RESEED_INTERVAL + 1; 322 len = 0; 323 } 324 memset(rt, 0, sizeof(*rt)); 325 kmem_intr_free(rt, sizeof(*rt)); 326 } 327 } 328 #endif 329 if (__predict_false(c->drbg.reseed_counter > 330 (NIST_CTR_DRBG_RESEED_INTERVAL / 2))) { 331 cprng_strong_sched_reseed(c); 332 } else if (rnd_full) { 333 if (c->entropy_serial != rnd_filled) { 334 #ifdef RND_VERBOSE 335 printf("cprng %s: reseeding from full pool " 336 "(serial %d vs pool %d)\n", c->name, 337 c->entropy_serial, rnd_filled); 338 #endif 339 cprng_strong_sched_reseed(c); 340 } 341 } 342 343 mutex_exit(&c->mtx); 344 return len; 345 } 346 347 void 348 cprng_strong_destroy(cprng_strong_t *c) 349 { 350 mutex_enter(&c->mtx); 351 mutex_spin_enter(&c->reseed.mtx); 352 353 if (c->flags & CPRNG_USE_CV) { 354 KASSERT(!cv_has_waiters(&c->cv)); 355 cv_destroy(&c->cv); 356 } 357 seldestroy(&c->selq); 358 359 if (RSTATE_PENDING == c->reseed.state) { 360 rndsink_detach(&c->reseed); 361 } 362 mutex_spin_exit(&c->reseed.mtx); 363 mutex_destroy(&c->reseed.mtx); 364 365 nist_ctr_drbg_destroy(&c->drbg); 366 367 mutex_exit(&c->mtx); 368 mutex_destroy(&c->mtx); 369 370 memset(c, 0, sizeof(*c)); 371 kmem_free(c, sizeof(*c)); 372 } 373 374 int 375 cprng_strong_getflags(cprng_strong_t *const c) 376 { 377 KASSERT(mutex_owned(&c->mtx)); 378 return c->flags; 379 } 380 381 void 382 cprng_strong_setflags(cprng_strong_t *const c, int flags) 383 { 384 KASSERT(mutex_owned(&c->mtx)); 385 if (flags & CPRNG_USE_CV) { 386 if (!(c->flags & CPRNG_USE_CV)) { 387 cv_init(&c->cv, (const char *)c->name); 388 } 389 } else { 390 if (c->flags & CPRNG_USE_CV) { 391 KASSERT(!cv_has_waiters(&c->cv)); 392 cv_destroy(&c->cv); 393 } 394 } 395 if (flags & CPRNG_REKEY_ANY) { 396 if (!(c->flags & CPRNG_REKEY_ANY)) { 397 if (c->flags & CPRNG_USE_CV) { 398 cv_broadcast(&c->cv); 399 } 400 selnotify(&c->selq, 0, 0); 401 } 402 } 403 c->flags = flags; 404 } 405