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