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
strncpy_spacepad(uchar_t * s1,char * s2,int n)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
ext_info(crypto_provider_handle_t prov,crypto_provider_ext_info_t * ext_info,crypto_req_handle_t cfreq)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
unregister_task(void * targ)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
n2rng_register_provider(n2rng_t * n2rng)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
n2rng_unregister_provider(n2rng_t * n2rng)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
n2rng_failure(n2rng_t * n2rng)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
n2rng_unconfigured(n2rng_t * n2rng)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
n2rng_init(n2rng_t * n2rng)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
n2rng_uninit(n2rng_t * n2rng)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
n2rng_provider_status(crypto_provider_handle_t provider,uint_t * status)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
n2rng_random_number(crypto_provider_handle_t provider,crypto_session_id_t sess,unsigned char * buf,size_t buflen,crypto_req_handle_t cfreq)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
fips_init(n2rng_t * n2rng)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
fips_fini(n2rng_t * n2rng)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