10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51070Skais * Common Development and Distribution License (the "License"). 61070Skais * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 228513SVladimir.Kotal@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* 270Sstevel@tonic-gate * This file implements the interfaces that the /dev/random 280Sstevel@tonic-gate * driver uses for read(2), write(2) and poll(2) on /dev/random or 290Sstevel@tonic-gate * /dev/urandom. It also implements the kernel API - random_add_entropy(), 308513SVladimir.Kotal@Sun.COM * random_add_pseudo_entropy(), random_get_pseudo_bytes() 318513SVladimir.Kotal@Sun.COM * and random_get_bytes(). 320Sstevel@tonic-gate * 330Sstevel@tonic-gate * We periodically collect random bits from providers which are registered 340Sstevel@tonic-gate * with the Kernel Cryptographic Framework (kCF) as capable of random 350Sstevel@tonic-gate * number generation. The random bits are maintained in a cache and 360Sstevel@tonic-gate * it is used for high quality random numbers (/dev/random) requests. 370Sstevel@tonic-gate * We pick a provider and call its SPI routine, if the cache does not have 380Sstevel@tonic-gate * enough bytes to satisfy a request. 390Sstevel@tonic-gate * 400Sstevel@tonic-gate * /dev/urandom requests use a software-based generator algorithm that uses the 410Sstevel@tonic-gate * random bits in the cache as a seed. We create one pseudo-random generator 420Sstevel@tonic-gate * (for /dev/urandom) per possible CPU on the system, and use it, 430Sstevel@tonic-gate * kmem-magazine-style, to avoid cache line contention. 440Sstevel@tonic-gate * 450Sstevel@tonic-gate * LOCKING HIERARCHY: 468029SHai-May.Chao@Sun.COM * 1) rmp->rm_mag.rm_lock protects the per-cpu pseudo-random generators. 470Sstevel@tonic-gate * 2) rndpool_lock protects the high-quality randomness pool. 488029SHai-May.Chao@Sun.COM * It may be locked while a rmp->rm_mag.rm_lock is held. 490Sstevel@tonic-gate * 500Sstevel@tonic-gate * A history note: The kernel API and the software-based algorithms in this 510Sstevel@tonic-gate * file used to be part of the /dev/random driver. 520Sstevel@tonic-gate */ 530Sstevel@tonic-gate 540Sstevel@tonic-gate #include <sys/types.h> 550Sstevel@tonic-gate #include <sys/conf.h> 560Sstevel@tonic-gate #include <sys/sunddi.h> 570Sstevel@tonic-gate #include <sys/disp.h> 580Sstevel@tonic-gate #include <sys/modctl.h> 590Sstevel@tonic-gate #include <sys/ddi.h> 600Sstevel@tonic-gate #include <sys/crypto/common.h> 610Sstevel@tonic-gate #include <sys/crypto/api.h> 620Sstevel@tonic-gate #include <sys/crypto/impl.h> 630Sstevel@tonic-gate #include <sys/crypto/sched_impl.h> 64*10732SAnthony.Scarpino@Sun.COM #include <sys/crypto/ioctladmin.h> 650Sstevel@tonic-gate #include <sys/random.h> 660Sstevel@tonic-gate #include <sys/sha1.h> 670Sstevel@tonic-gate #include <sys/time.h> 680Sstevel@tonic-gate #include <sys/sysmacros.h> 690Sstevel@tonic-gate #include <sys/cpuvar.h> 700Sstevel@tonic-gate #include <sys/taskq.h> 718029SHai-May.Chao@Sun.COM #include <rng/fips_random.h> 720Sstevel@tonic-gate 730Sstevel@tonic-gate #define RNDPOOLSIZE 1024 /* Pool size in bytes */ 740Sstevel@tonic-gate #define MINEXTRACTBYTES 20 750Sstevel@tonic-gate #define MAXEXTRACTBYTES 1024 760Sstevel@tonic-gate #define PRNG_MAXOBLOCKS 1310720 /* Max output block per prng key */ 770Sstevel@tonic-gate #define TIMEOUT_INTERVAL 5 /* Periodic mixing interval in secs */ 780Sstevel@tonic-gate 790Sstevel@tonic-gate typedef enum extract_type { 800Sstevel@tonic-gate NONBLOCK_EXTRACT, 810Sstevel@tonic-gate BLOCKING_EXTRACT, 820Sstevel@tonic-gate ALWAYS_EXTRACT 830Sstevel@tonic-gate } extract_type_t; 840Sstevel@tonic-gate 850Sstevel@tonic-gate /* 860Sstevel@tonic-gate * Hash-algo generic definitions. For now, they are SHA1's. We use SHA1 870Sstevel@tonic-gate * routines directly instead of using k-API because we can't return any 880Sstevel@tonic-gate * error code in /dev/urandom case and we can get an error using k-API 890Sstevel@tonic-gate * if a mechanism is disabled. 900Sstevel@tonic-gate */ 910Sstevel@tonic-gate #define HASHSIZE 20 920Sstevel@tonic-gate #define HASH_CTX SHA1_CTX 930Sstevel@tonic-gate #define HashInit(ctx) SHA1Init((ctx)) 940Sstevel@tonic-gate #define HashUpdate(ctx, p, s) SHA1Update((ctx), (p), (s)) 950Sstevel@tonic-gate #define HashFinal(d, ctx) SHA1Final((d), (ctx)) 960Sstevel@tonic-gate 970Sstevel@tonic-gate /* HMAC-SHA1 */ 980Sstevel@tonic-gate #define HMAC_KEYSIZE 20 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 1010Sstevel@tonic-gate * Cache of random bytes implemented as a circular buffer. findex and rindex 1020Sstevel@tonic-gate * track the front and back of the circular buffer. 1030Sstevel@tonic-gate */ 1040Sstevel@tonic-gate uint8_t rndpool[RNDPOOLSIZE]; 1050Sstevel@tonic-gate static int findex, rindex; 1060Sstevel@tonic-gate static int rnbyte_cnt; /* Number of bytes in the cache */ 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate static kmutex_t rndpool_lock; /* protects r/w accesses to the cache, */ 1090Sstevel@tonic-gate /* and the global variables */ 1100Sstevel@tonic-gate static kcondvar_t rndpool_read_cv; /* serializes poll/read syscalls */ 1110Sstevel@tonic-gate static int num_waiters; /* #threads waiting to read from /dev/random */ 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate static struct pollhead rnd_pollhead; 11410627Sopensolaris@drydog.com /* LINTED E_STATIC_UNUSED */ 1150Sstevel@tonic-gate static timeout_id_t kcf_rndtimeout_id; 1160Sstevel@tonic-gate static crypto_mech_type_t rngmech_type = CRYPTO_MECH_INVALID; 1170Sstevel@tonic-gate rnd_stats_t rnd_stats; 1183096Skrishna static boolean_t rng_prov_found = B_TRUE; 1193096Skrishna static boolean_t rng_ok_to_log = B_TRUE; 12010641SBhargava.Yenduri@Sun.COM static boolean_t rngprov_task_idle = B_TRUE; 1210Sstevel@tonic-gate 1220Sstevel@tonic-gate static void rndc_addbytes(uint8_t *, size_t); 1230Sstevel@tonic-gate static void rndc_getbytes(uint8_t *ptr, size_t len); 1240Sstevel@tonic-gate static void rnd_handler(void *); 1250Sstevel@tonic-gate static void rnd_alloc_magazines(); 1260Sstevel@tonic-gate 1270Sstevel@tonic-gate void 1280Sstevel@tonic-gate kcf_rnd_init() 1290Sstevel@tonic-gate { 1300Sstevel@tonic-gate hrtime_t ts; 1310Sstevel@tonic-gate time_t now; 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate mutex_init(&rndpool_lock, NULL, MUTEX_DEFAULT, NULL); 1340Sstevel@tonic-gate cv_init(&rndpool_read_cv, NULL, CV_DEFAULT, NULL); 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate /* 1370Sstevel@tonic-gate * Add bytes to the cache using 1380Sstevel@tonic-gate * . 2 unpredictable times: high resolution time since the boot-time, 1390Sstevel@tonic-gate * and the current time-of-the day. 1400Sstevel@tonic-gate * This is used only to make the timeout value in the timer 1410Sstevel@tonic-gate * unpredictable. 1420Sstevel@tonic-gate */ 1430Sstevel@tonic-gate ts = gethrtime(); 1440Sstevel@tonic-gate rndc_addbytes((uint8_t *)&ts, sizeof (ts)); 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate (void) drv_getparm(TIME, &now); 1470Sstevel@tonic-gate rndc_addbytes((uint8_t *)&now, sizeof (now)); 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate rnbyte_cnt = 0; 1500Sstevel@tonic-gate findex = rindex = 0; 1510Sstevel@tonic-gate num_waiters = 0; 1520Sstevel@tonic-gate rngmech_type = KCF_MECHID(KCF_MISC_CLASS, 0); 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate rnd_alloc_magazines(); 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate /* 1580Sstevel@tonic-gate * Return TRUE if at least one provider exists that can 1590Sstevel@tonic-gate * supply random numbers. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate boolean_t 1620Sstevel@tonic-gate kcf_rngprov_check(void) 1630Sstevel@tonic-gate { 1640Sstevel@tonic-gate int rv; 1650Sstevel@tonic-gate kcf_provider_desc_t *pd; 1660Sstevel@tonic-gate 16710444SVladimir.Kotal@Sun.COM if ((pd = kcf_get_mech_provider(rngmech_type, NULL, NULL, &rv, 1680Sstevel@tonic-gate NULL, CRYPTO_FG_RANDOM, B_FALSE, 0)) != NULL) { 1690Sstevel@tonic-gate KCF_PROV_REFRELE(pd); 1703096Skrishna /* 1713096Skrishna * We logged a warning once about no provider being available 1723096Skrishna * and now a provider became available. So, set the flag so 1733096Skrishna * that we can log again if the problem recurs. 1743096Skrishna */ 1753096Skrishna rng_ok_to_log = B_TRUE; 1763096Skrishna rng_prov_found = B_TRUE; 1770Sstevel@tonic-gate return (B_TRUE); 1783096Skrishna } else { 1793096Skrishna rng_prov_found = B_FALSE; 1800Sstevel@tonic-gate return (B_FALSE); 1813096Skrishna } 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate /* 1850Sstevel@tonic-gate * Pick a software-based provider and submit a request to seed 1860Sstevel@tonic-gate * its random number generator. 1870Sstevel@tonic-gate */ 1880Sstevel@tonic-gate static void 1891920Smcpowers rngprov_seed(uint8_t *buf, int len, uint_t entropy_est, uint32_t flags) 1900Sstevel@tonic-gate { 1910Sstevel@tonic-gate kcf_provider_desc_t *pd = NULL; 1920Sstevel@tonic-gate 1933708Skrishna if (kcf_get_sw_prov(rngmech_type, &pd, NULL, B_FALSE) == 1943708Skrishna CRYPTO_SUCCESS) { 1951920Smcpowers (void) KCF_PROV_SEED_RANDOM(pd, pd->pd_sid, buf, len, 1961920Smcpowers entropy_est, flags, NULL); 1970Sstevel@tonic-gate KCF_PROV_REFRELE(pd); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * This routine is called for blocking reads. 2030Sstevel@tonic-gate * 2040Sstevel@tonic-gate * The argument is_taskq_thr indicates whether the caller is 2050Sstevel@tonic-gate * the taskq thread dispatched by the timeout handler routine. 2060Sstevel@tonic-gate * In this case, we cycle through all the providers 2070Sstevel@tonic-gate * submitting a request to each provider to generate random numbers. 2080Sstevel@tonic-gate * 2090Sstevel@tonic-gate * For other cases, we pick a provider and submit a request to generate 2100Sstevel@tonic-gate * random numbers. We retry using another provider if we get an error. 2110Sstevel@tonic-gate * 2120Sstevel@tonic-gate * Returns the number of bytes that are written to 'ptr'. Returns -1 2130Sstevel@tonic-gate * if no provider is found. ptr and need are unchanged. 2140Sstevel@tonic-gate */ 2150Sstevel@tonic-gate static int 2169619SBhargava.Yenduri@Sun.COM rngprov_getbytes(uint8_t *ptr, size_t need, boolean_t is_taskq_thr) 2170Sstevel@tonic-gate { 2180Sstevel@tonic-gate int rv; 2190Sstevel@tonic-gate int prov_cnt = 0; 2200Sstevel@tonic-gate int total_bytes = 0; 2210Sstevel@tonic-gate kcf_provider_desc_t *pd; 2220Sstevel@tonic-gate kcf_req_params_t params; 2230Sstevel@tonic-gate kcf_prov_tried_t *list = NULL; 2240Sstevel@tonic-gate 22510444SVladimir.Kotal@Sun.COM while ((pd = kcf_get_mech_provider(rngmech_type, NULL, NULL, &rv, 2260Sstevel@tonic-gate list, CRYPTO_FG_RANDOM, B_FALSE, 0)) != NULL) { 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate prov_cnt++; 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate KCF_WRAP_RANDOM_OPS_PARAMS(¶ms, KCF_OP_RANDOM_GENERATE, 2311920Smcpowers pd->pd_sid, ptr, need, 0, 0); 2320Sstevel@tonic-gate rv = kcf_submit_request(pd, NULL, NULL, ¶ms, B_FALSE); 2330Sstevel@tonic-gate ASSERT(rv != CRYPTO_QUEUED); 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate if (rv == CRYPTO_SUCCESS) { 2360Sstevel@tonic-gate total_bytes += need; 2370Sstevel@tonic-gate if (is_taskq_thr) 2380Sstevel@tonic-gate rndc_addbytes(ptr, need); 2390Sstevel@tonic-gate else { 2400Sstevel@tonic-gate KCF_PROV_REFRELE(pd); 2410Sstevel@tonic-gate break; 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate } 2440Sstevel@tonic-gate 2450Sstevel@tonic-gate if (is_taskq_thr || rv != CRYPTO_SUCCESS) { 2460Sstevel@tonic-gate /* Add pd to the linked list of providers tried. */ 2470Sstevel@tonic-gate if (kcf_insert_triedlist(&list, pd, KM_SLEEP) == NULL) { 2480Sstevel@tonic-gate KCF_PROV_REFRELE(pd); 2490Sstevel@tonic-gate break; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate if (list != NULL) 2560Sstevel@tonic-gate kcf_free_triedlist(list); 2570Sstevel@tonic-gate 2580Sstevel@tonic-gate if (prov_cnt == 0) { /* no provider could be found. */ 2593096Skrishna rng_prov_found = B_FALSE; 2600Sstevel@tonic-gate return (-1); 2613096Skrishna } else { 2623096Skrishna rng_prov_found = B_TRUE; 2633096Skrishna /* See comments in kcf_rngprov_check() */ 2643096Skrishna rng_ok_to_log = B_TRUE; 2650Sstevel@tonic-gate } 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate return (total_bytes); 2680Sstevel@tonic-gate } 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate static void 2710Sstevel@tonic-gate notify_done(void *arg, int rv) 2720Sstevel@tonic-gate { 2730Sstevel@tonic-gate uchar_t *rndbuf = arg; 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate if (rv == CRYPTO_SUCCESS) 2760Sstevel@tonic-gate rndc_addbytes(rndbuf, MINEXTRACTBYTES); 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate bzero(rndbuf, MINEXTRACTBYTES); 2790Sstevel@tonic-gate kmem_free(rndbuf, MINEXTRACTBYTES); 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate /* 2830Sstevel@tonic-gate * Cycle through all the providers submitting a request to each provider 2840Sstevel@tonic-gate * to generate random numbers. This is called for the modes - NONBLOCK_EXTRACT 2850Sstevel@tonic-gate * and ALWAYS_EXTRACT. 2860Sstevel@tonic-gate * 2870Sstevel@tonic-gate * Returns the number of bytes that are written to 'ptr'. Returns -1 2880Sstevel@tonic-gate * if no provider is found. ptr and len are unchanged. 2890Sstevel@tonic-gate */ 2900Sstevel@tonic-gate static int 2919619SBhargava.Yenduri@Sun.COM rngprov_getbytes_nblk(uint8_t *ptr, size_t len) 2920Sstevel@tonic-gate { 29310627Sopensolaris@drydog.com int rv, total_bytes; 29410627Sopensolaris@drydog.com size_t blen; 2950Sstevel@tonic-gate uchar_t *rndbuf; 2960Sstevel@tonic-gate kcf_provider_desc_t *pd; 2970Sstevel@tonic-gate kcf_req_params_t params; 2980Sstevel@tonic-gate crypto_call_req_t req; 2990Sstevel@tonic-gate kcf_prov_tried_t *list = NULL; 3000Sstevel@tonic-gate int prov_cnt = 0; 3010Sstevel@tonic-gate 3020Sstevel@tonic-gate blen = 0; 3030Sstevel@tonic-gate total_bytes = 0; 3040Sstevel@tonic-gate req.cr_flag = CRYPTO_SKIP_REQID; 3050Sstevel@tonic-gate req.cr_callback_func = notify_done; 3060Sstevel@tonic-gate 30710444SVladimir.Kotal@Sun.COM while ((pd = kcf_get_mech_provider(rngmech_type, NULL, NULL, &rv, 3080Sstevel@tonic-gate list, CRYPTO_FG_RANDOM, CHECK_RESTRICT(&req), 0)) != NULL) { 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate prov_cnt ++; 3110Sstevel@tonic-gate switch (pd->pd_prov_type) { 3120Sstevel@tonic-gate case CRYPTO_HW_PROVIDER: 3130Sstevel@tonic-gate /* 3140Sstevel@tonic-gate * We have to allocate a buffer here as we can not 3150Sstevel@tonic-gate * assume that the input buffer will remain valid 3160Sstevel@tonic-gate * when the callback comes. We use a fixed size buffer 3170Sstevel@tonic-gate * to simplify the book keeping. 3180Sstevel@tonic-gate */ 3190Sstevel@tonic-gate rndbuf = kmem_alloc(MINEXTRACTBYTES, KM_NOSLEEP); 3200Sstevel@tonic-gate if (rndbuf == NULL) { 3210Sstevel@tonic-gate KCF_PROV_REFRELE(pd); 3220Sstevel@tonic-gate if (list != NULL) 3230Sstevel@tonic-gate kcf_free_triedlist(list); 3240Sstevel@tonic-gate return (total_bytes); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate req.cr_callback_arg = rndbuf; 3270Sstevel@tonic-gate KCF_WRAP_RANDOM_OPS_PARAMS(¶ms, 3280Sstevel@tonic-gate KCF_OP_RANDOM_GENERATE, 3291920Smcpowers pd->pd_sid, rndbuf, MINEXTRACTBYTES, 0, 0); 3300Sstevel@tonic-gate break; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate case CRYPTO_SW_PROVIDER: 3330Sstevel@tonic-gate /* 3340Sstevel@tonic-gate * We do not need to allocate a buffer in the software 3350Sstevel@tonic-gate * provider case as there is no callback involved. We 3360Sstevel@tonic-gate * avoid any extra data copy by directly passing 'ptr'. 3370Sstevel@tonic-gate */ 3380Sstevel@tonic-gate KCF_WRAP_RANDOM_OPS_PARAMS(¶ms, 3390Sstevel@tonic-gate KCF_OP_RANDOM_GENERATE, 3401920Smcpowers pd->pd_sid, ptr, len, 0, 0); 3410Sstevel@tonic-gate break; 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate rv = kcf_submit_request(pd, NULL, &req, ¶ms, B_FALSE); 3450Sstevel@tonic-gate if (rv == CRYPTO_SUCCESS) { 3460Sstevel@tonic-gate switch (pd->pd_prov_type) { 3470Sstevel@tonic-gate case CRYPTO_HW_PROVIDER: 3480Sstevel@tonic-gate /* 3490Sstevel@tonic-gate * Since we have the input buffer handy, 3500Sstevel@tonic-gate * we directly copy to it rather than 3510Sstevel@tonic-gate * adding to the pool. 3520Sstevel@tonic-gate */ 3530Sstevel@tonic-gate blen = min(MINEXTRACTBYTES, len); 3540Sstevel@tonic-gate bcopy(rndbuf, ptr, blen); 3550Sstevel@tonic-gate if (len < MINEXTRACTBYTES) 3560Sstevel@tonic-gate rndc_addbytes(rndbuf + len, 3570Sstevel@tonic-gate MINEXTRACTBYTES - len); 3580Sstevel@tonic-gate ptr += blen; 3590Sstevel@tonic-gate len -= blen; 3600Sstevel@tonic-gate total_bytes += blen; 3610Sstevel@tonic-gate break; 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate case CRYPTO_SW_PROVIDER: 3640Sstevel@tonic-gate total_bytes += len; 3650Sstevel@tonic-gate len = 0; 3660Sstevel@tonic-gate break; 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate /* 3710Sstevel@tonic-gate * We free the buffer in the callback routine 3720Sstevel@tonic-gate * for the CRYPTO_QUEUED case. 3730Sstevel@tonic-gate */ 3740Sstevel@tonic-gate if (pd->pd_prov_type == CRYPTO_HW_PROVIDER && 3750Sstevel@tonic-gate rv != CRYPTO_QUEUED) { 3760Sstevel@tonic-gate bzero(rndbuf, MINEXTRACTBYTES); 3770Sstevel@tonic-gate kmem_free(rndbuf, MINEXTRACTBYTES); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate if (len == 0) { 3810Sstevel@tonic-gate KCF_PROV_REFRELE(pd); 3820Sstevel@tonic-gate break; 3830Sstevel@tonic-gate } 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate if (rv != CRYPTO_SUCCESS) { 3860Sstevel@tonic-gate /* Add pd to the linked list of providers tried. */ 3870Sstevel@tonic-gate if (kcf_insert_triedlist(&list, pd, KM_NOSLEEP) == 3880Sstevel@tonic-gate NULL) { 3890Sstevel@tonic-gate KCF_PROV_REFRELE(pd); 3900Sstevel@tonic-gate break; 3910Sstevel@tonic-gate } 3920Sstevel@tonic-gate } 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate if (list != NULL) { 3960Sstevel@tonic-gate kcf_free_triedlist(list); 3970Sstevel@tonic-gate } 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate if (prov_cnt == 0) { /* no provider could be found. */ 4003096Skrishna rng_prov_found = B_FALSE; 4010Sstevel@tonic-gate return (-1); 4023096Skrishna } else { 4033096Skrishna rng_prov_found = B_TRUE; 4043096Skrishna /* See comments in kcf_rngprov_check() */ 4053096Skrishna rng_ok_to_log = B_TRUE; 4060Sstevel@tonic-gate } 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate return (total_bytes); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate static void 4120Sstevel@tonic-gate rngprov_task(void *arg) 4130Sstevel@tonic-gate { 4140Sstevel@tonic-gate int len = (int)(uintptr_t)arg; 4150Sstevel@tonic-gate uchar_t tbuf[MAXEXTRACTBYTES]; 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate ASSERT(len <= MAXEXTRACTBYTES); 4189619SBhargava.Yenduri@Sun.COM (void) rngprov_getbytes(tbuf, len, B_TRUE); 41910641SBhargava.Yenduri@Sun.COM rngprov_task_idle = B_TRUE; 4200Sstevel@tonic-gate } 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /* 4230Sstevel@tonic-gate * Returns "len" random or pseudo-random bytes in *ptr. 4240Sstevel@tonic-gate * Will block if not enough random bytes are available and the 4250Sstevel@tonic-gate * call is blocking. 4260Sstevel@tonic-gate * 4270Sstevel@tonic-gate * Called with rndpool_lock held (allowing caller to do optimistic locking; 4280Sstevel@tonic-gate * releases the lock before return). 4290Sstevel@tonic-gate */ 4300Sstevel@tonic-gate static int 4319619SBhargava.Yenduri@Sun.COM rnd_get_bytes(uint8_t *ptr, size_t len, extract_type_t how) 4320Sstevel@tonic-gate { 43310627Sopensolaris@drydog.com size_t bytes; 4340Sstevel@tonic-gate size_t got; 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate ASSERT(mutex_owned(&rndpool_lock)); 4370Sstevel@tonic-gate /* 4380Sstevel@tonic-gate * Check if the request can be satisfied from the cache 4390Sstevel@tonic-gate * of random bytes. 4400Sstevel@tonic-gate */ 4410Sstevel@tonic-gate if (len <= rnbyte_cnt) { 4420Sstevel@tonic-gate rndc_getbytes(ptr, len); 4430Sstevel@tonic-gate mutex_exit(&rndpool_lock); 4440Sstevel@tonic-gate return (0); 4450Sstevel@tonic-gate } 4460Sstevel@tonic-gate mutex_exit(&rndpool_lock); 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate switch (how) { 4490Sstevel@tonic-gate case BLOCKING_EXTRACT: 4509619SBhargava.Yenduri@Sun.COM if ((got = rngprov_getbytes(ptr, len, B_FALSE)) == -1) 4510Sstevel@tonic-gate break; /* No provider found */ 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate if (got == len) 4540Sstevel@tonic-gate return (0); 4550Sstevel@tonic-gate len -= got; 4560Sstevel@tonic-gate ptr += got; 4570Sstevel@tonic-gate break; 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate case NONBLOCK_EXTRACT: 4600Sstevel@tonic-gate case ALWAYS_EXTRACT: 4619619SBhargava.Yenduri@Sun.COM if ((got = rngprov_getbytes_nblk(ptr, len)) == -1) { 4620Sstevel@tonic-gate /* No provider found */ 4630Sstevel@tonic-gate if (how == NONBLOCK_EXTRACT) { 4640Sstevel@tonic-gate return (EAGAIN); 4650Sstevel@tonic-gate } 4660Sstevel@tonic-gate } else { 4670Sstevel@tonic-gate if (got == len) 4680Sstevel@tonic-gate return (0); 4690Sstevel@tonic-gate len -= got; 4700Sstevel@tonic-gate ptr += got; 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate if (how == NONBLOCK_EXTRACT && (rnbyte_cnt < len)) 4730Sstevel@tonic-gate return (EAGAIN); 4740Sstevel@tonic-gate break; 4750Sstevel@tonic-gate } 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate mutex_enter(&rndpool_lock); 4780Sstevel@tonic-gate while (len > 0) { 4790Sstevel@tonic-gate if (how == BLOCKING_EXTRACT) { 4800Sstevel@tonic-gate /* Check if there is enough */ 4810Sstevel@tonic-gate while (rnbyte_cnt < MINEXTRACTBYTES) { 4820Sstevel@tonic-gate num_waiters++; 4830Sstevel@tonic-gate if (cv_wait_sig(&rndpool_read_cv, 4840Sstevel@tonic-gate &rndpool_lock) == 0) { 4850Sstevel@tonic-gate num_waiters--; 4860Sstevel@tonic-gate mutex_exit(&rndpool_lock); 4870Sstevel@tonic-gate return (EINTR); 4880Sstevel@tonic-gate } 4890Sstevel@tonic-gate num_waiters--; 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /* Figure out how many bytes to extract */ 4940Sstevel@tonic-gate bytes = min(len, rnbyte_cnt); 4950Sstevel@tonic-gate rndc_getbytes(ptr, bytes); 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate len -= bytes; 4980Sstevel@tonic-gate ptr += bytes; 4990Sstevel@tonic-gate 5000Sstevel@tonic-gate if (len > 0 && how == ALWAYS_EXTRACT) { 5010Sstevel@tonic-gate /* 5020Sstevel@tonic-gate * There are not enough bytes, but we can not block. 5030Sstevel@tonic-gate * This only happens in the case of /dev/urandom which 5040Sstevel@tonic-gate * runs an additional generation algorithm. So, there 5050Sstevel@tonic-gate * is no problem. 5060Sstevel@tonic-gate */ 5070Sstevel@tonic-gate while (len > 0) { 5080Sstevel@tonic-gate *ptr = rndpool[findex]; 5090Sstevel@tonic-gate ptr++; len--; 5100Sstevel@tonic-gate rindex = findex = (findex + 1) & 5110Sstevel@tonic-gate (RNDPOOLSIZE - 1); 5120Sstevel@tonic-gate } 5130Sstevel@tonic-gate break; 5140Sstevel@tonic-gate } 5150Sstevel@tonic-gate } 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate mutex_exit(&rndpool_lock); 5180Sstevel@tonic-gate return (0); 5190Sstevel@tonic-gate } 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate int 5229619SBhargava.Yenduri@Sun.COM kcf_rnd_get_bytes(uint8_t *ptr, size_t len, boolean_t noblock) 5230Sstevel@tonic-gate { 5240Sstevel@tonic-gate extract_type_t how; 5250Sstevel@tonic-gate int error; 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate how = noblock ? NONBLOCK_EXTRACT : BLOCKING_EXTRACT; 5280Sstevel@tonic-gate mutex_enter(&rndpool_lock); 5299619SBhargava.Yenduri@Sun.COM if ((error = rnd_get_bytes(ptr, len, how)) != 0) 5300Sstevel@tonic-gate return (error); 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate BUMP_RND_STATS(rs_rndOut, len); 5330Sstevel@tonic-gate return (0); 5340Sstevel@tonic-gate } 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate /* 5370Sstevel@tonic-gate * Revisit this if the structs grow or we come up with a better way 5380Sstevel@tonic-gate * of cache-line-padding structures. 5390Sstevel@tonic-gate */ 5400Sstevel@tonic-gate #define RND_CPU_CACHE_SIZE 64 5418029SHai-May.Chao@Sun.COM #define RND_CPU_PAD_SIZE RND_CPU_CACHE_SIZE*6 5420Sstevel@tonic-gate #define RND_CPU_PAD (RND_CPU_PAD_SIZE - \ 5438029SHai-May.Chao@Sun.COM sizeof (rndmag_t)) 5440Sstevel@tonic-gate /* 5450Sstevel@tonic-gate * Per-CPU random state. Somewhat like like kmem's magazines, this provides 5460Sstevel@tonic-gate * a per-CPU instance of the pseudo-random generator. We have it much easier 5470Sstevel@tonic-gate * than kmem, as we can afford to "leak" random bits if a CPU is DR'ed out. 5480Sstevel@tonic-gate * 5490Sstevel@tonic-gate * Note that this usage is preemption-safe; a thread 5500Sstevel@tonic-gate * entering a critical section remembers which generator it locked 5510Sstevel@tonic-gate * and unlocks the same one; should it be preempted and wind up running on 5520Sstevel@tonic-gate * a different CPU, there will be a brief period of increased contention 5530Sstevel@tonic-gate * before it exits the critical section but nothing will melt. 5540Sstevel@tonic-gate */ 5550Sstevel@tonic-gate typedef struct rndmag_s 5560Sstevel@tonic-gate { 5570Sstevel@tonic-gate kmutex_t rm_lock; 5588733SHai-May.Chao@Sun.COM uint8_t *rm_buffer; /* Start of buffer */ 5590Sstevel@tonic-gate uint8_t *rm_eptr; /* End of buffer */ 5600Sstevel@tonic-gate uint8_t *rm_rptr; /* Current read pointer */ 5610Sstevel@tonic-gate uint32_t rm_oblocks; /* time to rekey? */ 5620Sstevel@tonic-gate uint32_t rm_ofuzz; /* Rekey backoff state */ 5630Sstevel@tonic-gate uint32_t rm_olimit; /* Hard rekey limit */ 5640Sstevel@tonic-gate rnd_stats_t rm_stats; /* Per-CPU Statistics */ 5658733SHai-May.Chao@Sun.COM uint32_t rm_key[HASHSIZE/BYTES_IN_WORD]; /* FIPS XKEY */ 5668733SHai-May.Chao@Sun.COM uint32_t rm_seed[HASHSIZE/BYTES_IN_WORD]; /* seed for rekey */ 5678733SHai-May.Chao@Sun.COM uint32_t rm_previous[HASHSIZE/BYTES_IN_WORD]; /* prev random */ 5680Sstevel@tonic-gate } rndmag_t; 5690Sstevel@tonic-gate 5708029SHai-May.Chao@Sun.COM typedef struct rndmag_pad_s 5718029SHai-May.Chao@Sun.COM { 5728029SHai-May.Chao@Sun.COM rndmag_t rm_mag; 5738029SHai-May.Chao@Sun.COM uint8_t rm_pad[RND_CPU_PAD]; 5748029SHai-May.Chao@Sun.COM } rndmag_pad_t; 5758029SHai-May.Chao@Sun.COM 5760Sstevel@tonic-gate /* 5778029SHai-May.Chao@Sun.COM * Generate random bytes for /dev/urandom by applying the 5788029SHai-May.Chao@Sun.COM * FIPS 186-2 algorithm with a key created from bytes extracted 5790Sstevel@tonic-gate * from the pool. A maximum of PRNG_MAXOBLOCKS output blocks 5800Sstevel@tonic-gate * is generated before a new key is obtained. 5810Sstevel@tonic-gate * 5820Sstevel@tonic-gate * Note that callers to this routine are likely to assume it can't fail. 5830Sstevel@tonic-gate * 5840Sstevel@tonic-gate * Called with rmp locked; releases lock. 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate static int 5878029SHai-May.Chao@Sun.COM rnd_generate_pseudo_bytes(rndmag_pad_t *rmp, uint8_t *ptr, size_t len) 5880Sstevel@tonic-gate { 58910627Sopensolaris@drydog.com size_t bytes = len, size; 59010627Sopensolaris@drydog.com int nblock; 5910Sstevel@tonic-gate uint32_t oblocks; 5928733SHai-May.Chao@Sun.COM uint32_t tempout[HASHSIZE/BYTES_IN_WORD]; 5938733SHai-May.Chao@Sun.COM uint32_t seed[HASHSIZE/BYTES_IN_WORD]; 5948029SHai-May.Chao@Sun.COM int i; 5958029SHai-May.Chao@Sun.COM hrtime_t timestamp; 5968029SHai-May.Chao@Sun.COM uint8_t *src, *dst; 5970Sstevel@tonic-gate 5988029SHai-May.Chao@Sun.COM ASSERT(mutex_owned(&rmp->rm_mag.rm_lock)); 5990Sstevel@tonic-gate 6000Sstevel@tonic-gate /* Nothing is being asked */ 6010Sstevel@tonic-gate if (len == 0) { 6028029SHai-May.Chao@Sun.COM mutex_exit(&rmp->rm_mag.rm_lock); 6030Sstevel@tonic-gate return (0); 6040Sstevel@tonic-gate } 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate nblock = howmany(len, HASHSIZE); 6070Sstevel@tonic-gate 6088029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_oblocks += nblock; 6098029SHai-May.Chao@Sun.COM oblocks = rmp->rm_mag.rm_oblocks; 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate do { 6128029SHai-May.Chao@Sun.COM if (oblocks >= rmp->rm_mag.rm_olimit) { 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate /* 6150Sstevel@tonic-gate * Contention-avoiding rekey: see if 6160Sstevel@tonic-gate * the pool is locked, and if so, wait a bit. 6170Sstevel@tonic-gate * Do an 'exponential back-in' to ensure we don't 6180Sstevel@tonic-gate * run too long without rekey. 6190Sstevel@tonic-gate */ 6208029SHai-May.Chao@Sun.COM if (rmp->rm_mag.rm_ofuzz) { 6210Sstevel@tonic-gate /* 6220Sstevel@tonic-gate * Decaying exponential back-in for rekey. 6230Sstevel@tonic-gate */ 6240Sstevel@tonic-gate if ((rnbyte_cnt < MINEXTRACTBYTES) || 6250Sstevel@tonic-gate (!mutex_tryenter(&rndpool_lock))) { 6268029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_olimit += 6278029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_ofuzz; 6288029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_ofuzz >>= 1; 6290Sstevel@tonic-gate goto punt; 6300Sstevel@tonic-gate } 6310Sstevel@tonic-gate } else { 6320Sstevel@tonic-gate mutex_enter(&rndpool_lock); 6330Sstevel@tonic-gate } 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate /* Get a new chunk of entropy */ 6368029SHai-May.Chao@Sun.COM (void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_key, 6379619SBhargava.Yenduri@Sun.COM HMAC_KEYSIZE, ALWAYS_EXTRACT); 6380Sstevel@tonic-gate 6398029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_olimit = PRNG_MAXOBLOCKS/2; 6408029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_ofuzz = PRNG_MAXOBLOCKS/4; 6410Sstevel@tonic-gate oblocks = 0; 6428029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_oblocks = nblock; 6430Sstevel@tonic-gate } 6440Sstevel@tonic-gate punt: 6458029SHai-May.Chao@Sun.COM timestamp = gethrtime(); 6468029SHai-May.Chao@Sun.COM 6478029SHai-May.Chao@Sun.COM src = (uint8_t *)×tamp; 6488029SHai-May.Chao@Sun.COM dst = (uint8_t *)rmp->rm_mag.rm_seed; 6498029SHai-May.Chao@Sun.COM 6508029SHai-May.Chao@Sun.COM for (i = 0; i < HASHSIZE; i++) { 6518029SHai-May.Chao@Sun.COM dst[i] ^= src[i % sizeof (timestamp)]; 6528029SHai-May.Chao@Sun.COM } 6538029SHai-May.Chao@Sun.COM 6548029SHai-May.Chao@Sun.COM bcopy(rmp->rm_mag.rm_seed, seed, HASHSIZE); 6558029SHai-May.Chao@Sun.COM 6568029SHai-May.Chao@Sun.COM fips_random_inner(rmp->rm_mag.rm_key, tempout, 6578029SHai-May.Chao@Sun.COM seed); 6588029SHai-May.Chao@Sun.COM 6590Sstevel@tonic-gate if (bytes >= HASHSIZE) { 6600Sstevel@tonic-gate size = HASHSIZE; 6610Sstevel@tonic-gate } else { 6620Sstevel@tonic-gate size = min(bytes, HASHSIZE); 6630Sstevel@tonic-gate } 6648029SHai-May.Chao@Sun.COM 6658029SHai-May.Chao@Sun.COM /* 6668029SHai-May.Chao@Sun.COM * FIPS 140-2: Continuous RNG test - each generation 6678029SHai-May.Chao@Sun.COM * of an n-bit block shall be compared with the previously 6688029SHai-May.Chao@Sun.COM * generated block. Test shall fail if any two compared 6698029SHai-May.Chao@Sun.COM * n-bit blocks are equal. 6708029SHai-May.Chao@Sun.COM */ 6718733SHai-May.Chao@Sun.COM for (i = 0; i < HASHSIZE/BYTES_IN_WORD; i++) { 6728029SHai-May.Chao@Sun.COM if (tempout[i] != rmp->rm_mag.rm_previous[i]) 6738029SHai-May.Chao@Sun.COM break; 6748029SHai-May.Chao@Sun.COM } 67510500SHai-May.Chao@Sun.COM if (i == HASHSIZE/BYTES_IN_WORD) { 6768029SHai-May.Chao@Sun.COM cmn_err(CE_WARN, "kcf_random: The value of 160-bit " 6778029SHai-May.Chao@Sun.COM "block random bytes are same as the previous " 6788029SHai-May.Chao@Sun.COM "one.\n"); 67910500SHai-May.Chao@Sun.COM /* discard random bytes and return error */ 68010500SHai-May.Chao@Sun.COM return (EIO); 68110500SHai-May.Chao@Sun.COM } 6828029SHai-May.Chao@Sun.COM 6838029SHai-May.Chao@Sun.COM bcopy(tempout, rmp->rm_mag.rm_previous, 6848029SHai-May.Chao@Sun.COM HASHSIZE); 6858029SHai-May.Chao@Sun.COM 6868029SHai-May.Chao@Sun.COM bcopy(tempout, ptr, size); 6870Sstevel@tonic-gate ptr += size; 6880Sstevel@tonic-gate bytes -= size; 6890Sstevel@tonic-gate oblocks++; 6900Sstevel@tonic-gate nblock--; 6910Sstevel@tonic-gate } while (bytes > 0); 6920Sstevel@tonic-gate 6938029SHai-May.Chao@Sun.COM /* Zero out sensitive information */ 6948029SHai-May.Chao@Sun.COM bzero(seed, HASHSIZE); 6958029SHai-May.Chao@Sun.COM bzero(tempout, HASHSIZE); 6968029SHai-May.Chao@Sun.COM mutex_exit(&rmp->rm_mag.rm_lock); 6970Sstevel@tonic-gate return (0); 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * Per-CPU Random magazines. 7020Sstevel@tonic-gate */ 7038029SHai-May.Chao@Sun.COM static rndmag_pad_t *rndmag; 7040Sstevel@tonic-gate static uint8_t *rndbuf; 7050Sstevel@tonic-gate static size_t rndmag_total; 7060Sstevel@tonic-gate /* 7070Sstevel@tonic-gate * common/os/cpu.c says that platform support code can shrinkwrap 7080Sstevel@tonic-gate * max_ncpus. On the off chance that we get loaded very early, we 7090Sstevel@tonic-gate * read it exactly once, to copy it here. 7100Sstevel@tonic-gate */ 7110Sstevel@tonic-gate static uint32_t random_max_ncpus = 0; 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate /* 7140Sstevel@tonic-gate * Boot-time tunables, for experimentation. 7150Sstevel@tonic-gate */ 7161070Skais size_t rndmag_threshold = 2560; 7171070Skais size_t rndbuf_len = 5120; 718445Skrishna size_t rndmag_size = 1280; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate int 7220Sstevel@tonic-gate kcf_rnd_get_pseudo_bytes(uint8_t *ptr, size_t len) 7230Sstevel@tonic-gate { 7248029SHai-May.Chao@Sun.COM rndmag_pad_t *rmp; 7250Sstevel@tonic-gate uint8_t *cptr, *eptr; 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate /* 7280Sstevel@tonic-gate * Anyone who asks for zero bytes of randomness should get slapped. 7290Sstevel@tonic-gate */ 7300Sstevel@tonic-gate ASSERT(len > 0); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * Fast path. 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate for (;;) { 7360Sstevel@tonic-gate rmp = &rndmag[CPU->cpu_seqid]; 7378029SHai-May.Chao@Sun.COM mutex_enter(&rmp->rm_mag.rm_lock); 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate /* 7400Sstevel@tonic-gate * Big requests bypass buffer and tail-call the 7410Sstevel@tonic-gate * generate routine directly. 7420Sstevel@tonic-gate */ 7430Sstevel@tonic-gate if (len > rndmag_threshold) { 7440Sstevel@tonic-gate BUMP_CPU_RND_STATS(rmp, rs_urndOut, len); 7450Sstevel@tonic-gate return (rnd_generate_pseudo_bytes(rmp, ptr, len)); 7460Sstevel@tonic-gate } 7470Sstevel@tonic-gate 7488029SHai-May.Chao@Sun.COM cptr = rmp->rm_mag.rm_rptr; 7490Sstevel@tonic-gate eptr = cptr + len; 7500Sstevel@tonic-gate 7518029SHai-May.Chao@Sun.COM if (eptr <= rmp->rm_mag.rm_eptr) { 7528029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_rptr = eptr; 7530Sstevel@tonic-gate bcopy(cptr, ptr, len); 7540Sstevel@tonic-gate BUMP_CPU_RND_STATS(rmp, rs_urndOut, len); 7558029SHai-May.Chao@Sun.COM mutex_exit(&rmp->rm_mag.rm_lock); 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate return (0); 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate /* 7600Sstevel@tonic-gate * End fast path. 7610Sstevel@tonic-gate */ 7628029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_rptr = rmp->rm_mag.rm_buffer; 7630Sstevel@tonic-gate /* 7640Sstevel@tonic-gate * Note: We assume the generate routine always succeeds 7650Sstevel@tonic-gate * in this case (because it does at present..) 7660Sstevel@tonic-gate * It also always releases rm_lock. 7670Sstevel@tonic-gate */ 7688029SHai-May.Chao@Sun.COM (void) rnd_generate_pseudo_bytes(rmp, rmp->rm_mag.rm_buffer, 7690Sstevel@tonic-gate rndbuf_len); 7700Sstevel@tonic-gate } 7710Sstevel@tonic-gate } 7720Sstevel@tonic-gate 7730Sstevel@tonic-gate /* 7740Sstevel@tonic-gate * We set up (empty) magazines for all of max_ncpus, possibly wasting a 7750Sstevel@tonic-gate * little memory on big systems that don't have the full set installed. 7760Sstevel@tonic-gate * See above; "empty" means "rptr equal to eptr"; this will trigger the 7770Sstevel@tonic-gate * refill path in rnd_get_pseudo_bytes above on the first call for each CPU. 7780Sstevel@tonic-gate * 7790Sstevel@tonic-gate * TODO: make rndmag_size tunable at run time! 7800Sstevel@tonic-gate */ 7810Sstevel@tonic-gate static void 7820Sstevel@tonic-gate rnd_alloc_magazines() 7830Sstevel@tonic-gate { 7848029SHai-May.Chao@Sun.COM rndmag_pad_t *rmp; 7850Sstevel@tonic-gate int i; 7868029SHai-May.Chao@Sun.COM uint8_t discard_buf[HASHSIZE]; 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate rndbuf_len = roundup(rndbuf_len, HASHSIZE); 7890Sstevel@tonic-gate if (rndmag_size < rndbuf_len) 7900Sstevel@tonic-gate rndmag_size = rndbuf_len; 7910Sstevel@tonic-gate rndmag_size = roundup(rndmag_size, RND_CPU_CACHE_SIZE); 7920Sstevel@tonic-gate 7930Sstevel@tonic-gate random_max_ncpus = max_ncpus; 7940Sstevel@tonic-gate rndmag_total = rndmag_size * random_max_ncpus; 7950Sstevel@tonic-gate 7960Sstevel@tonic-gate rndbuf = kmem_alloc(rndmag_total, KM_SLEEP); 7978029SHai-May.Chao@Sun.COM rndmag = kmem_zalloc(sizeof (rndmag_pad_t) * random_max_ncpus, 7988029SHai-May.Chao@Sun.COM KM_SLEEP); 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate for (i = 0; i < random_max_ncpus; i++) { 8010Sstevel@tonic-gate uint8_t *buf; 8020Sstevel@tonic-gate 8030Sstevel@tonic-gate rmp = &rndmag[i]; 8048029SHai-May.Chao@Sun.COM mutex_init(&rmp->rm_mag.rm_lock, NULL, MUTEX_DRIVER, NULL); 8050Sstevel@tonic-gate 8060Sstevel@tonic-gate buf = rndbuf + i * rndmag_size; 8070Sstevel@tonic-gate 8088029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_buffer = buf; 8098029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_eptr = buf + rndbuf_len; 8108029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_rptr = buf + rndbuf_len; 8118029SHai-May.Chao@Sun.COM rmp->rm_mag.rm_oblocks = 1; 8128029SHai-May.Chao@Sun.COM 8138029SHai-May.Chao@Sun.COM mutex_enter(&rndpool_lock); 8148029SHai-May.Chao@Sun.COM /* 8158029SHai-May.Chao@Sun.COM * FIPS 140-2: the first n-bit (n > 15) block generated 8168029SHai-May.Chao@Sun.COM * after power-up, initialization, or reset shall not 8178029SHai-May.Chao@Sun.COM * be used, but shall be saved for comparison. 8188029SHai-May.Chao@Sun.COM */ 8198029SHai-May.Chao@Sun.COM (void) rnd_get_bytes(discard_buf, 8209619SBhargava.Yenduri@Sun.COM HMAC_KEYSIZE, ALWAYS_EXTRACT); 8218029SHai-May.Chao@Sun.COM bcopy(discard_buf, rmp->rm_mag.rm_previous, 8228029SHai-May.Chao@Sun.COM HMAC_KEYSIZE); 8238029SHai-May.Chao@Sun.COM /* rnd_get_bytes() will call mutex_exit(&rndpool_lock) */ 8248029SHai-May.Chao@Sun.COM mutex_enter(&rndpool_lock); 8258029SHai-May.Chao@Sun.COM (void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_key, 8269619SBhargava.Yenduri@Sun.COM HMAC_KEYSIZE, ALWAYS_EXTRACT); 8278029SHai-May.Chao@Sun.COM /* rnd_get_bytes() will call mutex_exit(&rndpool_lock) */ 8288029SHai-May.Chao@Sun.COM mutex_enter(&rndpool_lock); 8298029SHai-May.Chao@Sun.COM (void) rnd_get_bytes((uint8_t *)rmp->rm_mag.rm_seed, 8309619SBhargava.Yenduri@Sun.COM HMAC_KEYSIZE, ALWAYS_EXTRACT); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate } 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate void 8350Sstevel@tonic-gate kcf_rnd_schedule_timeout(boolean_t do_mech2id) 8360Sstevel@tonic-gate { 8370Sstevel@tonic-gate clock_t ut; /* time in microseconds */ 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate if (do_mech2id) 8400Sstevel@tonic-gate rngmech_type = crypto_mech2id(SUN_RANDOM); 8410Sstevel@tonic-gate 8420Sstevel@tonic-gate /* 8430Sstevel@tonic-gate * The new timeout value is taken from the buffer of random bytes. 8440Sstevel@tonic-gate * We're merely reading the first 32 bits from the buffer here, not 8450Sstevel@tonic-gate * consuming any random bytes. 8460Sstevel@tonic-gate * The timeout multiplier value is a random value between 0.5 sec and 8470Sstevel@tonic-gate * 1.544480 sec (0.5 sec + 0xFF000 microseconds). 8480Sstevel@tonic-gate * The new timeout is TIMEOUT_INTERVAL times that multiplier. 8490Sstevel@tonic-gate */ 8500Sstevel@tonic-gate ut = 500000 + (clock_t)((((uint32_t)rndpool[findex]) << 12) & 0xFF000); 8510Sstevel@tonic-gate kcf_rndtimeout_id = timeout(rnd_handler, NULL, 8520Sstevel@tonic-gate TIMEOUT_INTERVAL * drv_usectohz(ut)); 8530Sstevel@tonic-gate } 8540Sstevel@tonic-gate 8550Sstevel@tonic-gate /* 8568928SBhargava.Yenduri@Sun.COM * Called from the driver for a poll on /dev/random 8578928SBhargava.Yenduri@Sun.COM * . POLLOUT always succeeds. 8588928SBhargava.Yenduri@Sun.COM * . POLLIN and POLLRDNORM will block until a 8598928SBhargava.Yenduri@Sun.COM * minimum amount of entropy is available. 8608928SBhargava.Yenduri@Sun.COM * 8610Sstevel@tonic-gate * &rnd_pollhead is passed in *phpp in order to indicate the calling thread 8620Sstevel@tonic-gate * will block. When enough random bytes are available, later, the timeout 8630Sstevel@tonic-gate * handler routine will issue the pollwakeup() calls. 8640Sstevel@tonic-gate */ 8650Sstevel@tonic-gate void 8668928SBhargava.Yenduri@Sun.COM kcf_rnd_chpoll(short events, int anyyet, short *reventsp, 8678928SBhargava.Yenduri@Sun.COM struct pollhead **phpp) 8680Sstevel@tonic-gate { 8698928SBhargava.Yenduri@Sun.COM *reventsp = events & POLLOUT; 8708928SBhargava.Yenduri@Sun.COM 8718928SBhargava.Yenduri@Sun.COM if (events & (POLLIN | POLLRDNORM)) { 8728928SBhargava.Yenduri@Sun.COM /* 8738928SBhargava.Yenduri@Sun.COM * Sampling of rnbyte_cnt is an atomic 8748928SBhargava.Yenduri@Sun.COM * operation. Hence we do not need any locking. 8758928SBhargava.Yenduri@Sun.COM */ 8768928SBhargava.Yenduri@Sun.COM if (rnbyte_cnt >= MINEXTRACTBYTES) 8778928SBhargava.Yenduri@Sun.COM *reventsp |= (events & (POLLIN | POLLRDNORM)); 8780Sstevel@tonic-gate } 8798928SBhargava.Yenduri@Sun.COM 8808928SBhargava.Yenduri@Sun.COM if (*reventsp == 0 && !anyyet) 8818928SBhargava.Yenduri@Sun.COM *phpp = &rnd_pollhead; 8820Sstevel@tonic-gate } 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate /*ARGSUSED*/ 8850Sstevel@tonic-gate static void 8860Sstevel@tonic-gate rnd_handler(void *arg) 8870Sstevel@tonic-gate { 8880Sstevel@tonic-gate int len = 0; 8890Sstevel@tonic-gate 8903096Skrishna if (!rng_prov_found && rng_ok_to_log) { 8913096Skrishna cmn_err(CE_WARN, "No randomness provider enabled for " 8923096Skrishna "/dev/random. Use cryptoadm(1M) to enable a provider."); 8933096Skrishna rng_ok_to_log = B_FALSE; 8943096Skrishna } 8953096Skrishna 8960Sstevel@tonic-gate if (num_waiters > 0) 89710641SBhargava.Yenduri@Sun.COM /* 89810641SBhargava.Yenduri@Sun.COM * Note: len has no relationship with how many bytes 89910641SBhargava.Yenduri@Sun.COM * a poll thread needs. 90010641SBhargava.Yenduri@Sun.COM */ 9010Sstevel@tonic-gate len = MAXEXTRACTBYTES; 9020Sstevel@tonic-gate else if (rnbyte_cnt < RNDPOOLSIZE) 9030Sstevel@tonic-gate len = MINEXTRACTBYTES; 9040Sstevel@tonic-gate 90510641SBhargava.Yenduri@Sun.COM /* 90610641SBhargava.Yenduri@Sun.COM * Only one thread gets to set rngprov_task_idle at a given point 90710641SBhargava.Yenduri@Sun.COM * of time and the order of the writes is defined. Also, it is OK 90810641SBhargava.Yenduri@Sun.COM * if we read an older value of it and skip the dispatch once 90910641SBhargava.Yenduri@Sun.COM * since we will get the correct value during the next time here. 91010641SBhargava.Yenduri@Sun.COM * So, no locking is needed here. 91110641SBhargava.Yenduri@Sun.COM */ 91210641SBhargava.Yenduri@Sun.COM if (len > 0 && rngprov_task_idle) { 91310641SBhargava.Yenduri@Sun.COM rngprov_task_idle = B_FALSE; 91410641SBhargava.Yenduri@Sun.COM 91510641SBhargava.Yenduri@Sun.COM /* 91610641SBhargava.Yenduri@Sun.COM * It is OK if taskq_dispatch fails here. We will retry 91710641SBhargava.Yenduri@Sun.COM * the next time around. Meanwhile, a thread doing a 91810641SBhargava.Yenduri@Sun.COM * read() will go to the provider directly, if the 91910641SBhargava.Yenduri@Sun.COM * cache becomes empty. 92010641SBhargava.Yenduri@Sun.COM */ 92110641SBhargava.Yenduri@Sun.COM if (taskq_dispatch(system_taskq, rngprov_task, 92210641SBhargava.Yenduri@Sun.COM (void *)(uintptr_t)len, TQ_NOSLEEP | TQ_NOQUEUE) == 0) { 92310641SBhargava.Yenduri@Sun.COM rngprov_task_idle = B_TRUE; 92410641SBhargava.Yenduri@Sun.COM } 9250Sstevel@tonic-gate } 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate mutex_enter(&rndpool_lock); 9280Sstevel@tonic-gate /* 9290Sstevel@tonic-gate * Wake up threads waiting in poll() or for enough accumulated 9300Sstevel@tonic-gate * random bytes to read from /dev/random. In case a poll() is 9310Sstevel@tonic-gate * concurrent with a read(), the polling process may be woken up 9320Sstevel@tonic-gate * indicating that enough randomness is now available for reading, 9330Sstevel@tonic-gate * and another process *steals* the bits from the pool, causing the 9340Sstevel@tonic-gate * subsequent read() from the first process to block. It is acceptable 9350Sstevel@tonic-gate * since the blocking will eventually end, after the timeout 9360Sstevel@tonic-gate * has expired enough times to honor the read. 9370Sstevel@tonic-gate * 9380Sstevel@tonic-gate * Note - Since we hold the rndpool_lock across the pollwakeup() call 9390Sstevel@tonic-gate * we MUST NOT grab the rndpool_lock in kcf_rndchpoll(). 9400Sstevel@tonic-gate */ 9410Sstevel@tonic-gate if (rnbyte_cnt >= MINEXTRACTBYTES) 9420Sstevel@tonic-gate pollwakeup(&rnd_pollhead, POLLIN | POLLRDNORM); 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate if (num_waiters > 0) 9450Sstevel@tonic-gate cv_broadcast(&rndpool_read_cv); 9460Sstevel@tonic-gate mutex_exit(&rndpool_lock); 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate kcf_rnd_schedule_timeout(B_FALSE); 9490Sstevel@tonic-gate } 9500Sstevel@tonic-gate 9510Sstevel@tonic-gate static void 9520Sstevel@tonic-gate rndc_addbytes(uint8_t *ptr, size_t len) 9530Sstevel@tonic-gate { 9540Sstevel@tonic-gate ASSERT(ptr != NULL && len > 0); 9550Sstevel@tonic-gate ASSERT(rnbyte_cnt <= RNDPOOLSIZE); 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate mutex_enter(&rndpool_lock); 9580Sstevel@tonic-gate while ((len > 0) && (rnbyte_cnt < RNDPOOLSIZE)) { 9590Sstevel@tonic-gate rndpool[rindex] ^= *ptr; 9600Sstevel@tonic-gate ptr++; len--; 9610Sstevel@tonic-gate rindex = (rindex + 1) & (RNDPOOLSIZE - 1); 9620Sstevel@tonic-gate rnbyte_cnt++; 9630Sstevel@tonic-gate } 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate /* Handle buffer full case */ 9660Sstevel@tonic-gate while (len > 0) { 9670Sstevel@tonic-gate rndpool[rindex] ^= *ptr; 9680Sstevel@tonic-gate ptr++; len--; 9690Sstevel@tonic-gate findex = rindex = (rindex + 1) & (RNDPOOLSIZE - 1); 9700Sstevel@tonic-gate } 9710Sstevel@tonic-gate mutex_exit(&rndpool_lock); 9720Sstevel@tonic-gate } 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate /* 9750Sstevel@tonic-gate * Caller should check len <= rnbyte_cnt under the 9760Sstevel@tonic-gate * rndpool_lock before calling. 9770Sstevel@tonic-gate */ 9780Sstevel@tonic-gate static void 9790Sstevel@tonic-gate rndc_getbytes(uint8_t *ptr, size_t len) 9800Sstevel@tonic-gate { 9810Sstevel@tonic-gate ASSERT(MUTEX_HELD(&rndpool_lock)); 9820Sstevel@tonic-gate ASSERT(len <= rnbyte_cnt && rnbyte_cnt <= RNDPOOLSIZE); 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate BUMP_RND_STATS(rs_rndcOut, len); 9850Sstevel@tonic-gate 9860Sstevel@tonic-gate while (len > 0) { 9870Sstevel@tonic-gate *ptr = rndpool[findex]; 9880Sstevel@tonic-gate ptr++; len--; 9890Sstevel@tonic-gate findex = (findex + 1) & (RNDPOOLSIZE - 1); 9900Sstevel@tonic-gate rnbyte_cnt--; 9910Sstevel@tonic-gate } 9920Sstevel@tonic-gate } 9930Sstevel@tonic-gate 9940Sstevel@tonic-gate /* Random number exported entry points */ 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate /* 9970Sstevel@tonic-gate * Mix the supplied bytes into the entropy pool of a kCF 9980Sstevel@tonic-gate * RNG provider. 9990Sstevel@tonic-gate */ 10000Sstevel@tonic-gate int 10011920Smcpowers random_add_pseudo_entropy(uint8_t *ptr, size_t len, uint_t entropy_est) 10020Sstevel@tonic-gate { 10030Sstevel@tonic-gate if (len < 1) 10040Sstevel@tonic-gate return (-1); 10050Sstevel@tonic-gate 10061920Smcpowers rngprov_seed(ptr, len, entropy_est, 0); 10071920Smcpowers 10081920Smcpowers return (0); 10091920Smcpowers } 10101920Smcpowers 10111920Smcpowers /* 10121920Smcpowers * Mix the supplied bytes into the entropy pool of a kCF 10131920Smcpowers * RNG provider. Mix immediately. 10141920Smcpowers */ 10151920Smcpowers int 10161920Smcpowers random_add_entropy(uint8_t *ptr, size_t len, uint_t entropy_est) 10171920Smcpowers { 10181920Smcpowers if (len < 1) 10191920Smcpowers return (-1); 10201920Smcpowers 10211920Smcpowers rngprov_seed(ptr, len, entropy_est, CRYPTO_SEED_NOW); 10220Sstevel@tonic-gate 10230Sstevel@tonic-gate return (0); 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate /* 10270Sstevel@tonic-gate * Get bytes from the /dev/urandom generator. This function 10280Sstevel@tonic-gate * always succeeds. Returns 0. 10290Sstevel@tonic-gate */ 10300Sstevel@tonic-gate int 10310Sstevel@tonic-gate random_get_pseudo_bytes(uint8_t *ptr, size_t len) 10320Sstevel@tonic-gate { 10330Sstevel@tonic-gate ASSERT(!mutex_owned(&rndpool_lock)); 10340Sstevel@tonic-gate 10350Sstevel@tonic-gate if (len < 1) 10360Sstevel@tonic-gate return (0); 10370Sstevel@tonic-gate return (kcf_rnd_get_pseudo_bytes(ptr, len)); 10380Sstevel@tonic-gate } 10390Sstevel@tonic-gate 10400Sstevel@tonic-gate /* 10410Sstevel@tonic-gate * Get bytes from the /dev/random generator. Returns 0 10420Sstevel@tonic-gate * on success. Returns EAGAIN if there is insufficient entropy. 10430Sstevel@tonic-gate */ 10440Sstevel@tonic-gate int 10450Sstevel@tonic-gate random_get_bytes(uint8_t *ptr, size_t len) 10460Sstevel@tonic-gate { 10470Sstevel@tonic-gate ASSERT(!mutex_owned(&rndpool_lock)); 10480Sstevel@tonic-gate 10490Sstevel@tonic-gate if (len < 1) 10500Sstevel@tonic-gate return (0); 10519619SBhargava.Yenduri@Sun.COM return (kcf_rnd_get_bytes(ptr, len, B_TRUE)); 10520Sstevel@tonic-gate } 1053*10732SAnthony.Scarpino@Sun.COM 1054*10732SAnthony.Scarpino@Sun.COM /* 1055*10732SAnthony.Scarpino@Sun.COM * The two functions below are identical to random_get_pseudo_bytes() and 1056*10732SAnthony.Scarpino@Sun.COM * random_get_bytes_fips, this function is called for consumers that want 1057*10732SAnthony.Scarpino@Sun.COM * FIPS 140-2. This function waits until the FIPS boundary can be verified. 1058*10732SAnthony.Scarpino@Sun.COM */ 1059*10732SAnthony.Scarpino@Sun.COM 1060*10732SAnthony.Scarpino@Sun.COM /* 1061*10732SAnthony.Scarpino@Sun.COM * Get bytes from the /dev/urandom generator. This function 1062*10732SAnthony.Scarpino@Sun.COM * always succeeds. Returns 0. 1063*10732SAnthony.Scarpino@Sun.COM */ 1064*10732SAnthony.Scarpino@Sun.COM int 1065*10732SAnthony.Scarpino@Sun.COM random_get_pseudo_bytes_fips140(uint8_t *ptr, size_t len) 1066*10732SAnthony.Scarpino@Sun.COM { 1067*10732SAnthony.Scarpino@Sun.COM ASSERT(!mutex_owned(&rndpool_lock)); 1068*10732SAnthony.Scarpino@Sun.COM 1069*10732SAnthony.Scarpino@Sun.COM mutex_enter(&fips140_mode_lock); 1070*10732SAnthony.Scarpino@Sun.COM while (global_fips140_mode < FIPS140_MODE_ENABLED) { 1071*10732SAnthony.Scarpino@Sun.COM cv_wait(&cv_fips140, &fips140_mode_lock); 1072*10732SAnthony.Scarpino@Sun.COM } 1073*10732SAnthony.Scarpino@Sun.COM mutex_exit(&fips140_mode_lock); 1074*10732SAnthony.Scarpino@Sun.COM 1075*10732SAnthony.Scarpino@Sun.COM if (len < 1) 1076*10732SAnthony.Scarpino@Sun.COM return (0); 1077*10732SAnthony.Scarpino@Sun.COM return (kcf_rnd_get_pseudo_bytes(ptr, len)); 1078*10732SAnthony.Scarpino@Sun.COM } 1079*10732SAnthony.Scarpino@Sun.COM 1080*10732SAnthony.Scarpino@Sun.COM /* 1081*10732SAnthony.Scarpino@Sun.COM * Get bytes from the /dev/random generator. Returns 0 1082*10732SAnthony.Scarpino@Sun.COM * on success. Returns EAGAIN if there is insufficient entropy. 1083*10732SAnthony.Scarpino@Sun.COM */ 1084*10732SAnthony.Scarpino@Sun.COM int 1085*10732SAnthony.Scarpino@Sun.COM random_get_bytes_fips140(uint8_t *ptr, size_t len) 1086*10732SAnthony.Scarpino@Sun.COM { 1087*10732SAnthony.Scarpino@Sun.COM ASSERT(!mutex_owned(&rndpool_lock)); 1088*10732SAnthony.Scarpino@Sun.COM 1089*10732SAnthony.Scarpino@Sun.COM mutex_enter(&fips140_mode_lock); 1090*10732SAnthony.Scarpino@Sun.COM while (global_fips140_mode < FIPS140_MODE_ENABLED) { 1091*10732SAnthony.Scarpino@Sun.COM cv_wait(&cv_fips140, &fips140_mode_lock); 1092*10732SAnthony.Scarpino@Sun.COM } 1093*10732SAnthony.Scarpino@Sun.COM mutex_exit(&fips140_mode_lock); 1094*10732SAnthony.Scarpino@Sun.COM 1095*10732SAnthony.Scarpino@Sun.COM if (len < 1) 1096*10732SAnthony.Scarpino@Sun.COM return (0); 1097*10732SAnthony.Scarpino@Sun.COM return (kcf_rnd_get_bytes(ptr, len, B_TRUE)); 1098*10732SAnthony.Scarpino@Sun.COM } 1099