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
getseed(seed,seedsize,pass)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
adjust(keyout,keyin)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
__gen_dhkeys(public,secret,pass)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
__gen_dhkeys_g(char * pkey,char * skey,keylen_t keylen,algtype_t algtype,char * pass)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
__extractdeskey(ck,deskey)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
setmodulus_192_0(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
__gen_common_dhkeys_g(char * xpublic,char * xsecret,keylen_t keylen,algtype_t algtype,des_block deskeys[],keynum_t keynum)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