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 #include "mt.h" 36 #include <stdlib.h> 37 #include <mp.h> 38 #include <rpc/key_prot.h> 39 #include <rpcsvc/nis_dhext.h> 40 #include <thread.h> 41 42 extern long random(); 43 extern void _mp_move(MINT *, MINT *); 44 extern void des_setparity(char *); 45 static void adjust(); 46 void __gen_dhkeys(); 47 48 static MINT *MODULUS_192_0; 49 static mutex_t mod_192_0_lck = DEFAULTMUTEX; 50 static bool_t first_time = TRUE; 51 52 /* 53 * symbol names for the entry points into the Diffie-Hellman 54 * GSS mech backend routines 55 */ 56 static char dl_gen_funcname[] = "__dl_gen_dhkeys"; 57 static char dl_gen_common_funcname[] = "__dl_gen_common_dhkeys"; 58 59 /* 60 * Generate a seed 61 */ 62 static void 63 getseed(seed, seedsize, pass) 64 char *seed; 65 int seedsize; 66 unsigned char *pass; 67 { 68 int i; 69 int rseed; 70 struct timeval tv; 71 72 (void) gettimeofday(&tv, (struct timezone *)NULL); 73 rseed = tv.tv_sec + tv.tv_usec; 74 for (i = 0; i < 8; i++) { 75 rseed ^= (rseed << 8) | pass[i]; 76 } 77 (void) srandom(rseed); 78 79 for (i = 0; i < seedsize; i++) { 80 seed[i] = (random() & 0xff) ^ pass[i % 8]; 81 } 82 } 83 84 /* 85 * Adjust the input key so that it is 0-filled on the left 86 */ 87 static void 88 adjust(keyout, keyin) 89 char keyout[HEXKEYBYTES + 1]; 90 char *keyin; 91 { 92 char *p; 93 char *s; 94 95 for (p = keyin; *p; p++) 96 ; 97 for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) { 98 *s = *p; 99 } 100 while (s >= keyout) { 101 *s-- = '0'; 102 } 103 } 104 105 /* 106 * generate a Diffie-Hellman key-pair based on the given password. 107 * public and secret are buffers of size HEXKEYBYTES + 1. 108 */ 109 void 110 __gen_dhkeys(public, secret, pass) 111 char *public; 112 char *secret; 113 char *pass; 114 { 115 int i; 116 117 #define BASEBITS (8 * sizeof (short) - 1) 118 #define BASE (1 << BASEBITS) 119 120 MINT *pk = mp_itom(0); 121 MINT *sk = mp_itom(0); 122 MINT *tmp; 123 MINT *base = mp_itom(BASE/2); /* BASE won't fit in a short */ 124 MINT *root = mp_itom(PROOT); 125 MINT *modulus = mp_xtom(HEXMODULUS); 126 unsigned short r; 127 unsigned short seed[KEYSIZE/BASEBITS + 1]; 128 char *xkey; 129 130 /* multiply base by 2 to get BASE */ 131 tmp = mp_itom(2); 132 mp_mult(base, tmp, base); 133 mp_mfree(tmp); 134 135 getseed((char *)seed, (int)sizeof (seed), (uchar_t *)pass); 136 for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) { 137 r = seed[i] % ((unsigned short)BASE); 138 tmp = mp_itom(r); 139 mp_mult(sk, base, sk); 140 mp_madd(sk, tmp, sk); 141 mp_mfree(tmp); 142 } 143 tmp = mp_itom(0); 144 mp_mdiv(sk, modulus, tmp, sk); 145 mp_mfree(tmp); 146 mp_pow(root, sk, modulus, pk); 147 xkey = mp_mtox(sk); 148 (void) adjust(secret, xkey); 149 xkey = mp_mtox(pk); 150 (void) adjust(public, xkey); 151 mp_mfree(sk); 152 mp_mfree(base); 153 mp_mfree(pk); 154 mp_mfree(root); 155 mp_mfree(modulus); 156 } 157 158 159 /* 160 * Generic key size Diffie-Hellman key pair generation routine. For classic 161 * AUTH_DES, just call the current routine to handle it. Else, call the 162 * one in the appro GSS mech backend. 163 * 164 */ 165 int 166 __gen_dhkeys_g(char *pkey, /* out */ 167 char *skey, /* out */ 168 keylen_t keylen, /* in */ 169 algtype_t algtype, /* in */ 170 char *pass) /* in */ 171 { 172 const int classic_des = keylen == 192 && algtype == 0; 173 174 if (! pkey || ! skey || ! pass) 175 return (0); 176 177 if (classic_des) { 178 __gen_dhkeys(pkey, skey, pass); 179 return (1); 180 } else { 181 int (*dlfp)(); /* func ptr to dynamic loaded lib */ 182 183 if (dlfp = (int (*)())__nis_get_mechanism_symbol(keylen, 184 algtype, 185 dl_gen_funcname)) { 186 (*dlfp)(pkey, skey, pass); /* void */ 187 return (1); 188 } 189 } 190 191 return (0); 192 } 193 194 195 /* 196 * Choose middle 64 bits of the common key to use as our des key, possibly 197 * overwriting the lower order bits by setting parity. 198 * 199 * (copied/moved) from keyserv's setkey.c for the DH extensions. 200 */ 201 int 202 __extractdeskey(ck, deskey) 203 MINT *ck; 204 des_block *deskey; 205 { 206 MINT *a; 207 short r; 208 int i; 209 short base = (1 << 8); 210 char *k; 211 212 a = mp_itom(0); 213 _mp_move(ck, a); 214 for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) { 215 mp_sdiv(a, base, a, &r); 216 } 217 k = deskey->c; 218 for (i = 0; i < 8; i++) { 219 mp_sdiv(a, base, a, &r); 220 *k++ = r; 221 } 222 mp_mfree(a); 223 des_setparity((char *)deskey); 224 return (0); 225 } 226 227 228 /* 229 * Set the modulus for all our 192bit (algtype=0) Diffie-Hellman operations 230 */ 231 static void 232 setmodulus_192_0(void) 233 { 234 (void) mutex_lock(&mod_192_0_lck); 235 if (first_time) { 236 first_time = FALSE; 237 MODULUS_192_0 = mp_xtom(HEXMODULUS); 238 } 239 (void) mutex_unlock(&mod_192_0_lck); 240 } 241 242 /* 243 * Generic key size Diffie-Hellman common key generation routine. 244 * For classic AUTH_DES, do it inline like it's already done in several 245 * places (keyserv being one place). For new long key sizes, 246 * call the appro GSS mech backend routine. 247 * 248 * Arg 'keynum' is the size of the 'deskeys' array. It should be a 1 249 * classic AUTH_DES and a 3 for new long DH keys. 250 * 251 * Returns 1 on success and 0 on err. 252 */ 253 int 254 __gen_common_dhkeys_g(char *xpublic, /* in */ 255 char *xsecret, /* in */ 256 keylen_t keylen, /* in */ 257 algtype_t algtype, /* in */ 258 des_block deskeys[], /* out */ 259 keynum_t keynum) /* in */ 260 { 261 const int classic_des = keylen == 192 && algtype == 0; 262 263 if (! xpublic || ! xsecret || ! deskeys) 264 return (0); 265 266 if (classic_des) { 267 MINT *common; 268 MINT *public; 269 MINT *secret; 270 271 setmodulus_192_0(); 272 273 public = mp_xtom(xpublic); 274 secret = mp_xtom(xsecret); 275 common = mp_itom(0); 276 mp_pow(public, secret, MODULUS_192_0, common); 277 (void) __extractdeskey(common, &deskeys[0]); 278 return (1); 279 } else { 280 int (*dlfp)(); /* func ptr to dynamically loaded lib */ 281 282 if (dlfp = (int (*)())__nis_get_mechanism_symbol(keylen, 283 algtype, 284 dl_gen_common_funcname)) { 285 /* function called will have void return value */ 286 (*dlfp)(xpublic, xsecret, deskeys, keynum); 287 return (1); 288 } 289 } 290 291 return (0); 292 } 293