xref: /NextBSD/contrib/opie/opiekey.c (revision b137080f19736ee33fede2e88bb54438604cf86b)
1 /* opiekey.c: Stand-alone program for computing responses to OTP challenges.
2 
3  Takes a sequence number and seed (presumably from an OPIE challenge)
4  as command line arguments, prompts for the user's secret pass phrase,
5  and outputs a response.
6 
7 %%% portions-copyright-cmetz-96
8 Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights
9 Reserved. The Inner Net License Version 2 applies to these portions of
10 the software.
11 You should have received a copy of the license with this software. If
12 you didn't get a copy, you may request one from <license@inner.net>.
13 
14 Portions of this software are Copyright 1995 by Randall Atkinson and Dan
15 McDonald, All Rights Reserved. All Rights under this copyright are assigned
16 to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
17 License Agreement applies to this software.
18 
19 	History:
20 
21 	Modified by cmetz for OPIE 2.4. Use struct opie_key for key blocks.
22 	Modified by cmetz for OPIE 2.31. Renamed "init" and RESPONSE_INIT
23 	        to "init-hex" and RESPONSE_INIT_HEX. Removed active attack
24 		protection support.
25 	Modified by cmetz for OPIE 2.3. OPIE_PASS_MAX changed to
26 		OPIE_SECRET_MAX. Added extended responses, which created
27 		lots of changes. Eliminated extra variable. Added -x and
28 		-t to help. Added -f flag. Added SHA support.
29 	Modified by cmetz for OPIE 2.22. Print newline after seed too long
30 	        message. Check for minimum seed length. Correct a grammar
31 		error.
32         Modified at NRL for OPIE 2.2. Check opiereadpass() return.
33                 Change opiereadpass() calls to add echo arg. Use FUNCTION
34                 definition et al. Check seed length here, too. Added back
35 		hex output. Reworked final output function.
36 	Modified at NRL for OPIE 2.0.
37 	Written at Bellcore for the S/Key Version 1 software distribution
38 		(skey.c).
39 
40 $FreeBSD$
41 
42 */
43 #include "opie_cfg.h"
44 
45 #include <stdio.h>
46 #include <string.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 
50 #include "opie.h"
51 
52 #ifdef	__MSDOS__
53 #include <dos.h>
54 #endif
55 
56 #if HAVE_FCNTL_H
57 #include <fcntl.h>
58 #endif /* HAVE_FCNTL_H */
59 
60 extern char *optarg;
61 extern int optind, opterr;
62 
63 int aflag = 0;
64 
65 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
66 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
67 
68 /******** Begin real source code ***************/
69 
70 static VOIDRET usage FUNCTION((s), char *s)
71 {
72   fprintf(stderr, "usage: %s [-v] [-h] [-f] [-x] [-t type] [-4 | -5 | -s] [-a] [-n count] sequence_number seed\n", s);
73   exit(1);
74 }
75 
76 #define RESPONSE_STANDARD  0
77 #define RESPONSE_WORD      1
78 #define RESPONSE_HEX       2
79 #define RESPONSE_INIT_HEX  3
80 #define RESPONSE_INIT_WORD 4
81 #define RESPONSE_UNKNOWN   5
82 
83 struct _rtrans {
84   int type;
85   char *name;
86 };
87 
88 static struct _rtrans rtrans[] = {
89   { RESPONSE_WORD, "word" },
90   { RESPONSE_HEX, "hex" },
91   { RESPONSE_INIT_HEX, "init-hex" },
92   { RESPONSE_INIT_WORD, "init-word" },
93   { RESPONSE_STANDARD, "" },
94   { RESPONSE_STANDARD, "standard" },
95   { RESPONSE_STANDARD, "otp" },
96   { RESPONSE_UNKNOWN, NULL }
97 };
98 
99 static void getsecret FUNCTION((secret, promptextra, retype), char *secret AND char *promptextra AND int flags)
100 {
101   fprintf(stderr, "Enter %ssecret pass phrase: ", promptextra);
102   if (!opiereadpass(secret, OPIE_SECRET_MAX, 0)) {
103     fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra);
104     exit(1);
105   }
106   if (secret[0] && (flags & 1)) {
107     char verify[OPIE_SECRET_MAX + 1];
108 
109     fprintf(stderr, "Again %ssecret pass phrase: ", promptextra);
110     if (!opiereadpass(verify, OPIE_SECRET_MAX, 0)) {
111       fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra);
112       memset(verify, 0, sizeof(verify));
113       memset(secret, 0, OPIE_SECRET_MAX + 1);
114       exit(1);
115     }
116     if (verify[0] && strcmp(verify, secret)) {
117       fprintf(stderr, "They don't match. Try again.\n");
118       memset(verify, 0, sizeof(verify));
119       memset(secret, 0, OPIE_SECRET_MAX + 1);
120       exit(1);
121     }
122     memset(verify, 0, sizeof(verify));
123   }
124   if (!(flags & 2) && !aflag && opiepasscheck(secret)) {
125     memset(secret, 0, OPIE_SECRET_MAX + 1);
126     fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX);
127     exit(1);
128   };
129 }
130 
131 int main FUNCTION((argc, argv), int argc AND char *argv[])
132 {
133   /* variable declarations */
134   unsigned algorithm = MDX;	/* default algorithm per Makefile's MDX
135 				   symbol */
136   int keynum = 0;
137   int i;
138   int count = 1;
139   char secret[OPIE_SECRET_MAX + 1], newsecret[OPIE_SECRET_MAX + 1];
140   struct opie_otpkey key, newkey;
141   char *seed, newseed[OPIE_SEED_MAX + 1];
142   char response[OPIE_RESPONSE_MAX + 1];
143   char *slash;
144   int hex = 0;
145   int type = RESPONSE_STANDARD;
146   int force = 0;
147 
148   if (slash = strrchr(argv[0], '/'))
149     slash++;
150   else
151     slash = argv[0];
152 
153   if (!strcmp(slash, "key") || strstr(slash, "md4"))
154     algorithm = 4;
155 
156   if (strstr(slash, "md5"))
157     algorithm = 5;
158 
159   if (strstr(slash, "sha"))
160     algorithm = 3;
161 
162   while ((i = getopt(argc, argv, "fhvn:x45at:s")) != EOF) {
163     switch (i) {
164     case 'v':
165       opieversion();
166 
167     case 'n':
168       count = atoi(optarg);
169       break;
170 
171     case 'x':
172       hex = 1;
173       break;
174 
175     case 'f':
176 #if INSECURE_OVERRIDE
177       force = 1;
178 #else /* INSECURE_OVERRIDE */
179       fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n");
180 #endif /* INSECURE_OVERRIDE */
181       break;
182 
183     case '4':
184       /* use MD4 algorithm */
185       algorithm = 4;
186       break;
187 
188     case '5':
189       /* use MD5 algorithm */
190       algorithm = 5;
191       break;
192 
193     case 'a':
194       aflag = 1;
195       break;
196 
197     case 't':
198       {
199 	struct _rtrans *r;
200 	for (r = rtrans; r->name && strcmp(r->name, optarg); r++);
201 	if (!r->name) {
202 	  fprintf(stderr, "%s: %s: unknown response type.\n", argv[0], optarg);
203 	  exit(1);
204 	}
205 	type = r->type;
206       }
207       break;
208 
209     case 's':
210       algorithm = 3;
211       break;
212 
213     default:
214       usage(argv[0]);
215     }
216   }
217 
218   if ((argc - optind) < 2)
219     usage(argv[0]);
220 
221   fprintf(stderr, "Using the %s algorithm to compute response.\n", algnames[algorithm]);
222 
223   /* get sequence number, which is next-to-last parameter */
224   keynum = atoi(argv[optind]);
225   if (keynum < 1) {
226     fprintf(stderr, "Sequence number %s is not positive.\n", argv[optind]);
227     exit(1);
228   }
229   /* get seed string, which is last parameter */
230   seed = argv[optind + 1];
231   {
232     i = strlen(seed);
233 
234     if (i > OPIE_SEED_MAX) {
235       fprintf(stderr, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX);
236       exit(1);
237     }
238     if (i < OPIE_SEED_MIN) {
239       fprintf(stderr, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN);
240       exit(1);
241     }
242   }
243 
244   fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n");
245 
246   if (opieinsecure()) {
247     fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
248 #if INSECURE_OVERRIDE
249     if (force)
250       fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
251     else
252 #endif /* INSECURE_OVERRIDE */
253       exit(1);
254   }
255 
256   if ((type == RESPONSE_INIT_HEX) || (type == RESPONSE_INIT_WORD)) {
257 #if RETYPE
258     getsecret(secret, "old ", 1);
259 #else /* RETYPE */
260     getsecret(secret, "old ", 0);
261 #endif /* RETYPE */
262     getsecret(newsecret, "new ", 1);
263     if (!newsecret[0])
264       strcpy(newsecret, secret);
265 
266     if (opienewseed(strcpy(newseed, seed)) < 0) {
267       fprintf(stderr, "Error updating seed.\n");
268       goto error;
269     }
270 
271     if (opiekeycrunch(algorithm, &newkey, newseed, newsecret)) {
272       fprintf(stderr, "%s: key crunch failed (1)\n", argv[0]);
273       goto error;
274     }
275 
276     for (i = 0; i < 499; i++)
277       opiehash(&newkey, algorithm);
278   } else
279 #if RETYPE
280     getsecret(secret, "", 1);
281 #else /* RETYPE */
282     getsecret(secret, "", 0);
283 #endif /* RETYPE */
284 
285   /* Crunch seed and secret password into starting key normally */
286   if (opiekeycrunch(algorithm, &key, seed, secret)) {
287     fprintf(stderr, "%s: key crunch failed\n", argv[0]);
288     goto error;
289   }
290 
291   for (i = 0; i <= (keynum - count); i++)
292     opiehash(&key, algorithm);
293 
294   {
295     char buf[OPIE_SEED_MAX + 48 + 1];
296     char *c;
297 
298     for (; i <= keynum; i++) {
299       if (count > 1)
300 	printf("%d: %s", i, (type == RESPONSE_STANDARD) ? "" : "\n");
301 
302       switch(type) {
303       case RESPONSE_STANDARD:
304 	if (hex)
305 	  opiebtoh(response, &key);
306 	else
307 	  opiebtoe(response, &key);
308 	break;
309       case RESPONSE_WORD:
310 	strcpy(response, "word:");
311 	strcat(response, opiebtoe(buf, &key));
312 	break;
313       case RESPONSE_HEX:
314 	strcpy(response, "hex:");
315 	strcat(response, opiebtoh(buf, &key));
316 	break;
317       case RESPONSE_INIT_HEX:
318       case RESPONSE_INIT_WORD:
319 	if (type == RESPONSE_INIT_HEX) {
320 	  strcpy(response, "init-hex:");
321 	  strcat(response, opiebtoh(buf, &key));
322 	  sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed);
323 	  strcat(response, buf);
324 	  strcat(response, opiebtoh(buf, &newkey));
325 	} else {
326 	  strcpy(response, "init-word:");
327 	  strcat(response, opiebtoe(buf, &key));
328 	  sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed);
329 	  strcat(response, buf);
330 	  strcat(response, opiebtoe(buf, &newkey));
331 	}
332 	break;
333       }
334       puts(response);
335       opiehash(&key, algorithm);
336     }
337   }
338 
339   memset(secret, 0, sizeof(secret));
340   memset(newsecret, 0, sizeof(newsecret));
341   return 0;
342 
343 error:
344   memset(secret, 0, sizeof(secret));
345   memset(newsecret, 0, sizeof(newsecret));
346   return 1;
347 }
348