1fec509a0Sgm89044 /* 2fec509a0Sgm89044 * CDDL HEADER START 3fec509a0Sgm89044 * 4fec509a0Sgm89044 * The contents of this file are subject to the terms of the 5fec509a0Sgm89044 * Common Development and Distribution License (the "License"). 6fec509a0Sgm89044 * You may not use this file except in compliance with the License. 7fec509a0Sgm89044 * 8fec509a0Sgm89044 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fec509a0Sgm89044 * or http://www.opensolaris.org/os/licensing. 10fec509a0Sgm89044 * See the License for the specific language governing permissions 11fec509a0Sgm89044 * and limitations under the License. 12fec509a0Sgm89044 * 13fec509a0Sgm89044 * When distributing Covered Code, include this CDDL HEADER in each 14fec509a0Sgm89044 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fec509a0Sgm89044 * If applicable, add the following below this CDDL HEADER, with the 16fec509a0Sgm89044 * fields enclosed by brackets "[]" replaced with your own identifying 17fec509a0Sgm89044 * information: Portions Copyright [yyyy] [name of copyright owner] 18fec509a0Sgm89044 * 19fec509a0Sgm89044 * CDDL HEADER END 20fec509a0Sgm89044 */ 21fec509a0Sgm89044 /* 22fec509a0Sgm89044 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23fec509a0Sgm89044 * Use is subject to license terms. 24fec509a0Sgm89044 */ 25fec509a0Sgm89044 26fec509a0Sgm89044 #pragma ident "%Z%%M% %I% %E% SMI" 27fec509a0Sgm89044 28fec509a0Sgm89044 #include <sys/types.h> 29fec509a0Sgm89044 #include <sys/uio.h> 30fec509a0Sgm89044 #include <sys/stream.h> 31fec509a0Sgm89044 #include <sys/ddi.h> 32fec509a0Sgm89044 #include <sys/sunddi.h> 33fec509a0Sgm89044 #include <sys/strsun.h> 34fec509a0Sgm89044 #include <sys/kmem.h> 35fec509a0Sgm89044 #include <sys/atomic.h> 36fec509a0Sgm89044 #include <sys/random.h> 37fec509a0Sgm89044 #include <sys/crypto/common.h> 38fec509a0Sgm89044 #include <sys/crypto/spi.h> 39fec509a0Sgm89044 #include <sys/n2rng.h> 40fec509a0Sgm89044 41fec509a0Sgm89044 #define IDENT_N2RNG "SUNW_N2_Random_Number_Generator" 42fec509a0Sgm89044 43fec509a0Sgm89044 #define N2RNG_PROVIDER2N2RNG(x) (((n2rng_provider_private_t *)x)->mp_n2rng) 44fec509a0Sgm89044 45fec509a0Sgm89044 46fec509a0Sgm89044 static void n2rng_provider_status(crypto_provider_handle_t, uint_t *); 47fec509a0Sgm89044 48fec509a0Sgm89044 static int n2rng_random_number(crypto_provider_handle_t, crypto_session_id_t, 49fec509a0Sgm89044 uchar_t *, size_t, crypto_req_handle_t); 50fec509a0Sgm89044 51fec509a0Sgm89044 static int ext_info(crypto_provider_handle_t, crypto_provider_ext_info_t *, 52fec509a0Sgm89044 crypto_req_handle_t); 53fec509a0Sgm89044 54fec509a0Sgm89044 void n2rng_ksinit(n2rng_t *n2rng); 55fec509a0Sgm89044 void n2rng_ksdeinit(n2rng_t *n2rng); 56fec509a0Sgm89044 57fec509a0Sgm89044 static int fips_init(n2rng_t *n2rng); 58fec509a0Sgm89044 static void fips_fini(n2rng_t *n2rng); 59fec509a0Sgm89044 int fips_random(n2rng_t *n2rng, uint8_t *out, size_t nbytes); 60fec509a0Sgm89044 61fec509a0Sgm89044 62fec509a0Sgm89044 static crypto_control_ops_t n2rng_control_ops = { 63fec509a0Sgm89044 n2rng_provider_status 64fec509a0Sgm89044 }; 65fec509a0Sgm89044 66fec509a0Sgm89044 67fec509a0Sgm89044 static crypto_random_number_ops_t n2rng_rng_ops = { 68fec509a0Sgm89044 NULL, /* seed_random */ 69fec509a0Sgm89044 n2rng_random_number 70fec509a0Sgm89044 }; 71fec509a0Sgm89044 72fec509a0Sgm89044 static crypto_provider_management_ops_t n2rng_extinfo_op = { 73fec509a0Sgm89044 ext_info, /* ext_info */ 74fec509a0Sgm89044 NULL, /* init_token */ 75fec509a0Sgm89044 NULL, /* init_pin */ 76fec509a0Sgm89044 NULL, /* set_pin */ 77fec509a0Sgm89044 }; 78fec509a0Sgm89044 79fec509a0Sgm89044 static crypto_ops_t n2rng_ops = { 80fec509a0Sgm89044 &n2rng_control_ops, 81fec509a0Sgm89044 NULL, /* digest_ops */ 82fec509a0Sgm89044 NULL, /* cipher_ops */ 83fec509a0Sgm89044 NULL, /* mac_ops */ 84fec509a0Sgm89044 NULL, /* sign_ops */ 85fec509a0Sgm89044 NULL, /* verify_ops */ 86fec509a0Sgm89044 NULL, /* dual_ops */ 87fec509a0Sgm89044 NULL, /* cipher_mac_ops */ 88fec509a0Sgm89044 &n2rng_rng_ops, /* rng_ops */ 89fec509a0Sgm89044 NULL, /* session_ops */ 90fec509a0Sgm89044 NULL, /* object_ops */ 91fec509a0Sgm89044 NULL, /* key_ops */ 92fec509a0Sgm89044 &n2rng_extinfo_op, /* management_ops */ 93fec509a0Sgm89044 NULL, /* ctx_ops */ 94fec509a0Sgm89044 NULL /* mech_ops */ 95fec509a0Sgm89044 }; 96fec509a0Sgm89044 97fec509a0Sgm89044 static crypto_provider_info_t n2rng_prov_info = { 98fec509a0Sgm89044 CRYPTO_SPI_VERSION_2, 99fec509a0Sgm89044 NULL, /* pi_provider_description */ 100fec509a0Sgm89044 CRYPTO_HW_PROVIDER, 101fec509a0Sgm89044 NULL, /* pi_provider_dev */ 102fec509a0Sgm89044 NULL, /* pi_provider_handle */ 103fec509a0Sgm89044 &n2rng_ops, 104fec509a0Sgm89044 0, /* number of mechanisms */ 105fec509a0Sgm89044 NULL, /* mechanism table */ 106fec509a0Sgm89044 0, /* pi_logical_provider_count */ 107fec509a0Sgm89044 NULL /* pi_logical_providers */ 108fec509a0Sgm89044 }; 109fec509a0Sgm89044 110fec509a0Sgm89044 static void 111fec509a0Sgm89044 strncpy_spacepad(uchar_t *s1, char *s2, int n) 112fec509a0Sgm89044 { 113fec509a0Sgm89044 int s2len = strlen(s2); 114fec509a0Sgm89044 115fec509a0Sgm89044 (void) strncpy((char *)s1, s2, n); 116fec509a0Sgm89044 if (s2len < n) 117fec509a0Sgm89044 (void) memset(s1 + s2len, ' ', n - s2len); 118fec509a0Sgm89044 } 119fec509a0Sgm89044 120fec509a0Sgm89044 /*ARGSUSED*/ 121fec509a0Sgm89044 static int 122fec509a0Sgm89044 ext_info(crypto_provider_handle_t prov, crypto_provider_ext_info_t *ext_info, 123fec509a0Sgm89044 crypto_req_handle_t cfreq) 124fec509a0Sgm89044 { 125fec509a0Sgm89044 #define BUFSZ 64 126fec509a0Sgm89044 n2rng_t *n2rng = (n2rng_t *)prov; 127fec509a0Sgm89044 char buf[BUFSZ]; 128fec509a0Sgm89044 129fec509a0Sgm89044 /* handle info common to logical and hardware provider */ 130fec509a0Sgm89044 131fec509a0Sgm89044 /* Manufacturer ID */ 132fec509a0Sgm89044 strncpy_spacepad(ext_info->ei_manufacturerID, N2RNG_MANUFACTURER_ID, 133fec509a0Sgm89044 CRYPTO_EXT_SIZE_MANUF); 134fec509a0Sgm89044 135fec509a0Sgm89044 /* Model */ 136fec509a0Sgm89044 strncpy_spacepad(ext_info->ei_model, "0", CRYPTO_EXT_SIZE_MODEL); 137fec509a0Sgm89044 138fec509a0Sgm89044 /* Token flags */ 139fec509a0Sgm89044 ext_info->ei_flags = CRYPTO_EXTF_RNG | CRYPTO_EXTF_SO_PIN_LOCKED | 140fec509a0Sgm89044 CRYPTO_EXTF_WRITE_PROTECTED; 141fec509a0Sgm89044 142fec509a0Sgm89044 ext_info->ei_max_session_count = CRYPTO_EFFECTIVELY_INFINITE; 143fec509a0Sgm89044 ext_info->ei_max_pin_len = 0; 144fec509a0Sgm89044 ext_info->ei_min_pin_len = 0; 145fec509a0Sgm89044 ext_info->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO; 146fec509a0Sgm89044 ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO; 147fec509a0Sgm89044 ext_info->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO; 148fec509a0Sgm89044 ext_info->ei_free_private_memory = CRYPTO_UNAVAILABLE_INFO; 149fec509a0Sgm89044 150fec509a0Sgm89044 /* Time. No need to be supplied for token without a clock */ 151fec509a0Sgm89044 ext_info->ei_time[0] = '\000'; 152fec509a0Sgm89044 153fec509a0Sgm89044 /* handle hardware provider specific fields */ 154fec509a0Sgm89044 155fec509a0Sgm89044 /* Token label */ 156fec509a0Sgm89044 (void) snprintf(buf, BUFSZ, "%s/%d SUNW_N2_RNG", 157fec509a0Sgm89044 ddi_driver_name(n2rng->n_dip), 158fec509a0Sgm89044 ddi_get_instance(n2rng->n_dip)); 159fec509a0Sgm89044 160fec509a0Sgm89044 /* Serial number */ 161fec509a0Sgm89044 strncpy_spacepad(ext_info->ei_serial_number, 162fec509a0Sgm89044 "0", 163fec509a0Sgm89044 CRYPTO_EXT_SIZE_SERIAL); 164fec509a0Sgm89044 165fec509a0Sgm89044 /* Version info */ 166fec509a0Sgm89044 ext_info->ei_hardware_version.cv_major = 0; 167fec509a0Sgm89044 ext_info->ei_hardware_version.cv_minor = 0; 168fec509a0Sgm89044 ext_info->ei_firmware_version.cv_major = 0; 169fec509a0Sgm89044 ext_info->ei_firmware_version.cv_minor = 0; 170fec509a0Sgm89044 171fec509a0Sgm89044 buf[BUFSZ - 1] = '\000'; 172fec509a0Sgm89044 /* set the token label */ 173fec509a0Sgm89044 strncpy_spacepad(ext_info->ei_label, buf, CRYPTO_EXT_SIZE_LABEL); 174fec509a0Sgm89044 175fec509a0Sgm89044 #undef BUFSZ 176fec509a0Sgm89044 177fec509a0Sgm89044 return (CRYPTO_SUCCESS); 178fec509a0Sgm89044 } 179fec509a0Sgm89044 180*741c280dStwelke static void 181*741c280dStwelke unregister_task(void *targ) 182*741c280dStwelke { 183*741c280dStwelke n2rng_t *n2rng = (n2rng_t *)targ; 184*741c280dStwelke 185*741c280dStwelke /* Unregister provider without checking result */ 186*741c280dStwelke (void) n2rng_unregister_provider(n2rng); 187*741c280dStwelke } 188*741c280dStwelke 189*741c280dStwelke /* 190*741c280dStwelke * Register with KCF if not already registered 191*741c280dStwelke */ 192*741c280dStwelke int 193*741c280dStwelke n2rng_register_provider(n2rng_t *n2rng) 194*741c280dStwelke { 195*741c280dStwelke int ret; 196*741c280dStwelke 197*741c280dStwelke if (n2rng_isregistered(n2rng)) { 198*741c280dStwelke DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider already " 199*741c280dStwelke "registered"); 200*741c280dStwelke return (DDI_SUCCESS); 201*741c280dStwelke } else { 202*741c280dStwelke ret = crypto_register_provider(&n2rng_prov_info, 203*741c280dStwelke &n2rng->n_prov); 204*741c280dStwelke if (ret == CRYPTO_SUCCESS) { 205*741c280dStwelke DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider " 206*741c280dStwelke "registered"); 207*741c280dStwelke } else { 208*741c280dStwelke cmn_err(CE_WARN, 209*741c280dStwelke "crypto_register_provider() failed (%d)", ret); 210*741c280dStwelke n2rng->n_prov = NULL; 211*741c280dStwelke return (DDI_FAILURE); 212*741c280dStwelke } 213*741c280dStwelke } 214*741c280dStwelke n2rng_setregistered(n2rng); 215*741c280dStwelke crypto_provider_notification(n2rng->n_prov, CRYPTO_PROVIDER_READY); 216*741c280dStwelke 217*741c280dStwelke return (DDI_SUCCESS); 218*741c280dStwelke } 219*741c280dStwelke 220*741c280dStwelke /* 221*741c280dStwelke * Unregister with KCF if not already registered 222*741c280dStwelke */ 223*741c280dStwelke int 224*741c280dStwelke n2rng_unregister_provider(n2rng_t *n2rng) 225*741c280dStwelke { 226*741c280dStwelke if (!n2rng_isregistered(n2rng)) { 227*741c280dStwelke DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider already " 228*741c280dStwelke "unregistered"); 229*741c280dStwelke } else { 230*741c280dStwelke if (crypto_unregister_provider(n2rng->n_prov) == 231*741c280dStwelke CRYPTO_SUCCESS) { 232*741c280dStwelke DBG0(n2rng, DKCF, "n2rng_kcf: Crypto provider " 233*741c280dStwelke "unregistered"); 234*741c280dStwelke } else { 235*741c280dStwelke n2rng_error(n2rng, "unable to unregister from kcf"); 236*741c280dStwelke return (DDI_FAILURE); 237*741c280dStwelke } 238*741c280dStwelke } 239*741c280dStwelke n2rng->n_prov = NULL; 240*741c280dStwelke n2rng_clrregistered(n2rng); 241*741c280dStwelke return (DDI_SUCCESS); 242*741c280dStwelke } 243*741c280dStwelke 244*741c280dStwelke 245*741c280dStwelke /* 246*741c280dStwelke * Set state to failed for all rngs if in control domain and dispatch a task 247*741c280dStwelke * to unregister from kcf 248*741c280dStwelke */ 249*741c280dStwelke void 250*741c280dStwelke n2rng_failure(n2rng_t *n2rng) 251*741c280dStwelke { 252*741c280dStwelke int rngid; 253*741c280dStwelke rng_entry_t *rng; 254*741c280dStwelke 255*741c280dStwelke mutex_enter(&n2rng->n_lock); 256*741c280dStwelke /* Check if error has already been detected */ 257*741c280dStwelke if (n2rng_isfailed(n2rng)) { 258*741c280dStwelke mutex_exit(&n2rng->n_lock); 259*741c280dStwelke return; 260*741c280dStwelke } 261*741c280dStwelke 262*741c280dStwelke cmn_err(CE_WARN, "n2rng: hardware failure detected"); 263*741c280dStwelke n2rng_setfailed(n2rng); 264*741c280dStwelke 265*741c280dStwelke /* Set each rng to failed if running in control domain */ 266*741c280dStwelke if (n2rng_iscontrol(n2rng)) { 267*741c280dStwelke for (rngid = 0; rngid < n2rng->n_ctl_data->n_num_rngs; 268*741c280dStwelke rngid++) { 269*741c280dStwelke rng = &n2rng->n_ctl_data->n_rngs[rngid]; 270*741c280dStwelke rng->n_rng_state = CTL_STATE_ERROR; 271*741c280dStwelke } 272*741c280dStwelke } 273*741c280dStwelke mutex_exit(&n2rng->n_lock); 274*741c280dStwelke 275*741c280dStwelke /* Dispatch task to unregister from kcf */ 276*741c280dStwelke if (ddi_taskq_dispatch(n2rng->n_taskq, unregister_task, 277*741c280dStwelke (void *)n2rng, DDI_SLEEP) != DDI_SUCCESS) { 278*741c280dStwelke cmn_err(CE_WARN, "n2rng: ddi_taskq_dispatch() failed"); 279*741c280dStwelke } 280*741c280dStwelke } 281*741c280dStwelke 282*741c280dStwelke /* 283*741c280dStwelke * Set state to unconfigured for all rngs if in control domain and dispatch a 284*741c280dStwelke * task to unregister from kcf. 285*741c280dStwelke */ 286*741c280dStwelke void 287*741c280dStwelke n2rng_unconfigured(n2rng_t *n2rng) 288*741c280dStwelke { 289*741c280dStwelke int rngid; 290*741c280dStwelke rng_entry_t *rng; 291*741c280dStwelke 292*741c280dStwelke mutex_enter(&n2rng->n_lock); 293*741c280dStwelke /* Check if unconfigured state has already been detected */ 294*741c280dStwelke if (!n2rng_isconfigured(n2rng)) { 295*741c280dStwelke mutex_exit(&n2rng->n_lock); 296*741c280dStwelke return; 297*741c280dStwelke } 298*741c280dStwelke 299*741c280dStwelke cmn_err(CE_WARN, "n2rng: no longer generating entropy"); 300*741c280dStwelke n2rng_clrconfigured(n2rng); 301*741c280dStwelke 302*741c280dStwelke /* Set each rng to unconfigured if running in control domain */ 303*741c280dStwelke if (n2rng_iscontrol(n2rng)) { 304*741c280dStwelke for (rngid = 0; rngid < n2rng->n_ctl_data->n_num_rngs; 305*741c280dStwelke rngid++) { 306*741c280dStwelke rng = &n2rng->n_ctl_data->n_rngs[rngid]; 307*741c280dStwelke rng->n_rng_state = CTL_STATE_UNCONFIGURED; 308*741c280dStwelke } 309*741c280dStwelke } 310*741c280dStwelke mutex_exit(&n2rng->n_lock); 311*741c280dStwelke 312*741c280dStwelke /* Dispatch task to unregister from kcf */ 313*741c280dStwelke if (ddi_taskq_dispatch(n2rng->n_taskq, unregister_task, 314*741c280dStwelke (void *)n2rng, DDI_SLEEP) != DDI_SUCCESS) { 315*741c280dStwelke cmn_err(CE_WARN, "n2rng: ddi_taskq_dispatch() failed"); 316*741c280dStwelke } else { 317*741c280dStwelke /* Schedule a configuration retry */ 318*741c280dStwelke n2rng_config_retry(n2rng, RNG_CFG_RETRY_SECS); 319*741c280dStwelke } 320*741c280dStwelke } 321fec509a0Sgm89044 322fec509a0Sgm89044 /* 323fec509a0Sgm89044 * Setup and also register to kCF 324fec509a0Sgm89044 */ 325fec509a0Sgm89044 int 326fec509a0Sgm89044 n2rng_init(n2rng_t *n2rng) 327fec509a0Sgm89044 { 328fec509a0Sgm89044 int ret; 329fec509a0Sgm89044 char ID[64]; 330fec509a0Sgm89044 dev_info_t *dip; 331fec509a0Sgm89044 332fec509a0Sgm89044 dip = n2rng->n_dip; 333fec509a0Sgm89044 334*741c280dStwelke /* Initialize data structures if not already done */ 335*741c280dStwelke if (!n2rng_isinitialized(n2rng)) { 336fec509a0Sgm89044 /* initialize kstats */ 337fec509a0Sgm89044 n2rng_ksinit(n2rng); 338fec509a0Sgm89044 339fec509a0Sgm89044 /* initialize the FIPS data and mutexes */ 340fec509a0Sgm89044 ret = fips_init(n2rng); 341fec509a0Sgm89044 if (ret) { 342fec509a0Sgm89044 n2rng_ksdeinit(n2rng); 343fec509a0Sgm89044 return (DDI_FAILURE); 344fec509a0Sgm89044 } 345*741c280dStwelke } 346fec509a0Sgm89044 347*741c280dStwelke /* 348*741c280dStwelke * Register with crypto framework if not already registered. 349*741c280dStwelke * Be careful not to exceed 32 characters. 350*741c280dStwelke */ 351fec509a0Sgm89044 (void) sprintf(ID, "%s/%d %s", 352fec509a0Sgm89044 ddi_driver_name(dip), ddi_get_instance(dip), 353fec509a0Sgm89044 IDENT_N2RNG); 354fec509a0Sgm89044 n2rng_prov_info.pi_provider_description = ID; 355fec509a0Sgm89044 n2rng_prov_info.pi_provider_dev.pd_hw = dip; 356fec509a0Sgm89044 n2rng_prov_info.pi_provider_handle = n2rng; 357*741c280dStwelke n2rng_setinitialized(n2rng); 358*741c280dStwelke ret = n2rng_register_provider(n2rng); 359*741c280dStwelke if (ret != DDI_SUCCESS) { 360fec509a0Sgm89044 fips_fini(n2rng); 361fec509a0Sgm89044 n2rng_ksdeinit(n2rng); 362*741c280dStwelke n2rng_clrinitialized(n2rng); 363fec509a0Sgm89044 return (DDI_FAILURE); 364fec509a0Sgm89044 } 365fec509a0Sgm89044 366fec509a0Sgm89044 return (DDI_SUCCESS); 367fec509a0Sgm89044 } 368fec509a0Sgm89044 369fec509a0Sgm89044 /* 370fec509a0Sgm89044 * Unregister from kCF and cleanup 371fec509a0Sgm89044 */ 372fec509a0Sgm89044 int 373fec509a0Sgm89044 n2rng_uninit(n2rng_t *n2rng) 374fec509a0Sgm89044 { 375*741c280dStwelke /* Un-initialize data structures if they exist */ 376*741c280dStwelke if (n2rng_isinitialized(n2rng)) { 377fec509a0Sgm89044 /* 378fec509a0Sgm89044 * Unregister from kCF. 379fec509a0Sgm89044 * This needs to be done at the beginning of detach. 380fec509a0Sgm89044 */ 381*741c280dStwelke if (n2rng_unregister_provider(n2rng) != DDI_SUCCESS) { 382fec509a0Sgm89044 return (DDI_FAILURE); 383fec509a0Sgm89044 } 384fec509a0Sgm89044 385fec509a0Sgm89044 fips_fini(n2rng); 386fec509a0Sgm89044 387fec509a0Sgm89044 /* deinitialize kstats */ 388fec509a0Sgm89044 n2rng_ksdeinit(n2rng); 389*741c280dStwelke n2rng_clrinitialized(n2rng); 390*741c280dStwelke } 391fec509a0Sgm89044 392fec509a0Sgm89044 return (DDI_SUCCESS); 393fec509a0Sgm89044 } 394fec509a0Sgm89044 395fec509a0Sgm89044 /* 396fec509a0Sgm89044 * At this time there are no periodic health checks. If the health 397fec509a0Sgm89044 * check done at attrach time fails, the driver does not even attach. 398fec509a0Sgm89044 * So there are no failure conditions to report, and this provider is 399fec509a0Sgm89044 * never busy. 400fec509a0Sgm89044 */ 401fec509a0Sgm89044 /* ARGSUSED */ 402fec509a0Sgm89044 static void 403fec509a0Sgm89044 n2rng_provider_status(crypto_provider_handle_t provider, uint_t *status) 404fec509a0Sgm89044 { 405fec509a0Sgm89044 *status = CRYPTO_PROVIDER_READY; 406fec509a0Sgm89044 } 407fec509a0Sgm89044 408fec509a0Sgm89044 /*ARGSUSED*/ 409fec509a0Sgm89044 static int 410fec509a0Sgm89044 n2rng_random_number(crypto_provider_handle_t provider, 411fec509a0Sgm89044 crypto_session_id_t sess, unsigned char *buf, size_t buflen, 412fec509a0Sgm89044 crypto_req_handle_t cfreq) 413fec509a0Sgm89044 { 414fec509a0Sgm89044 n2rng_t *n2rng = (n2rng_t *)provider; 415fec509a0Sgm89044 int rv; 416fec509a0Sgm89044 417fec509a0Sgm89044 rv = fips_random(n2rng, buf, buflen); 418fec509a0Sgm89044 419fec509a0Sgm89044 atomic_add_64(&n2rng->n_stats[DS_RNGBYTES], buflen); 420fec509a0Sgm89044 atomic_inc_64(&n2rng->n_stats[DS_RNGJOBS]); 421fec509a0Sgm89044 422fec509a0Sgm89044 return (rv); 423fec509a0Sgm89044 } 424fec509a0Sgm89044 425fec509a0Sgm89044 static int 426fec509a0Sgm89044 fips_init(n2rng_t *n2rng) 427fec509a0Sgm89044 { 428fec509a0Sgm89044 int i; 429fec509a0Sgm89044 int rv; 430fec509a0Sgm89044 431fec509a0Sgm89044 n2rng->n_frs.fips_round_robin_j = 0; 432fec509a0Sgm89044 for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) { 433fec509a0Sgm89044 rv = n2rng_fips_random_init(n2rng, &n2rng->n_frs.fipsarray[i]); 434fec509a0Sgm89044 if (rv) { 435fec509a0Sgm89044 /* finalize all the FIPS structures allocated so far */ 436fec509a0Sgm89044 for (--i; i >= 0; --i) { 437fec509a0Sgm89044 n2rng_fips_random_fini( 438fec509a0Sgm89044 &n2rng->n_frs.fipsarray[i]); 439fec509a0Sgm89044 } 440fec509a0Sgm89044 return (rv); 441fec509a0Sgm89044 } 442fec509a0Sgm89044 } 443fec509a0Sgm89044 return (0); 444fec509a0Sgm89044 } 445fec509a0Sgm89044 446fec509a0Sgm89044 static void 447fec509a0Sgm89044 fips_fini(n2rng_t *n2rng) 448fec509a0Sgm89044 { 449fec509a0Sgm89044 int i; 450fec509a0Sgm89044 451fec509a0Sgm89044 for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) { 452fec509a0Sgm89044 n2rng_fips_random_fini(&n2rng->n_frs.fipsarray[i]); 453fec509a0Sgm89044 } 454fec509a0Sgm89044 } 455