]> andersk Git - openssh.git/blob - ssh-keygen.c
- OpenBSD CVS updates.
[openssh.git] / ssh-keygen.c
1 /*
2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  * Created: Mon Mar 27 02:26:40 1995 ylo
6  * Identity and host key generation and maintenance.
7  */
8
9 #include "includes.h"
10 RCSID("$Id$");
11
12 #include "rsa.h"
13 #include "ssh.h"
14 #include "xmalloc.h"
15 #include "fingerprint.h"
16
17 /* Generated private key. */
18 RSA *private_key;
19
20 /* Generated public key. */
21 RSA *public_key;
22
23 /* Number of bits in the RSA key.  This value can be changed on the command line. */
24 int bits = 1024;
25
26 /*
27  * Flag indicating that we just want to change the passphrase.  This can be
28  * set on the command line.
29  */
30 int change_passphrase = 0;
31
32 /*
33  * Flag indicating that we just want to change the comment.  This can be set
34  * on the command line.
35  */
36 int change_comment = 0;
37
38 int quiet = 0;
39
40 /* Flag indicating that we just want to see the key fingerprint */
41 int print_fingerprint = 0;
42
43 /* The identity file name, given on the command line or entered by the user. */
44 char identity_file[1024];
45 int have_identity = 0;
46
47 /* This is set to the passphrase if given on the command line. */
48 char *identity_passphrase = NULL;
49
50 /* This is set to the new passphrase if given on the command line. */
51 char *identity_new_passphrase = NULL;
52
53 /* This is set to the new comment if given on the command line. */
54 char *identity_comment = NULL;
55
56 /* argv0 */
57 #ifdef HAVE___PROGNAME
58 extern char *__progname;
59 #else /* HAVE___PROGNAME */
60 const char *__progname = "ssh-keygen";
61 #endif /* HAVE___PROGNAME */
62
63 void
64 ask_filename(struct passwd *pw, const char *prompt)
65 {
66         char buf[1024];
67         snprintf(identity_file, sizeof(identity_file), "%s/%s",
68                  pw->pw_dir, SSH_CLIENT_IDENTITY);
69         printf("%s (%s): ", prompt, identity_file);
70         fflush(stdout);
71         if (fgets(buf, sizeof(buf), stdin) == NULL)
72                 exit(1);
73         if (strchr(buf, '\n'))
74                 *strchr(buf, '\n') = 0;
75         if (strcmp(buf, "") != 0)
76                 strlcpy(identity_file, buf, sizeof(identity_file));
77         have_identity = 1;
78 }
79
80 void
81 do_fingerprint(struct passwd *pw)
82 {
83         FILE *f;
84         BIGNUM *e, *n;
85         RSA *public_key;
86         char *comment = NULL, *cp, *ep, line[16*1024];
87         int i, skip = 0, num = 1, invalid = 1;
88         unsigned int ignore;
89         struct stat st;
90
91         if (!have_identity)
92                 ask_filename(pw, "Enter file in which the key is");
93         if (stat(identity_file, &st) < 0) {
94                 perror(identity_file);
95                 exit(1);
96         }
97         
98         public_key = RSA_new();
99         if (load_public_key(identity_file, public_key, &comment)) {
100                 printf("%d %s %s\n", BN_num_bits(public_key->n),
101                     fingerprint(public_key->e, public_key->n),
102                     comment);
103                 RSA_free(public_key);
104                 exit(0);
105         }
106         RSA_free(public_key);
107
108         f = fopen(identity_file, "r");
109         if (f != NULL) {
110                 n = BN_new();
111                 e = BN_new();
112                 while (fgets(line, sizeof(line), f)) {
113                         i = strlen(line) - 1;
114                         if (line[i] != '\n') {
115                                 error("line %d too long: %.40s...", num, line);
116                                 skip = 1;
117                                 continue;
118                         }
119                         num++;
120                         if (skip) {
121                                 skip = 0;
122                                 continue;
123                         }
124                         line[i] = '\0';
125
126                         /* Skip leading whitespace, empty and comment lines. */
127                         for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
128                                 ;
129                         if (!*cp || *cp == '\n' || *cp == '#')
130                                 continue ;
131                         i = strtol(cp, &ep, 10);
132                         if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
133                                 int quoted = 0;
134                                 comment = cp;
135                                 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
136                                         if (*cp == '\\' && cp[1] == '"')
137                                                 cp++;   /* Skip both */
138                                         else if (*cp == '"')
139                                                 quoted = !quoted;
140                                 }
141                                 if (!*cp)
142                                         continue;
143                                 *cp++ = '\0';
144                         }
145                         ep = cp;
146                         if (auth_rsa_read_key(&cp, &ignore, e, n)) {
147                                 invalid = 0;
148                                 comment = *cp ? cp : comment;
149                                 printf("%d %s %s\n", BN_num_bits(n),
150                                     fingerprint(e, n),
151                                     comment ? comment : "no comment");
152                         }
153                 }
154                 BN_free(e);
155                 BN_free(n);
156                 fclose(f);
157         }
158         if (invalid) {
159                 printf("%s is not a valid key file.\n", identity_file);
160                 exit(1);
161         }
162         exit(0);
163 }
164
165 /*
166  * Perform changing a passphrase.  The argument is the passwd structure
167  * for the current user.
168  */
169 void
170 do_change_passphrase(struct passwd *pw)
171 {
172         char *comment;
173         char *old_passphrase, *passphrase1, *passphrase2;
174         struct stat st;
175         RSA *private_key;
176
177         if (!have_identity)
178                 ask_filename(pw, "Enter file in which the key is");
179         if (stat(identity_file, &st) < 0) {
180                 perror(identity_file);
181                 exit(1);
182         }
183         public_key = RSA_new();
184         if (!load_public_key(identity_file, public_key, NULL)) {
185                 printf("%s is not a valid key file.\n", identity_file);
186                 exit(1);
187         }
188         /* Clear the public key since we are just about to load the whole file. */
189         RSA_free(public_key);
190
191         /* Try to load the file with empty passphrase. */
192         private_key = RSA_new();
193         if (!load_private_key(identity_file, "", private_key, &comment)) {
194                 if (identity_passphrase)
195                         old_passphrase = xstrdup(identity_passphrase);
196                 else
197                         old_passphrase = read_passphrase("Enter old passphrase: ", 1);
198                 if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) {
199                         memset(old_passphrase, 0, strlen(old_passphrase));
200                         xfree(old_passphrase);
201                         printf("Bad passphrase.\n");
202                         exit(1);
203                 }
204                 memset(old_passphrase, 0, strlen(old_passphrase));
205                 xfree(old_passphrase);
206         }
207         printf("Key has comment '%s'\n", comment);
208
209         /* Ask the new passphrase (twice). */
210         if (identity_new_passphrase) {
211                 passphrase1 = xstrdup(identity_new_passphrase);
212                 passphrase2 = NULL;
213         } else {
214                 passphrase1 =
215                         read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
216                 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
217
218                 /* Verify that they are the same. */
219                 if (strcmp(passphrase1, passphrase2) != 0) {
220                         memset(passphrase1, 0, strlen(passphrase1));
221                         memset(passphrase2, 0, strlen(passphrase2));
222                         xfree(passphrase1);
223                         xfree(passphrase2);
224                         printf("Pass phrases do not match.  Try again.\n");
225                         exit(1);
226                 }
227                 /* Destroy the other copy. */
228                 memset(passphrase2, 0, strlen(passphrase2));
229                 xfree(passphrase2);
230         }
231
232         /* Save the file using the new passphrase. */
233         if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
234                 printf("Saving the key failed: %s: %s.\n",
235                        identity_file, strerror(errno));
236                 memset(passphrase1, 0, strlen(passphrase1));
237                 xfree(passphrase1);
238                 RSA_free(private_key);
239                 xfree(comment);
240                 exit(1);
241         }
242         /* Destroy the passphrase and the copy of the key in memory. */
243         memset(passphrase1, 0, strlen(passphrase1));
244         xfree(passphrase1);
245         RSA_free(private_key);  /* Destroys contents */
246         xfree(comment);
247
248         printf("Your identification has been saved with the new passphrase.\n");
249         exit(0);
250 }
251
252 /*
253  * Change the comment of a private key file.
254  */
255 void
256 do_change_comment(struct passwd *pw)
257 {
258         char new_comment[1024], *comment;
259         RSA *private_key;
260         char *passphrase;
261         struct stat st;
262         FILE *f;
263         char *tmpbuf;
264
265         if (!have_identity)
266                 ask_filename(pw, "Enter file in which the key is");
267         if (stat(identity_file, &st) < 0) {
268                 perror(identity_file);
269                 exit(1);
270         }
271         /*
272          * Try to load the public key from the file the verify that it is
273          * readable and of the proper format.
274          */
275         public_key = RSA_new();
276         if (!load_public_key(identity_file, public_key, NULL)) {
277                 printf("%s is not a valid key file.\n", identity_file);
278                 exit(1);
279         }
280         private_key = RSA_new();
281
282         if (load_private_key(identity_file, "", private_key, &comment))
283                 passphrase = xstrdup("");
284         else {
285                 if (identity_passphrase)
286                         passphrase = xstrdup(identity_passphrase);
287                 else if (identity_new_passphrase)
288                         passphrase = xstrdup(identity_new_passphrase);
289                 else
290                         passphrase = read_passphrase("Enter passphrase: ", 1);
291                 /* Try to load using the passphrase. */
292                 if (!load_private_key(identity_file, passphrase, private_key, &comment)) {
293                         memset(passphrase, 0, strlen(passphrase));
294                         xfree(passphrase);
295                         printf("Bad passphrase.\n");
296                         exit(1);
297                 }
298         }
299         printf("Key now has comment '%s'\n", comment);
300
301         if (identity_comment) {
302                 strlcpy(new_comment, identity_comment, sizeof(new_comment));
303         } else {
304                 printf("Enter new comment: ");
305                 fflush(stdout);
306                 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
307                         memset(passphrase, 0, strlen(passphrase));
308                         RSA_free(private_key);
309                         exit(1);
310                 }
311                 if (strchr(new_comment, '\n'))
312                         *strchr(new_comment, '\n') = 0;
313         }
314
315         /* Save the file using the new passphrase. */
316         if (!save_private_key(identity_file, passphrase, private_key, new_comment)) {
317                 printf("Saving the key failed: %s: %s.\n",
318                        identity_file, strerror(errno));
319                 memset(passphrase, 0, strlen(passphrase));
320                 xfree(passphrase);
321                 RSA_free(private_key);
322                 xfree(comment);
323                 exit(1);
324         }
325         memset(passphrase, 0, strlen(passphrase));
326         xfree(passphrase);
327         RSA_free(private_key);
328
329         strlcat(identity_file, ".pub", sizeof(identity_file));
330         f = fopen(identity_file, "w");
331         if (!f) {
332                 printf("Could not save your public key in %s\n", identity_file);
333                 exit(1);
334         }
335         fprintf(f, "%d ", BN_num_bits(public_key->n));
336         tmpbuf = BN_bn2dec(public_key->e);
337         fprintf(f, "%s ", tmpbuf);
338         free(tmpbuf);
339         tmpbuf = BN_bn2dec(public_key->n);
340         fprintf(f, "%s %s\n", tmpbuf, new_comment);
341         free(tmpbuf);
342         fclose(f);
343
344         xfree(comment);
345
346         printf("The comment in your key file has been changed.\n");
347         exit(0);
348 }
349
350 void
351 usage(void)
352 {
353         printf("ssh-keygen version %s\n", SSH_VERSION);
354         printf("Usage: %s [-b bits] [-p] [-c] [-l] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname);
355         exit(1);
356 }
357
358 /*
359  * Main program for key management.
360  */
361 int
362 main(int ac, char **av)
363 {
364         char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
365         struct passwd *pw;
366         char *tmpbuf;
367         int opt;
368         struct stat st;
369         FILE *f;
370         char hostname[MAXHOSTNAMELEN];
371         extern int optind;
372         extern char *optarg;
373
374         /* check if RSA support exists */
375         if (rsa_alive() == 0) {
376                 fprintf(stderr,
377                         "%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
378                         __progname);
379                 exit(1);
380         }
381         /* we need this for the home * directory.  */
382         pw = getpwuid(getuid());
383         if (!pw) {
384                 printf("You don't exist, go away!\n");
385                 exit(1);
386         }
387
388         while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) {
389                 switch (opt) {
390                 case 'b':
391                         bits = atoi(optarg);
392                         if (bits < 512 || bits > 32768) {
393                                 printf("Bits has bad value.\n");
394                                 exit(1);
395                         }
396                         break;
397
398                 case 'l':
399                         print_fingerprint = 1;
400                         break;
401
402                 case 'p':
403                         change_passphrase = 1;
404                         break;
405
406                 case 'c':
407                         change_comment = 1;
408                         break;
409
410                 case 'f':
411                         strlcpy(identity_file, optarg, sizeof(identity_file));
412                         have_identity = 1;
413                         break;
414
415                 case 'P':
416                         identity_passphrase = optarg;
417                         break;
418
419                 case 'N':
420                         identity_new_passphrase = optarg;
421                         break;
422
423                 case 'C':
424                         identity_comment = optarg;
425                         break;
426
427                 case 'q':
428                         quiet = 1;
429                         break;
430
431                 case '?':
432                 default:
433                         usage();
434                 }
435         }
436         if (optind < ac) {
437                 printf("Too many arguments.\n");
438                 usage();
439         }
440         if (change_passphrase && change_comment) {
441                 printf("Can only have one of -p and -c.\n");
442                 usage();
443         }
444         if (print_fingerprint)
445                 do_fingerprint(pw);
446         if (change_passphrase)
447                 do_change_passphrase(pw);
448         if (change_comment)
449                 do_change_comment(pw);
450
451         arc4random_stir();
452
453         if (quiet)
454                 rsa_set_verbose(0);
455
456         /* Generate the rsa key pair. */
457         private_key = RSA_new();
458         public_key = RSA_new();
459         rsa_generate_key(private_key, public_key, bits);
460
461         if (!have_identity)
462                 ask_filename(pw, "Enter file in which to save the key");
463
464         /* Create ~/.ssh directory if it doesn\'t already exist. */
465         snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
466         if (strstr(identity_file, dotsshdir) != NULL &&
467             stat(dotsshdir, &st) < 0) {
468                 if (mkdir(dotsshdir, 0755) < 0)
469                         error("Could not create directory '%s'.", dotsshdir);
470                 else if (!quiet)
471                         printf("Created directory '%s'.\n", dotsshdir);
472         }
473         /* If the file already exists, ask the user to confirm. */
474         if (stat(identity_file, &st) >= 0) {
475                 char yesno[3];
476                 printf("%s already exists.\n", identity_file);
477                 printf("Overwrite (y/n)? ");
478                 fflush(stdout);
479                 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
480                         exit(1);
481                 if (yesno[0] != 'y' && yesno[0] != 'Y')
482                         exit(1);
483         }
484         /* Ask for a passphrase (twice). */
485         if (identity_passphrase)
486                 passphrase1 = xstrdup(identity_passphrase);
487         else if (identity_new_passphrase)
488                 passphrase1 = xstrdup(identity_new_passphrase);
489         else {
490 passphrase_again:
491                 passphrase1 =
492                         read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
493                 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
494                 if (strcmp(passphrase1, passphrase2) != 0) {
495                         /* The passphrases do not match.  Clear them and retry. */
496                         memset(passphrase1, 0, strlen(passphrase1));
497                         memset(passphrase2, 0, strlen(passphrase2));
498                         xfree(passphrase1);
499                         xfree(passphrase2);
500                         printf("Passphrases do not match.  Try again.\n");
501                         goto passphrase_again;
502                 }
503                 /* Clear the other copy of the passphrase. */
504                 memset(passphrase2, 0, strlen(passphrase2));
505                 xfree(passphrase2);
506         }
507
508         if (identity_comment) {
509                 strlcpy(comment, identity_comment, sizeof(comment));
510         } else {
511                 /* Create default commend field for the passphrase. */
512                 if (gethostname(hostname, sizeof(hostname)) < 0) {
513                         perror("gethostname");
514                         exit(1);
515                 }
516                 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
517         }
518
519         /* Save the key with the given passphrase and comment. */
520         if (!save_private_key(identity_file, passphrase1, private_key, comment)) {
521                 printf("Saving the key failed: %s: %s.\n",
522                        identity_file, strerror(errno));
523                 memset(passphrase1, 0, strlen(passphrase1));
524                 xfree(passphrase1);
525                 exit(1);
526         }
527         /* Clear the passphrase. */
528         memset(passphrase1, 0, strlen(passphrase1));
529         xfree(passphrase1);
530
531         /* Clear the private key and the random number generator. */
532         RSA_free(private_key);
533         arc4random_stir();
534
535         if (!quiet)
536                 printf("Your identification has been saved in %s.\n", identity_file);
537
538         strlcat(identity_file, ".pub", sizeof(identity_file));
539         f = fopen(identity_file, "w");
540         if (!f) {
541                 printf("Could not save your public key in %s\n", identity_file);
542                 exit(1);
543         }
544         fprintf(f, "%d ", BN_num_bits(public_key->n));
545         tmpbuf = BN_bn2dec(public_key->e);
546         fprintf(f, "%s ", tmpbuf);
547         free(tmpbuf);
548         tmpbuf = BN_bn2dec(public_key->n);
549         fprintf(f, "%s %s\n", tmpbuf, comment);
550         free(tmpbuf);
551         fclose(f);
552
553         if (!quiet) {
554                 printf("Your public key has been saved in %s.\n", identity_file);
555                 printf("The key fingerprint is:\n");
556                 printf("%d %s %s\n", BN_num_bits(public_key->n),
557                        fingerprint(public_key->e, public_key->n),
558                        comment);
559         }
560         exit(0);
561 }
This page took 0.086787 seconds and 5 git commands to generate.