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