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