Merge from vendor branch OPENSSL:
[dragonfly.git] / crypto / telnet / libtelnet / rsaencpwd.c
1 /*-
2  * Copyright (c) 1992, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)rsaencpwd.c      8.3 (Berkeley) 5/30/95
34  * $FreeBSD: src/crypto/telnet/libtelnet/rsaencpwd.c,v 1.1.1.1.8.1 2002/04/13 10:59:07 markm Exp $
35  * $DragonFly: src/crypto/telnet/libtelnet/rsaencpwd.c,v 1.2 2003/06/17 04:24:37 dillon Exp $
36  */
37
38 #ifdef  RSA_ENCPWD
39 /*
40  * COPYRIGHT (C) 1990 DIGITAL EQUIPMENT CORPORATION
41  * ALL RIGHTS RESERVED
42  *
43  * "Digital Equipment Corporation authorizes the reproduction,
44  * distribution and modification of this software subject to the following
45  * restrictions:
46  *
47  * 1.  Any partial or whole copy of this software, or any modification
48  * thereof, must include this copyright notice in its entirety.
49  *
50  * 2.  This software is supplied "as is" with no warranty of any kind,
51  * expressed or implied, for any purpose, including any warranty of fitness
52  * or merchantibility.  DIGITAL assumes no responsibility for the use or
53  * reliability of this software, nor promises to provide any form of
54  * support for it on any basis.
55  *
56  * 3.  Distribution of this software is authorized only if no profit or
57  * remuneration of any kind is received in exchange for such distribution.
58  *
59  * 4.  This software produces public key authentication certificates
60  * bearing an expiration date established by DIGITAL and RSA Data
61  * Security, Inc.  It may cease to generate certificates after the expiration
62  * date.  Any modification of this software that changes or defeats
63  * the expiration date or its effect is unauthorized.
64  *
65  * 5.  Software that will renew or extend the expiration date of
66  * authentication certificates produced by this software may be obtained
67  * from RSA Data Security, Inc., 10 Twin Dolphin Drive, Redwood City, CA
68  * 94065, (415)595-8782, or from DIGITAL"
69  *
70  */
71
72 #include <sys/types.h>
73 #include <arpa/telnet.h>
74 #include <pwd.h>
75 #include <stdio.h>
76 #include <stdlib.h>
77 #include <string.h>
78
79 #include "encrypt.h"
80 #include "auth.h"
81 #include "misc.h"
82 #include "cdc.h"
83
84 extern auth_debug_mode;
85
86 static unsigned char str_data[1024] = { IAC, SB, TELOPT_AUTHENTICATION, 0,
87                                         AUTHTYPE_RSA_ENCPWD, };
88 static unsigned char str_name[1024] = { IAC, SB, TELOPT_AUTHENTICATION,
89                                         TELQUAL_NAME, };
90
91 #define RSA_ENCPWD_AUTH 0       /* Authentication data follows */
92 #define RSA_ENCPWD_REJECT       1       /* Rejected (reason might follow) */
93 #define RSA_ENCPWD_ACCEPT       2       /* Accepted */
94 #define RSA_ENCPWD_CHALLENGEKEY 3       /* Challenge and public key */
95
96 #define NAME_SZ   40
97 #define CHAL_SZ   20
98 #define PWD_SZ    40
99
100 static  KTEXT_ST auth;
101 static  char name[NAME_SZ];
102 static  char user_passwd[PWD_SZ];
103 static  char key_file[2*NAME_SZ];
104 static  char lhostname[NAME_SZ];
105 static char  challenge[CHAL_SZ];
106 static int   challenge_len;
107
108         static int
109 Data(ap, type, d, c)
110         Authenticator *ap;
111         int type;
112         void *d;
113         int c;
114 {
115         unsigned char *p = str_data + 4;
116         unsigned char *cd = (unsigned char *)d;
117
118         if (c == -1)
119                 c = strlen((char *)cd);
120
121         if (0) {
122                 printf("%s:%d: [%d] (%d)",
123                         str_data[3] == TELQUAL_IS ? ">>>IS" : ">>>REPLY",
124                         str_data[3],
125                         type, c);
126                 printd(d, c);
127                 printf("\r\n");
128         }
129         *p++ = ap->type;
130         *p++ = ap->way;
131         if (type != NULL) *p++ = type;
132         while (c-- > 0) {
133                 if ((*p++ = *cd++) == IAC)
134                         *p++ = IAC;
135         }
136         *p++ = IAC;
137         *p++ = SE;
138         if (str_data[3] == TELQUAL_IS)
139                 printsub('>', &str_data[2], p - (&str_data[2]));
140         return(net_write(str_data, p - str_data));
141 }
142
143         int
144 rsaencpwd_init(ap, server)
145         Authenticator *ap;
146         int server;
147 {
148         char  *cp;
149         FILE  *fp;
150
151         if (server) {
152                 str_data[3] = TELQUAL_REPLY;
153                 memset(key_file, 0, sizeof(key_file));
154                 gethostname(lhostname, sizeof(lhostname));
155                 if ((cp = strchr(lhostname, '.')) != 0)  *cp = '\0';
156                 strcpy(key_file, "/etc/.");
157                 strcat(key_file, lhostname);
158                 strcat(key_file, "_privkey");
159                 if ((fp=fopen(key_file, "r"))==NULL) return(0);
160                 fclose(fp);
161         } else {
162                 str_data[3] = TELQUAL_IS;
163         }
164         return(1);
165 }
166
167         int
168 rsaencpwd_send(ap)
169         Authenticator *ap;
170 {
171
172         printf("[ Trying RSAENCPWD ... ]\n");
173         if (!UserNameRequested) {
174                 return(0);
175         }
176         if (!auth_sendname(UserNameRequested, strlen(UserNameRequested))) {
177                 return(0);
178         }
179         if (!Data(ap, NULL, (void *)NULL, 0)) {
180                 return(0);
181         }
182
183
184         return(1);
185 }
186
187         void
188 rsaencpwd_is(ap, data, cnt)
189         Authenticator *ap;
190         unsigned char *data;
191         int cnt;
192 {
193         Session_Key skey;
194         Block datablock;
195         char  r_passwd[PWD_SZ], r_user[NAME_SZ];
196         char  *cp, key[160];
197         char  chalkey[160], *ptr;
198         FILE  *fp;
199         int r, i, j, chalkey_len, len;
200         time_t now;
201
202         cnt--;
203         switch (*data++) {
204         case RSA_ENCPWD_AUTH:
205                 memmove((void *)auth.dat, (void *)data, auth.length = cnt);
206
207                 if ((fp=fopen(key_file, "r"))==NULL) {
208                   Data(ap, RSA_ENCPWD_REJECT, (void *)"Auth failed", -1);
209                   auth_finished(ap, AUTH_REJECT);
210                   return;
211                 }
212                 /*
213                  *  get privkey
214                  */
215                 fscanf(fp, "%x;", &len);
216                 for (i=0;i<len;i++) {
217                   j = getc(fp);  key[i]=j;
218                 }
219                 fclose(fp);
220
221                 r = accept_rsa_encpwd(&auth, key, challenge,
222                                       challenge_len, r_passwd);
223                 if (r < 0) {
224                   Data(ap, RSA_ENCPWD_REJECT, (void *)"Auth failed", -1);
225                   auth_finished(ap, AUTH_REJECT);
226                   return;
227                 }
228                 auth_encrypt_userpwd(r_passwd);
229                 if (rsaencpwd_passwdok(UserNameRequested, UserPassword) == 0) {
230                   /*
231                    *  illegal username and password
232                    */
233                   Data(ap, RSA_ENCPWD_REJECT, (void *)"Illegal password", -1);
234                   auth_finished(ap, AUTH_REJECT);
235                   return;
236                 }
237
238                 Data(ap, RSA_ENCPWD_ACCEPT, (void *)0, 0);
239                 auth_finished(ap, AUTH_USER);
240                 break;
241
242
243         case IAC:
244
245                 /*
246                  * If we are doing mutual authentication, get set up to send
247                  * the challenge, and verify it when the response comes back.
248                  */
249                 if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_ONE_WAY) {
250                   register int i;
251
252
253                   time(&now);
254                   if ((now % 2) == 0) {
255                     sprintf(challenge, "%x", now);
256                     challenge_len = strlen(challenge);
257                   } else {
258                     strcpy(challenge, "randchal");
259                     challenge_len = 8;
260                   }
261
262                   if ((fp=fopen(key_file, "r"))==NULL) {
263                     Data(ap, RSA_ENCPWD_REJECT, (void *)"Auth failed", -1);
264                     auth_finished(ap, AUTH_REJECT);
265                     return;
266                   }
267                   /*
268                    *  skip privkey
269                    */
270                   fscanf(fp, "%x;", &len);
271                   for (i=0;i<len;i++) {
272                     j = getc(fp);
273                   }
274                   /*
275                    * get pubkey
276                    */
277                   fscanf(fp, "%x;", &len);
278                   for (i=0;i<len;i++) {
279                     j = getc(fp);  key[i]=j;
280                   }
281                   fclose(fp);
282                   chalkey[0] = 0x30;
283                   ptr = (char *) &chalkey[1];
284                   chalkey_len = 1+NumEncodeLengthOctets(i)+i+1+NumEncodeLengthOctets(challenge_len)+challenge_len;
285                   EncodeLength(ptr, chalkey_len);
286                   ptr +=NumEncodeLengthOctets(chalkey_len);
287                   *ptr++ = 0x04;  /* OCTET STRING */
288                   *ptr++ = challenge_len;
289                   memmove(ptr, challenge, challenge_len);
290                   ptr += challenge_len;
291                   *ptr++ = 0x04;  /* OCTET STRING */
292                   EncodeLength(ptr, i);
293                   ptr += NumEncodeLengthOctets(i);
294                   memmove(ptr, key, i);
295                   chalkey_len = 1+NumEncodeLengthOctets(chalkey_len)+chalkey_len;
296                   Data(ap, RSA_ENCPWD_CHALLENGEKEY, (void *)chalkey, chalkey_len);
297                 }
298                 break;
299
300         default:
301                 Data(ap, RSA_ENCPWD_REJECT, 0, 0);
302                 break;
303         }
304 }
305
306
307         void
308 rsaencpwd_reply(ap, data, cnt)
309         Authenticator *ap;
310         unsigned char *data;
311         int cnt;
312 {
313         Session_Key skey;
314         KTEXT_ST token;
315         Block enckey;
316         int r, pubkey_len;
317         char    randchal[CHAL_SZ], *cp;
318         char    chalkey[160], pubkey[128], *ptr;
319
320         if (cnt-- < 1)
321                 return;
322         switch (*data++) {
323         case RSA_ENCPWD_REJECT:
324                 if (cnt > 0) {
325                         printf("[ RSA_ENCPWD refuses authentication because %.*s ]\r\n",
326                                 cnt, data);
327                 } else
328                         printf("[ RSA_ENCPWD refuses authentication ]\r\n");
329                 auth_send_retry();
330                 return;
331         case RSA_ENCPWD_ACCEPT:
332                 printf("[ RSA_ENCPWD accepts you ]\n");
333                 auth_finished(ap, AUTH_USER);
334                 return;
335         case RSA_ENCPWD_CHALLENGEKEY:
336                 /*
337                  * Verify that the response to the challenge is correct.
338                  */
339
340                 memmove((void *)chalkey, (void *)data, cnt);
341                 ptr = (char *) &chalkey[0];
342                 ptr += DecodeHeaderLength(chalkey);
343                 if (*ptr != 0x04) {
344                   return;
345                 }
346                 *ptr++;
347                 challenge_len = DecodeValueLength(ptr);
348                 ptr += NumEncodeLengthOctets(challenge_len);
349                 memmove(challenge, ptr, challenge_len);
350                 ptr += challenge_len;
351                 if (*ptr != 0x04) {
352                   return;
353                 }
354                 *ptr++;
355                 pubkey_len = DecodeValueLength(ptr);
356                 ptr += NumEncodeLengthOctets(pubkey_len);
357                 memmove(pubkey, ptr, pubkey_len);
358                 memset(user_passwd, 0, sizeof(user_passwd));
359                 local_des_read_pw_string(user_passwd, sizeof(user_passwd)-1, "Password: ", 0);
360                 UserPassword = user_passwd;
361                 Challenge = challenge;
362                 r = init_rsa_encpwd(&token, user_passwd, challenge, challenge_len, pubkey);
363                 if (r < 0) {
364                   token.length = 1;
365                 }
366
367                 if (!Data(ap, RSA_ENCPWD_AUTH, (void *)token.dat, token.length)) {
368                   return;
369                 }
370
371                 break;
372
373         default:
374                 return;
375         }
376 }
377
378         int
379 rsaencpwd_status(ap, name, level)
380         Authenticator *ap;
381         char *name;
382         int level;
383 {
384
385         if (level < AUTH_USER)
386                 return(level);
387
388         if (UserNameRequested && rsaencpwd_passwdok(UserNameRequested, UserPassword)) {
389                 strcpy(name, UserNameRequested);
390                 return(AUTH_VALID);
391         } else {
392                 return(AUTH_USER);
393         }
394 }
395
396 #define BUMP(buf, len)          while (*(buf)) {++(buf), --(len);}
397 #define ADDC(buf, len, c)       if ((len) > 0) {*(buf)++ = (c); --(len);}
398
399         void
400 rsaencpwd_printsub(data, cnt, buf, buflen)
401         unsigned char *data, *buf;
402         int cnt, buflen;
403 {
404         char lbuf[32];
405         register int i;
406
407         buf[buflen-1] = '\0';           /* make sure its NULL terminated */
408         buflen -= 1;
409
410         switch(data[3]) {
411         case RSA_ENCPWD_REJECT: /* Rejected (reason might follow) */
412                 strncpy((char *)buf, " REJECT ", buflen);
413                 goto common;
414
415         case RSA_ENCPWD_ACCEPT: /* Accepted (name might follow) */
416                 strncpy((char *)buf, " ACCEPT ", buflen);
417         common:
418                 BUMP(buf, buflen);
419                 if (cnt <= 4)
420                         break;
421                 ADDC(buf, buflen, '"');
422                 for (i = 4; i < cnt; i++)
423                         ADDC(buf, buflen, data[i]);
424                 ADDC(buf, buflen, '"');
425                 ADDC(buf, buflen, '\0');
426                 break;
427
428         case RSA_ENCPWD_AUTH:           /* Authentication data follows */
429                 strncpy((char *)buf, " AUTH", buflen);
430                 goto common2;
431
432         case RSA_ENCPWD_CHALLENGEKEY:
433                 strncpy((char *)buf, " CHALLENGEKEY", buflen);
434                 goto common2;
435
436         default:
437                 sprintf(lbuf, " %d (unknown)", data[3]);
438                 strncpy((char *)buf, lbuf, buflen);
439         common2:
440                 BUMP(buf, buflen);
441                 for (i = 4; i < cnt; i++) {
442                         sprintf(lbuf, " %d", data[i]);
443                         strncpy((char *)buf, lbuf, buflen);
444                         BUMP(buf, buflen);
445                 }
446                 break;
447         }
448 }
449
450 int rsaencpwd_passwdok(name, passwd)
451 char *name, *passwd;
452 {
453   char *crypt();
454   char *salt, *p;
455   struct passwd *pwd;
456   int   passwdok_status = 0;
457
458   if (pwd = getpwnam(name))
459     salt = pwd->pw_passwd;
460   else salt = "xx";
461
462   p = crypt(passwd, salt);
463
464   if (pwd && !strcmp(p, pwd->pw_passwd)) {
465     passwdok_status = 1;
466   } else passwdok_status = 0;
467   return(passwdok_status);
468 }
469
470 #endif