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