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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * Portions of this source code were derived from Berkeley 4.3 BSD 32 * under license from the Regents of the University of California. 33 */ 34 35 #pragma ident "%Z%%M% %I% %E% SMI" 36 37 #include "mt.h" 38 #include <stdlib.h> 39 #include <mp.h> 40 #include <rpc/key_prot.h> 41 #include <rpcsvc/nis_dhext.h> 42 #include <thread.h> 43 44 extern long random(); 45 extern void _mp_move(MINT *, MINT *); 46 extern void des_setparity(char *); 47 static void adjust(); 48 void __gen_dhkeys(); 49 50 static MINT *MODULUS_192_0; 51 static mutex_t mod_192_0_lck = DEFAULTMUTEX; 52 static bool_t first_time = TRUE; 53 54 /* 55 * symbol names for the entry points into the Diffie-Hellman 56 * GSS mech backend routines 57 */ 58 static char dl_gen_funcname[] = "__dl_gen_dhkeys"; 59 static char dl_gen_common_funcname[] = "__dl_gen_common_dhkeys"; 60 61 /* 62 * Generate a seed 63 */ 64 static void 65 getseed(seed, seedsize, pass) 66 char *seed; 67 int seedsize; 68 unsigned char *pass; 69 { 70 int i; 71 int rseed; 72 struct timeval tv; 73 74 (void) gettimeofday(&tv, (struct timezone *)NULL); 75 rseed = tv.tv_sec + tv.tv_usec; 76 for (i = 0; i < 8; i++) { 77 rseed ^= (rseed << 8) | pass[i]; 78 } 79 (void) srandom(rseed); 80 81 for (i = 0; i < seedsize; i++) { 82 seed[i] = (random() & 0xff) ^ pass[i % 8]; 83 } 84 } 85 86 /* 87 * Adjust the input key so that it is 0-filled on the left 88 */ 89 static void 90 adjust(keyout, keyin) 91 char keyout[HEXKEYBYTES + 1]; 92 char *keyin; 93 { 94 char *p; 95 char *s; 96 97 for (p = keyin; *p; p++) 98 ; 99 for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) { 100 *s = *p; 101 } 102 while (s >= keyout) { 103 *s-- = '0'; 104 } 105 } 106 107 /* 108 * generate a Diffie-Hellman key-pair based on the given password. 109 * public and secret are buffers of size HEXKEYBYTES + 1. 110 */ 111 void 112 __gen_dhkeys(public, secret, pass) 113 char *public; 114 char *secret; 115 char *pass; 116 { 117 int i; 118 119 #define BASEBITS (8 * sizeof (short) - 1) 120 #define BASE (1 << BASEBITS) 121 122 MINT *pk = mp_itom(0); 123 MINT *sk = mp_itom(0); 124 MINT *tmp; 125 MINT *base = mp_itom(BASE/2); /* BASE won't fit in a short */ 126 MINT *root = mp_itom(PROOT); 127 MINT *modulus = mp_xtom(HEXMODULUS); 128 unsigned short r; 129 unsigned short seed[KEYSIZE/BASEBITS + 1]; 130 char *xkey; 131 132 /* multiply base by 2 to get BASE */ 133 tmp = mp_itom(2); 134 mp_mult(base, tmp, base); 135 mp_mfree(tmp); 136 137 getseed((char *)seed, (int)sizeof (seed), (uchar_t *)pass); 138 for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) { 139 r = seed[i] % ((unsigned short)BASE); 140 tmp = mp_itom(r); 141 mp_mult(sk, base, sk); 142 mp_madd(sk, tmp, sk); 143 mp_mfree(tmp); 144 } 145 tmp = mp_itom(0); 146 mp_mdiv(sk, modulus, tmp, sk); 147 mp_mfree(tmp); 148 mp_pow(root, sk, modulus, pk); 149 xkey = mp_mtox(sk); 150 (void) adjust(secret, xkey); 151 xkey = mp_mtox(pk); 152 (void) adjust(public, xkey); 153 mp_mfree(sk); 154 mp_mfree(base); 155 mp_mfree(pk); 156 mp_mfree(root); 157 mp_mfree(modulus); 158 } 159 160 161 /* 162 * Generic key size Diffie-Hellman key pair generation routine. For classic 163 * AUTH_DES, just call the current routine to handle it. Else, call the 164 * one in the appro GSS mech backend. 165 * 166 */ 167 int 168 __gen_dhkeys_g(char *pkey, /* out */ 169 char *skey, /* out */ 170 keylen_t keylen, /* in */ 171 algtype_t algtype, /* in */ 172 char *pass) /* in */ 173 { 174 const int classic_des = keylen == 192 && algtype == 0; 175 176 if (! pkey || ! skey || ! pass) 177 return (0); 178 179 if (classic_des) { 180 __gen_dhkeys(pkey, skey, pass); 181 return (1); 182 } else { 183 int (*dlfp)(); /* func ptr to dynamic loaded lib */ 184 185 if (dlfp = (int (*)())__nis_get_mechanism_symbol(keylen, 186 algtype, 187 dl_gen_funcname)) { 188 (*dlfp)(pkey, skey, pass); /* void */ 189 return (1); 190 } 191 } 192 193 return (0); 194 } 195 196 197 /* 198 * Choose middle 64 bits of the common key to use as our des key, possibly 199 * overwriting the lower order bits by setting parity. 200 * 201 * (copied/moved) from keyserv's setkey.c for the DH extensions. 202 */ 203 int 204 __extractdeskey(ck, deskey) 205 MINT *ck; 206 des_block *deskey; 207 { 208 MINT *a; 209 short r; 210 int i; 211 short base = (1 << 8); 212 char *k; 213 214 a = mp_itom(0); 215 _mp_move(ck, a); 216 for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) { 217 mp_sdiv(a, base, a, &r); 218 } 219 k = deskey->c; 220 for (i = 0; i < 8; i++) { 221 mp_sdiv(a, base, a, &r); 222 *k++ = r; 223 } 224 mp_mfree(a); 225 des_setparity((char *)deskey); 226 return (0); 227 } 228 229 230 /* 231 * Set the modulus for all our 192bit (algtype=0) Diffie-Hellman operations 232 */ 233 static void 234 setmodulus_192_0(void) 235 { 236 (void) mutex_lock(&mod_192_0_lck); 237 if (first_time) { 238 first_time = FALSE; 239 MODULUS_192_0 = mp_xtom(HEXMODULUS); 240 } 241 (void) mutex_unlock(&mod_192_0_lck); 242 } 243 244 /* 245 * Generic key size Diffie-Hellman common key generation routine. 246 * For classic AUTH_DES, do it inline like it's already done in several 247 * places (keyserv being one place). For new long key sizes, 248 * call the appro GSS mech backend routine. 249 * 250 * Arg 'keynum' is the size of the 'deskeys' array. It should be a 1 251 * classic AUTH_DES and a 3 for new long DH keys. 252 * 253 * Returns 1 on success and 0 on err. 254 */ 255 int 256 __gen_common_dhkeys_g(char *xpublic, /* in */ 257 char *xsecret, /* in */ 258 keylen_t keylen, /* in */ 259 algtype_t algtype, /* in */ 260 des_block deskeys[], /* out */ 261 keynum_t keynum) /* in */ 262 { 263 const int classic_des = keylen == 192 && algtype == 0; 264 265 if (! xpublic || ! xsecret || ! deskeys) 266 return (0); 267 268 if (classic_des) { 269 MINT *common; 270 MINT *public; 271 MINT *secret; 272 273 setmodulus_192_0(); 274 275 public = mp_xtom(xpublic); 276 secret = mp_xtom(xsecret); 277 common = mp_itom(0); 278 mp_pow(public, secret, MODULUS_192_0, common); 279 (void) __extractdeskey(common, &deskeys[0]); 280 return (1); 281 } else { 282 int (*dlfp)(); /* func ptr to dynamically loaded lib */ 283 284 if (dlfp = (int (*)())__nis_get_mechanism_symbol(keylen, 285 algtype, 286 dl_gen_common_funcname)) { 287 /* function called will have void return value */ 288 (*dlfp)(xpublic, xsecret, deskeys, keynum); 289 return (1); 290 } 291 } 292 293 return (0); 294 } 295