]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/opie/opiekey.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / opie / opiekey.c
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
49 #include "opie.h"
50
51 #ifdef  __MSDOS__
52 #include <dos.h>
53 #endif
54
55 #if HAVE_FCNTL_H
56 #include <fcntl.h>
57 #endif /* HAVE_FCNTL_H */
58
59 extern char *optarg;
60 extern int optind, opterr;
61
62 int aflag = 0;
63
64 char *algnames[] = { NULL, NULL, NULL, "SHA-1", "MD4", "MD5" };
65 char *algids[] = { NULL, NULL, NULL, "sha1", "md4", "md5" };
66
67 /******** Begin real source code ***************/
68
69 static VOIDRET usage FUNCTION((s), char *s)
70 {
71   fprintf(stderr, "usage: %s [-v] [-h] [-f] [-x] [-t type] [-4 | -5 | -s] [-a] [-n count] sequence_number seed\n", s);
72   exit(1);
73 }
74
75 #define RESPONSE_STANDARD  0
76 #define RESPONSE_WORD      1
77 #define RESPONSE_HEX       2
78 #define RESPONSE_INIT_HEX  3
79 #define RESPONSE_INIT_WORD 4
80 #define RESPONSE_UNKNOWN   5
81
82 struct _rtrans {
83   int type;
84   char *name;
85 };
86
87 static struct _rtrans rtrans[] = {
88   { RESPONSE_WORD, "word" },
89   { RESPONSE_HEX, "hex" },
90   { RESPONSE_INIT_HEX, "init-hex" },
91   { RESPONSE_INIT_WORD, "init-word" },
92   { RESPONSE_STANDARD, "" },
93   { RESPONSE_STANDARD, "standard" },
94   { RESPONSE_STANDARD, "otp" },
95   { RESPONSE_UNKNOWN, NULL }
96 };
97
98 static void getsecret FUNCTION((secret, promptextra, retype), char *secret AND char *promptextra AND int flags)
99 {
100   fprintf(stderr, "Enter %ssecret pass phrase: ", promptextra);
101   if (!opiereadpass(secret, OPIE_SECRET_MAX, 0)) {
102     fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra);
103     exit(1);
104   }
105   if (secret[0] && (flags & 1)) {
106     char verify[OPIE_SECRET_MAX + 1];
107
108     fprintf(stderr, "Again %ssecret pass phrase: ", promptextra);
109     if (!opiereadpass(verify, OPIE_SECRET_MAX, 0)) {
110       fprintf(stderr, "Error reading %ssecret pass phrase!\n", promptextra);
111       memset(verify, 0, sizeof(verify));
112       memset(secret, 0, OPIE_SECRET_MAX + 1);
113       exit(1);
114     }
115     if (verify[0] && strcmp(verify, secret)) {
116       fprintf(stderr, "They don't match. Try again.\n");
117       memset(verify, 0, sizeof(verify));
118       memset(secret, 0, OPIE_SECRET_MAX + 1);
119       exit(1);
120     }
121     memset(verify, 0, sizeof(verify));
122   }
123   if (!(flags & 2) && !aflag && opiepasscheck(secret)) {
124     memset(secret, 0, OPIE_SECRET_MAX + 1);
125     fprintf(stderr, "Secret pass phrases must be between %d and %d characters long.\n", OPIE_SECRET_MIN, OPIE_SECRET_MAX);
126     exit(1);
127   };
128 }
129
130 int main FUNCTION((argc, argv), int argc AND char *argv[])
131 {
132   /* variable declarations */
133   unsigned algorithm = MDX;     /* default algorithm per Makefile's MDX
134                                    symbol */
135   int keynum = 0;
136   int i;
137   int count = 1;
138   char secret[OPIE_SECRET_MAX + 1], newsecret[OPIE_SECRET_MAX + 1];
139   struct opie_otpkey key, newkey;
140   char *seed, newseed[OPIE_SEED_MAX + 1];
141   char response[OPIE_RESPONSE_MAX + 1];
142   char *slash;
143   int hex = 0;
144   int type = RESPONSE_STANDARD;
145   int force = 0;
146
147   if (slash = strchr(argv[0], '/'))
148     slash++;
149   else
150     slash = argv[0];
151
152   if (!strcmp(slash, "key") || strstr(slash, "md4"))
153     algorithm = 4;
154
155   if (strstr(slash, "md5"))
156     algorithm = 5;
157
158   if (strstr(slash, "sha"))
159     algorithm = 3;
160
161   while ((i = getopt(argc, argv, "fhvn:x45at:s")) != EOF) {
162     switch (i) {
163     case 'v':
164       opieversion();
165
166     case 'n':
167       count = atoi(optarg);
168       break;
169
170     case 'x':
171       hex = 1;
172       break;
173
174     case 'f':
175 #if INSECURE_OVERRIDE
176       force = 1;
177 #else /* INSECURE_OVERRIDE */
178       fprintf(stderr, "Sorry, but the -f option is not supported by this build of OPIE.\n");
179 #endif /* INSECURE_OVERRIDE */
180       break;
181
182     case '4':
183       /* use MD4 algorithm */
184       algorithm = 4;
185       break;
186
187     case '5':
188       /* use MD5 algorithm */
189       algorithm = 5;
190       break;
191
192     case 'a':
193       aflag = 1;
194       break;
195
196     case 't':
197       {
198         struct _rtrans *r;
199         for (r = rtrans; r->name && strcmp(r->name, optarg); r++);
200         if (!r->name) {
201           fprintf(stderr, "%s: %s: unknown response type.\n", argv[0], optarg);
202           exit(1);
203         }
204         type = r->type;
205       }
206       break;
207
208     case 's':
209       algorithm = 3;
210       break;
211
212     default:
213       usage(argv[0]);
214     }
215   }
216
217   if ((argc - optind) < 2)
218     usage(argv[0]);
219
220   fprintf(stderr, "Using the %s algorithm to compute response.\n", algnames[algorithm]);
221
222   /* get sequence number, which is next-to-last parameter */
223   keynum = atoi(argv[optind]);
224   if (keynum < 1) {
225     fprintf(stderr, "Sequence number %s is not positive.\n", argv[optind]);
226     exit(1);
227   }
228   /* get seed string, which is last parameter */
229   seed = argv[optind + 1];
230   {
231     i = strlen(seed);
232
233     if (i > OPIE_SEED_MAX) {
234       fprintf(stderr, "Seeds must be less than %d characters long.\n", OPIE_SEED_MAX);
235       exit(1);
236     }
237     if (i < OPIE_SEED_MIN) {
238       fprintf(stderr, "Seeds must be greater than %d characters long.\n", OPIE_SEED_MIN);
239       exit(1);
240     }
241   }
242
243   fprintf(stderr, "Reminder: Don't use opiekey from telnet or dial-in sessions.\n");
244
245   if (opieinsecure()) {
246     fprintf(stderr, "Sorry, but you don't seem to be on the console or a secure terminal.\n");
247 #if INSECURE_OVERRIDE
248     if (force)
249       fprintf(stderr, "Warning: Continuing could disclose your secret pass phrase to an attacker!\n");
250     else
251 #endif /* INSECURE_OVERRIDE */
252       exit(1);
253   }
254
255   if ((type == RESPONSE_INIT_HEX) || (type == RESPONSE_INIT_WORD)) {
256 #if RETYPE
257     getsecret(secret, "old ", 1);
258 #else /* RETYPE */
259     getsecret(secret, "old ", 0);
260 #endif /* RETYPE */
261     getsecret(newsecret, "new ", 1);
262     if (!newsecret[0])
263       strcpy(newsecret, secret);
264
265     if (opienewseed(strcpy(newseed, seed)) < 0) {
266       fprintf(stderr, "Error updating seed.\n");
267       goto error;
268     }
269
270     if (opiekeycrunch(algorithm, &newkey, newseed, newsecret)) {
271       fprintf(stderr, "%s: key crunch failed (1)\n", argv[0]);
272       goto error;
273     }
274
275     for (i = 0; i < 499; i++)
276       opiehash(&newkey, algorithm);
277   } else
278 #if RETYPE
279     getsecret(secret, "", 1);
280 #else /* RETYPE */
281     getsecret(secret, "", 0);
282 #endif /* RETYPE */
283
284   /* Crunch seed and secret password into starting key normally */
285   if (opiekeycrunch(algorithm, &key, seed, secret)) {
286     fprintf(stderr, "%s: key crunch failed\n", argv[0]);
287     goto error;
288   }
289
290   for (i = 0; i <= (keynum - count); i++)
291     opiehash(&key, algorithm);
292
293   {
294     char buf[OPIE_SEED_MAX + 48 + 1];
295     char *c;
296
297     for (; i <= keynum; i++) {
298       if (count > 1)
299         printf("%d: %s", i, (type == RESPONSE_STANDARD) ? "" : "\n");
300       
301       switch(type) {
302       case RESPONSE_STANDARD:
303         if (hex)
304           opiebtoh(response, &key);
305         else
306           opiebtoe(response, &key);
307         break;
308       case RESPONSE_WORD:
309         strcpy(response, "word:");
310         strcat(response, opiebtoe(buf, &key));
311         break;
312       case RESPONSE_HEX:
313         strcpy(response, "hex:");
314         strcat(response, opiebtoh(buf, &key));
315         break;
316       case RESPONSE_INIT_HEX:
317       case RESPONSE_INIT_WORD:
318         if (type == RESPONSE_INIT_HEX) {
319           strcpy(response, "init-hex:");
320           strcat(response, opiebtoh(buf, &key));
321           sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed);
322           strcat(response, buf);
323           strcat(response, opiebtoh(buf, &newkey));
324         } else {
325           strcpy(response, "init-word:");
326           strcat(response, opiebtoe(buf, &key));
327           sprintf(buf, ":%s 499 %s:", algids[algorithm], newseed);
328           strcat(response, buf);
329           strcat(response, opiebtoe(buf, &newkey));
330         }
331         break;
332       }
333       puts(response);
334       opiehash(&key, algorithm);
335     }
336   }
337
338   memset(secret, 0, sizeof(secret));
339   memset(newsecret, 0, sizeof(newsecret));
340   return 0;
341
342 error:
343   memset(secret, 0, sizeof(secret));
344   memset(newsecret, 0, sizeof(newsecret));
345   return 1;
346 }