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 * For those not familiar with DH keys, there are 4 components: 116 * p - a known prime 117 * g - the base 0 < g < p 118 * x - a random number 0 < x < p-1, or if a smaller value is desired, 119 * 2^(len-1) <= x < 2^(len) 120 * y = g^x mod p, this implies 0 < y < p. That is important! 121 */ 122 CK_RV 123 dh_genkey_pair(DHbytekey *bkey) 124 { 125 CK_RV rv = CKR_OK; 126 BIG_ERR_CODE brv; 127 uint32_t primebit_len; 128 DHkey dhkey; 129 int (*rf)(void *, size_t); 130 uint32_t prime_bytes; 131 132 if (bkey == NULL) 133 return (CKR_ARGUMENTS_BAD); 134 135 /* Must have prime and base set, value bits can be 0 or non-0 */ 136 if (bkey->prime_bits == 0 || bkey->prime == NULL || 137 bkey->base_bytes == 0 || bkey->base == NULL) 138 return (CKR_ARGUMENTS_BAD); 139 140 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits); 141 142 if ((prime_bytes < MIN_DH_KEYLENGTH_IN_BYTES) || 143 (prime_bytes > MAX_DH_KEYLENGTH_IN_BYTES)) { 144 return (CKR_KEY_SIZE_RANGE); 145 } 146 147 /* 148 * Initialize the DH key. 149 * Note: big_extend takes length in words. 150 */ 151 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) { 152 rv = convert_rv(brv); 153 goto ret; 154 } 155 156 /* Convert prime p to bignum. */ 157 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) != 158 BIG_OK) { 159 rv = convert_rv(brv); 160 goto ret; 161 } 162 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes); 163 164 /* Convert base g to bignum. */ 165 if ((brv = big_extend(&(dhkey.g), 166 CHARLEN2BIGNUMLEN(bkey->base_bytes))) != BIG_OK) { 167 rv = convert_rv(brv); 168 goto ret; 169 } 170 bytestring2bignum(&(dhkey.g), bkey->base, bkey->base_bytes); 171 172 /* Base g cannot be greater than prime p. */ 173 if (big_cmp_abs(&(dhkey.g), &(dhkey.p)) >= 0) { 174 rv = CKR_ATTRIBUTE_VALUE_INVALID; 175 goto ret; 176 } 177 178 /* 179 * The intention of selecting a private-value length is to reduce 180 * the computation time for key agreement, while maintaining a 181 * given level of security. 182 */ 183 184 /* Maximum bit length for private-value x is bit length of prime p */ 185 primebit_len = big_bitlength(&(dhkey.p)); 186 187 if (bkey->value_bits == 0) 188 bkey->value_bits = primebit_len; 189 190 if (bkey->value_bits > primebit_len) { 191 rv = CKR_ATTRIBUTE_VALUE_INVALID; 192 goto ret; 193 } 194 195 /* Generate DH key pair private and public values. */ 196 if ((brv = big_extend(&(dhkey.x), BITLEN2BIGNUMLEN(bkey->value_bits))) 197 != BIG_OK) { 198 rv = convert_rv(brv); 199 goto ret; 200 } 201 202 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes))) 203 != BIG_OK) { 204 rv = convert_rv(brv); 205 goto ret; 206 } 207 208 /* 209 * The big integer of the private value shall be generated privately 210 * and randomly. 211 */ 212 rf = bkey->rfunc; 213 if (rf == NULL) { 214 #ifdef _KERNEL 215 rf = random_get_pseudo_bytes; 216 #else 217 rf = pkcs11_get_urandom; 218 #endif 219 } 220 221 if ((brv = big_random(&(dhkey.x), bkey->value_bits, rf)) != BIG_OK) { 222 rv = convert_rv(brv); 223 goto ret; 224 } 225 226 /* 227 * The base g shall be raised to the private value x modulo p to 228 * give an integer y, the integer public value, i.e. y = (g^x) mod p. 229 */ 230 if ((brv = big_modexp(&(dhkey.y), &(dhkey.g), &(dhkey.x), 231 &(dhkey.p), NULL)) != BIG_OK) { 232 rv = convert_rv(brv); 233 goto ret; 234 } 235 236 bignum2bytestring(bkey->private_x, &(dhkey.x), 237 CRYPTO_BITS2BYTES(bkey->value_bits)); 238 bignum2bytestring(bkey->public_y, &(dhkey.y), prime_bytes); 239 240 ret: 241 DH_key_finish(&dhkey); 242 243 return (rv); 244 } 245 246 /* 247 * DH key derive operation, flag is ignored in userland 248 */ 249 CK_RV 250 dh_key_derive(DHbytekey *bkey, uint32_t key_type, /* = CKK_KEY_TYPE */ 251 uchar_t *secretkey, uint32_t *secretkey_len, /* derived secret */ 252 int flag) 253 { 254 CK_RV rv = CKR_OK; 255 BIG_ERR_CODE brv; 256 DHkey dhkey; 257 uchar_t *s = NULL; 258 uint32_t s_bytes = 0; 259 uint32_t prime_bytes; 260 uint32_t value_bytes; 261 size_t s_alloc; 262 263 if (bkey == NULL) 264 return (CKR_ARGUMENTS_BAD); 265 266 /* Must have prime, private value and public value */ 267 if (bkey->prime_bits == 0 || bkey->prime == NULL || 268 bkey->value_bits == 0 || bkey->private_x == NULL || 269 bkey->public_y == NULL) 270 return (CKR_ARGUMENTS_BAD); 271 272 if (secretkey == NULL) { 273 return (CKR_ARGUMENTS_BAD); 274 } 275 276 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits); 277 value_bytes = CRYPTO_BITS2BYTES(bkey->value_bits); 278 279 /* 280 * Initialize the DH key. 281 * Note: big_extend takes length in words. 282 */ 283 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) { 284 rv = convert_rv(brv); 285 goto ret; 286 } 287 288 /* Convert prime p to bignum. */ 289 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) != 290 BIG_OK) { 291 rv = convert_rv(brv); 292 goto ret; 293 } 294 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes); 295 296 /* Convert private-value x to bignum. */ 297 if ((brv = big_extend(&(dhkey.x), CHARLEN2BIGNUMLEN(value_bytes))) != 298 BIG_OK) { 299 rv = convert_rv(brv); 300 goto ret; 301 } 302 bytestring2bignum(&(dhkey.x), bkey->private_x, value_bytes); 303 304 /* Convert public-value y to bignum. */ 305 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes))) != 306 BIG_OK) { 307 rv = convert_rv(brv); 308 goto ret; 309 } 310 bytestring2bignum(&(dhkey.y), bkey->public_y, prime_bytes); 311 312 /* 313 * Recycle base g as a temporary variable to compute the derived 314 * secret value which is "g" = (y^x) mod p. (Not recomputing g.) 315 */ 316 if ((brv = big_extend(&(dhkey.g), CHARLEN2BIGNUMLEN(prime_bytes))) != 317 BIG_OK) { 318 rv = convert_rv(brv); 319 goto ret; 320 } 321 322 if ((brv = big_modexp(&(dhkey.g), &(dhkey.y), &(dhkey.x), 323 &(dhkey.p), NULL)) != BIG_OK) { 324 rv = convert_rv(brv); 325 goto ret; 326 } 327 328 s_alloc = P2ROUNDUP_TYPED(prime_bytes, sizeof (BIG_CHUNK_TYPE), size_t); 329 330 #ifdef _KERNEL 331 if ((s = kmem_alloc(s_alloc, flag)) == NULL) { 332 rv = CKR_HOST_MEMORY; 333 goto ret; 334 } 335 #else 336 if ((s = malloc(s_alloc)) == NULL) { 337 rv = CKR_HOST_MEMORY; 338 goto ret; 339 } 340 #endif 341 s_bytes = dhkey.g.len * (int)sizeof (BIG_CHUNK_TYPE); 342 bignum2bytestring(s, &(dhkey.g), s_bytes); 343 344 switch (key_type) { 345 346 case CKK_DES: 347 *secretkey_len = DES_KEYSIZE; 348 break; 349 case CKK_DES2: 350 *secretkey_len = DES2_KEYSIZE; 351 break; 352 case CKK_DES3: 353 *secretkey_len = DES3_KEYSIZE; 354 break; 355 case CKK_RC4: 356 case CKK_AES: 357 case CKK_GENERIC_SECRET: 358 /* use provided secret key length, if any */ 359 break; 360 default: 361 /* invalid key type */ 362 rv = CKR_ATTRIBUTE_TYPE_INVALID; 363 goto ret; 364 } 365 366 if (*secretkey_len == 0) { 367 *secretkey_len = s_bytes; 368 } 369 370 if (*secretkey_len > s_bytes) { 371 rv = CKR_ATTRIBUTE_VALUE_INVALID; 372 goto ret; 373 } 374 375 /* 376 * The truncation removes bytes from the leading end of the 377 * secret value. 378 */ 379 (void) memcpy(secretkey, (s + s_bytes - *secretkey_len), 380 *secretkey_len); 381 382 ret: 383 if (s != NULL) 384 #ifdef _KERNEL 385 kmem_free(s, s_alloc); 386 #else 387 free(s); 388 #endif 389 390 DH_key_finish(&dhkey); 391 392 return (rv); 393 } 394