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