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 /* 23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * This file contains DH helper routines common to 28 * the PKCS11 soft token code and the kernel DH code. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/sysmacros.h> 33 #include <bignum.h> 34 35 #ifdef _KERNEL 36 #include <sys/param.h> 37 #else 38 #include <strings.h> 39 #include <cryptoutil.h> 40 #endif 41 42 #include <sys/crypto/common.h> 43 #include <des/des_impl.h> 44 #include "dh_impl.h" 45 46 47 static CK_RV 48 convert_rv(BIG_ERR_CODE err) 49 { 50 switch (err) { 51 52 case BIG_OK: 53 return (CKR_OK); 54 55 case BIG_NO_MEM: 56 return (CKR_HOST_MEMORY); 57 58 case BIG_NO_RANDOM: 59 return (CKR_DEVICE_ERROR); 60 61 case BIG_INVALID_ARGS: 62 return (CKR_ARGUMENTS_BAD); 63 64 case BIG_DIV_BY_0: 65 default: 66 return (CKR_GENERAL_ERROR); 67 } 68 } 69 70 /* size is in bits */ 71 static BIG_ERR_CODE 72 DH_key_init(DHkey *key, int size) 73 { 74 BIG_ERR_CODE err = BIG_OK; 75 int len; 76 77 len = BITLEN2BIGNUMLEN(size); 78 key->size = size; 79 80 if ((err = big_init(&(key->p), len)) != BIG_OK) 81 return (err); 82 if ((err = big_init(&(key->g), len)) != BIG_OK) 83 goto ret1; 84 if ((err = big_init(&(key->x), len)) != BIG_OK) 85 goto ret2; 86 if ((err = big_init(&(key->y), len)) != BIG_OK) 87 goto ret3; 88 89 return (BIG_OK); 90 91 ret3: 92 big_finish(&(key->x)); 93 ret2: 94 big_finish(&(key->g)); 95 ret1: 96 big_finish(&(key->p)); 97 return (err); 98 } 99 100 static void 101 DH_key_finish(DHkey *key) 102 { 103 104 big_finish(&(key->y)); 105 big_finish(&(key->x)); 106 big_finish(&(key->g)); 107 big_finish(&(key->p)); 108 109 } 110 111 /* 112 * Generate DH key pair x and y, given prime p and base g. 113 * Can optionally provided bit length of x, not to exceed bit length of p. 114 */ 115 CK_RV 116 dh_genkey_pair(DHbytekey *bkey) 117 { 118 CK_RV rv = CKR_OK; 119 BIG_ERR_CODE brv; 120 uint32_t primebit_len; 121 DHkey dhkey; 122 int (*rf)(void *, size_t); 123 uint32_t prime_bytes; 124 125 if (bkey == NULL) 126 return (CKR_ARGUMENTS_BAD); 127 128 /* Must have prime and base set, value bits can be 0 or non-0 */ 129 if (bkey->prime_bits == 0 || bkey->prime == NULL || 130 bkey->base_bytes == 0 || bkey->base == NULL) 131 return (CKR_ARGUMENTS_BAD); 132 133 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits); 134 135 if ((prime_bytes < MIN_DH_KEYLENGTH_IN_BYTES) || 136 (prime_bytes > MAX_DH_KEYLENGTH_IN_BYTES)) { 137 return (CKR_KEY_SIZE_RANGE); 138 } 139 140 /* 141 * Initialize the DH key. 142 * Note: big_extend takes length in words. 143 */ 144 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) { 145 rv = convert_rv(brv); 146 goto ret; 147 } 148 149 /* Convert prime p to bignum. */ 150 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) != 151 BIG_OK) { 152 rv = convert_rv(brv); 153 goto ret; 154 } 155 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes); 156 157 /* Convert base g to bignum. */ 158 if ((brv = big_extend(&(dhkey.g), 159 CHARLEN2BIGNUMLEN(bkey->base_bytes))) != BIG_OK) { 160 rv = convert_rv(brv); 161 goto ret; 162 } 163 bytestring2bignum(&(dhkey.g), bkey->base, bkey->base_bytes); 164 165 /* Base g cannot be greater than prime p. */ 166 if (big_cmp_abs(&(dhkey.g), &(dhkey.p)) >= 0) { 167 rv = CKR_ATTRIBUTE_VALUE_INVALID; 168 goto ret; 169 } 170 171 /* 172 * The intention of selecting a private-value length is to reduce 173 * the computation time for key agreement, while maintaining a 174 * given level of security. 175 */ 176 177 /* Maximum bit length for private-value x is bit length of prime p */ 178 primebit_len = big_bitlength(&(dhkey.p)); 179 180 if (bkey->value_bits == 0) 181 bkey->value_bits = primebit_len; 182 183 if (bkey->value_bits > primebit_len) { 184 rv = CKR_ATTRIBUTE_VALUE_INVALID; 185 goto ret; 186 } 187 188 /* Generate DH key pair private and public values. */ 189 if ((brv = big_extend(&(dhkey.x), CHARLEN2BIGNUMLEN(prime_bytes))) 190 != BIG_OK) { 191 rv = convert_rv(brv); 192 goto ret; 193 } 194 195 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes))) 196 != BIG_OK) { 197 rv = convert_rv(brv); 198 goto ret; 199 } 200 201 /* 202 * The big integer of the private value shall be generated privately 203 * and randomly. 204 */ 205 rf = bkey->rfunc; 206 if (rf == NULL) { 207 #ifdef _KERNEL 208 rf = random_get_pseudo_bytes; 209 #else 210 rf = pkcs11_get_urandom; 211 #endif 212 } 213 214 if ((brv = big_random(&(dhkey.x), bkey->value_bits, rf)) != BIG_OK) { 215 rv = convert_rv(brv); 216 goto ret; 217 } 218 219 /* 220 * The base g shall be raised to the private value x modulo p to 221 * give an integer y, the integer public value, i.e. y = (g^x) mod p. 222 */ 223 if ((brv = big_modexp(&(dhkey.y), &(dhkey.g), &(dhkey.x), 224 &(dhkey.p), NULL)) != BIG_OK) { 225 rv = convert_rv(brv); 226 goto ret; 227 } 228 229 bignum2bytestring(bkey->private_x, &(dhkey.x), prime_bytes); 230 bignum2bytestring(bkey->public_y, &(dhkey.y), prime_bytes); 231 232 ret: 233 DH_key_finish(&dhkey); 234 235 return (rv); 236 } 237 238 /* 239 * DH key derive operation 240 */ 241 CK_RV 242 dh_key_derive(DHbytekey *bkey, uint32_t key_type, /* = CKK_KEY_TYPE */ 243 uchar_t *secretkey, uint32_t *secretkey_len) /* derived secret */ 244 { 245 CK_RV rv = CKR_OK; 246 BIG_ERR_CODE brv; 247 DHkey dhkey; 248 uchar_t *s = NULL; 249 uint32_t s_bytes = 0; 250 uint32_t prime_bytes; 251 uint32_t value_bytes; 252 253 if (bkey == NULL) 254 return (CKR_ARGUMENTS_BAD); 255 256 /* Must have prime, private value and public value */ 257 if (bkey->prime_bits == 0 || bkey->prime == NULL || 258 bkey->value_bits == 0 || bkey->private_x == NULL || 259 bkey->public_y == NULL) 260 return (CKR_ARGUMENTS_BAD); 261 262 if (secretkey == NULL) { 263 return (CKR_ARGUMENTS_BAD); 264 } 265 266 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits); 267 value_bytes = CRYPTO_BITS2BYTES(bkey->value_bits); 268 269 /* 270 * Initialize the DH key. 271 * Note: big_extend takes length in words. 272 */ 273 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) { 274 rv = convert_rv(brv); 275 goto ret; 276 } 277 278 /* Convert prime p to bignum. */ 279 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) != 280 BIG_OK) { 281 rv = convert_rv(brv); 282 goto ret; 283 } 284 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes); 285 286 /* Convert private-value x to bignum. */ 287 if ((brv = big_extend(&(dhkey.x), CHARLEN2BIGNUMLEN(value_bytes))) != 288 BIG_OK) { 289 rv = convert_rv(brv); 290 goto ret; 291 } 292 bytestring2bignum(&(dhkey.x), bkey->private_x, value_bytes); 293 294 /* Convert public-value y to bignum. */ 295 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(value_bytes))) != 296 BIG_OK) { 297 rv = convert_rv(brv); 298 goto ret; 299 } 300 bytestring2bignum(&(dhkey.y), bkey->public_y, value_bytes); 301 302 /* 303 * Recycle base g as a temporary variable to compute the derived 304 * secret value which is "g" = (y^x) mod p. (Not recomputing g.) 305 */ 306 if ((brv = big_extend(&(dhkey.g), CHARLEN2BIGNUMLEN(prime_bytes))) != 307 BIG_OK) { 308 rv = convert_rv(brv); 309 goto ret; 310 } 311 312 if ((brv = big_modexp(&(dhkey.g), &(dhkey.y), &(dhkey.x), 313 &(dhkey.p), NULL)) != BIG_OK) { 314 rv = convert_rv(brv); 315 goto ret; 316 } 317 318 #ifdef _KERNEL 319 if ((s = kmem_alloc(P2ROUNDUP_TYPED(prime_bytes, 320 sizeof (BIG_CHUNK_SIZE), size_t))) == NULL) { 321 #else 322 if ((s = malloc(P2ROUNDUP_TYPED(prime_bytes, 323 sizeof (BIG_CHUNK_SIZE), size_t))) == NULL) { 324 #endif 325 rv = CKR_HOST_MEMORY; 326 goto ret; 327 } 328 s_bytes = dhkey.g.len * (int)sizeof (BIG_CHUNK_TYPE); 329 bignum2bytestring(s, &(dhkey.g), s_bytes); 330 331 switch (key_type) { 332 333 case CKK_DES: 334 *secretkey_len = DES_KEYSIZE; 335 break; 336 case CKK_DES2: 337 *secretkey_len = DES2_KEYSIZE; 338 break; 339 case CKK_DES3: 340 *secretkey_len = DES3_KEYSIZE; 341 break; 342 case CKK_RC4: 343 case CKK_AES: 344 case CKK_GENERIC_SECRET: 345 /* use provided secret key length, if any */ 346 break; 347 default: 348 /* invalid key type */ 349 rv = CKR_ATTRIBUTE_TYPE_INVALID; 350 goto ret; 351 } 352 353 if (*secretkey_len == 0) { 354 *secretkey_len = s_bytes; 355 } 356 357 if (*secretkey_len > s_bytes) { 358 rv = CKR_ATTRIBUTE_VALUE_INVALID; 359 goto ret; 360 } 361 362 /* 363 * The truncation removes bytes from the leading end of the 364 * secret value. 365 */ 366 (void) memcpy(secretkey, (s + s_bytes - *secretkey_len), 367 *secretkey_len); 368 369 ret: 370 if (s != NULL) 371 #ifdef _KERNEL 372 kmem_free(s, sizeof (BIG_CHUNK_SIZE)); 373 #else 374 free(s); 375 #endif 376 377 DH_key_finish(&dhkey); 378 379 return (rv); 380 } 381