xref: /illumos-gate/usr/src/uts/sun4v/io/n2rng/n2rng_kcf.c (revision d362b749)
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
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
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 
181 /*
182  * Setup and also register to kCF
183  */
184 int
185 n2rng_init(n2rng_t *n2rng)
186 {
187 	int		ret;
188 	char		ID[64];
189 	dev_info_t	*dip;
190 
191 	dip = n2rng->n_dip;
192 
193 	/* initialize kstats */
194 	n2rng_ksinit(n2rng);
195 
196 	/* initialize the FIPS data and mutexes */
197 	ret = fips_init(n2rng);
198 	if (ret) {
199 		n2rng_ksdeinit(n2rng);
200 		return (DDI_FAILURE);
201 	}
202 
203 	/* register with the crypto framework */
204 	/* Be careful not to exceed 32 chars */
205 	(void) sprintf(ID, "%s/%d %s",
206 	    ddi_driver_name(dip), ddi_get_instance(dip),
207 	    IDENT_N2RNG);
208 	n2rng_prov_info.pi_provider_description = ID;
209 	n2rng_prov_info.pi_provider_dev.pd_hw = dip;
210 	n2rng_prov_info.pi_provider_handle = n2rng;
211 	ret = crypto_register_provider(&n2rng_prov_info, &n2rng->n_prov);
212 	if (ret != CRYPTO_SUCCESS) {
213 		cmn_err(CE_WARN,
214 		    "crypto_register_provider() failed (%d)", ret);
215 		fips_fini(n2rng);
216 		n2rng_ksdeinit(n2rng);
217 		return (DDI_FAILURE);
218 	}
219 
220 	crypto_provider_notification(n2rng->n_prov, CRYPTO_PROVIDER_READY);
221 
222 	return (DDI_SUCCESS);
223 }
224 
225 
226 /*
227  * Unregister from kCF and cleanup
228  */
229 int
230 n2rng_uninit(n2rng_t *n2rng)
231 {
232 	/*
233 	 * Unregister from kCF.
234 	 * This needs to be done at the beginning of detach.
235 	 */
236 	if (n2rng->n_prov != NULL) {
237 		if (crypto_unregister_provider(n2rng->n_prov) !=
238 		    CRYPTO_SUCCESS) {
239 			n2rng_error(n2rng, "unable to unregister from kcf");
240 			return (DDI_FAILURE);
241 		}
242 		n2rng->n_prov = NULL;
243 	}
244 
245 	fips_fini(n2rng);
246 
247 
248 	/* deinitialize kstats */
249 	n2rng_ksdeinit(n2rng);
250 
251 	return (DDI_SUCCESS);
252 }
253 
254 /*
255  * At this time there are no periodic health checks.  If the health
256  * check done at attrach time fails, the driver does not even attach.
257  * So there are no failure conditions to report, and this provider is
258  * never busy.
259  */
260 /* ARGSUSED */
261 static void
262 n2rng_provider_status(crypto_provider_handle_t provider, uint_t *status)
263 {
264 	*status = CRYPTO_PROVIDER_READY;
265 }
266 
267 /*ARGSUSED*/
268 static int
269 n2rng_random_number(crypto_provider_handle_t provider,
270 	crypto_session_id_t sess, unsigned char *buf, size_t buflen,
271 	crypto_req_handle_t cfreq)
272 {
273 	n2rng_t		*n2rng = (n2rng_t *)provider;
274 	int		rv;
275 
276 	rv = fips_random(n2rng, buf, buflen);
277 
278 	atomic_add_64(&n2rng->n_stats[DS_RNGBYTES], buflen);
279 	atomic_inc_64(&n2rng->n_stats[DS_RNGJOBS]);
280 
281 	return (rv);
282 }
283 
284 static int
285 fips_init(n2rng_t *n2rng)
286 {
287 	int		i;
288 	int		rv;
289 
290 	n2rng->n_frs.fips_round_robin_j = 0;
291 	for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) {
292 		rv = n2rng_fips_random_init(n2rng, &n2rng->n_frs.fipsarray[i]);
293 		if (rv) {
294 			/* finalize all the FIPS structures allocated so far */
295 			for (--i; i >= 0; --i) {
296 				n2rng_fips_random_fini(
297 				    &n2rng->n_frs.fipsarray[i]);
298 			}
299 			return (rv);
300 		}
301 	}
302 	return (0);
303 }
304 
305 
306 static void
307 fips_fini(n2rng_t *n2rng)
308 {
309 	int		i;
310 
311 	for (i = 0; i < N2RNG_FIPS_INSTANCES; i++) {
312 		n2rng_fips_random_fini(&n2rng->n_frs.fipsarray[i]);
313 	}
314 }
315