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 static void 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 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 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 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 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 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 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 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 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 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 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