]> andersk Git - openssh.git/blob - ssh-keygen.c
e3337dd6405a88e1c3a44d604ccae6fb66cd790d
[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 <openssl/evp.h>
13 #include <openssl/pem.h>
14 #include <openssl/rsa.h>
15 #include <openssl/dsa.h>
16
17 #include "ssh.h"
18 #include "xmalloc.h"
19 #include "fingerprint.h"
20 #include "key.h"
21 #include "rsa.h"
22 #include "dsa.h"
23 #include "authfile.h"
24 #include "uuencode.h"
25
26 /* Number of bits in the RSA/DSA key.  This value can be changed on the command line. */
27 int bits = 1024;
28
29 /*
30  * Flag indicating that we just want to change the passphrase.  This can be
31  * set on the command line.
32  */
33 int change_passphrase = 0;
34
35 /*
36  * Flag indicating that we just want to change the comment.  This can be set
37  * on the command line.
38  */
39 int change_comment = 0;
40
41 int quiet = 0;
42
43 /* Flag indicating that we just want to see the key fingerprint */
44 int print_fingerprint = 0;
45
46 /* The identity file name, given on the command line or entered by the user. */
47 char identity_file[1024];
48 int have_identity = 0;
49
50 /* This is set to the passphrase if given on the command line. */
51 char *identity_passphrase = NULL;
52
53 /* This is set to the new passphrase if given on the command line. */
54 char *identity_new_passphrase = NULL;
55
56 /* This is set to the new comment if given on the command line. */
57 char *identity_comment = NULL;
58
59 /* Dump public key file in format used by real and the original SSH 2 */
60 int convert_to_ssh2 = 0;
61 int convert_from_ssh2 = 0;
62 int print_public = 0;
63 int dsa_mode = 0;
64
65 /* argv0 */
66 #ifdef HAVE___PROGNAME
67 extern char *__progname;
68 #else /* HAVE___PROGNAME */
69 static const char *__progname = "ssh-keygen";
70 #endif /* HAVE___PROGNAME */
71
72 char hostname[MAXHOSTNAMELEN];
73
74 void
75 ask_filename(struct passwd *pw, const char *prompt)
76 {
77         char buf[1024];
78         snprintf(identity_file, sizeof(identity_file), "%s/%s",
79                  pw->pw_dir, SSH_CLIENT_IDENTITY);
80         printf("%s (%s): ", prompt, identity_file);
81         fflush(stdout);
82         if (fgets(buf, sizeof(buf), stdin) == NULL)
83                 exit(1);
84         if (strchr(buf, '\n'))
85                 *strchr(buf, '\n') = 0;
86         if (strcmp(buf, "") != 0)
87                 strlcpy(identity_file, buf, sizeof(identity_file));
88         have_identity = 1;
89 }
90
91 int
92 try_load_key(char *filename, Key *k)
93 {
94         int success = 1;
95         if (!load_private_key(filename, "", k, NULL)) {
96                 char *pass = read_passphrase("Enter passphrase: ", 1);
97                 if (!load_private_key(filename, pass, k, NULL)) {
98                         success = 0;
99                 }
100                 memset(pass, 0, strlen(pass));
101                 xfree(pass);
102         }
103         return success;
104 }
105
106 #define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
107 #define SSH_COM_MAGIC_END   "---- END SSH2 PUBLIC KEY ----"
108
109 void
110 do_convert_to_ssh2(struct passwd *pw)
111 {
112         Key *k;
113         int len;
114         unsigned char *blob;
115         struct stat st;
116
117         if (!have_identity)
118                 ask_filename(pw, "Enter file in which the key is");
119         if (stat(identity_file, &st) < 0) {
120                 perror(identity_file);
121                 exit(1);
122         }
123         k = key_new(KEY_DSA);
124         if (!try_load_key(identity_file, k)) {
125                 fprintf(stderr, "load failed\n");
126                 exit(1);
127         }
128         dsa_make_key_blob(k, &blob, &len);
129         fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
130         fprintf(stdout,
131             "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
132             BN_num_bits(k->dsa->p),
133             pw->pw_name, hostname);
134         dump_base64(stdout, blob, len);
135         fprintf(stdout, SSH_COM_MAGIC_END "\n");
136         key_free(k);
137         xfree(blob);
138         exit(0);
139 }
140
141 void
142 do_convert_from_ssh2(struct passwd *pw)
143 {
144         Key *k;
145         int blen;
146         char line[1024], *p;
147         char blob[8096];
148         char encoded[8096];
149         struct stat st;
150         FILE *fp;
151
152         if (!have_identity)
153                 ask_filename(pw, "Enter file in which the key is");
154         if (stat(identity_file, &st) < 0) {
155                 perror(identity_file);
156                 exit(1);
157         }
158         fp = fopen(identity_file, "r");
159         if (fp == NULL) {
160                 perror(identity_file);
161                 exit(1);
162         }
163         encoded[0] = '\0';
164         while (fgets(line, sizeof(line), fp)) {
165                 if (strncmp(line, "----", 4) == 0 ||
166                     strstr(line, ": ") != NULL) {
167                         fprintf(stderr, "ignore: %s", line);
168                         continue;
169                 }
170                 if (!(p = strchr(line, '\n'))) {
171                         fprintf(stderr, "input line too long.\n");
172                         exit(1);
173                 }
174                 *p = '\0';
175                 strlcat(encoded, line, sizeof(encoded));
176         }
177         blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
178         if (blen < 0) {
179                 fprintf(stderr, "uudecode failed.\n");
180                 exit(1);
181         }
182         k = dsa_key_from_blob(blob, blen);
183         if (!key_write(k, stdout))
184                 fprintf(stderr, "key_write failed");
185         key_free(k);
186         fprintf(stdout, "\n");
187         fclose(fp);
188         exit(0);
189 }
190
191 void
192 do_print_public(struct passwd *pw)
193 {
194         Key *k;
195         int len;
196         unsigned char *blob;
197         struct stat st;
198
199         if (!have_identity)
200                 ask_filename(pw, "Enter file in which the key is");
201         if (stat(identity_file, &st) < 0) {
202                 perror(identity_file);
203                 exit(1);
204         }
205         k = key_new(KEY_DSA);
206         if (!try_load_key(identity_file, k)) {
207                 fprintf(stderr, "load failed\n");
208                 exit(1);
209         }
210         dsa_make_key_blob(k, &blob, &len);
211         if (!key_write(k, stdout))
212                 fprintf(stderr, "key_write failed");
213         key_free(k);
214         xfree(blob);
215         fprintf(stdout, "\n");
216         exit(0);
217 }
218
219 void
220 do_fingerprint(struct passwd *pw)
221 {
222         FILE *f;
223         BIGNUM *e, *n;
224         Key *public;
225         char *comment = NULL, *cp, *ep, line[16*1024];
226         int i, skip = 0, num = 1, invalid = 1;
227         unsigned int ignore;
228         struct stat st;
229
230         if (!have_identity)
231                 ask_filename(pw, "Enter file in which the key is");
232         if (stat(identity_file, &st) < 0) {
233                 perror(identity_file);
234                 exit(1);
235         }
236         public = key_new(KEY_RSA);
237         if (load_public_key(identity_file, public, &comment)) {
238                 printf("%d %s %s\n", BN_num_bits(public->rsa->n),
239                     key_fingerprint(public), comment);
240                 key_free(public);
241                 exit(0);
242         }
243         key_free(public);
244
245         /* XXX */
246         f = fopen(identity_file, "r");
247         if (f != NULL) {
248                 n = BN_new();
249                 e = BN_new();
250                 while (fgets(line, sizeof(line), f)) {
251                         i = strlen(line) - 1;
252                         if (line[i] != '\n') {
253                                 error("line %d too long: %.40s...", num, line);
254                                 skip = 1;
255                                 continue;
256                         }
257                         num++;
258                         if (skip) {
259                                 skip = 0;
260                                 continue;
261                         }
262                         line[i] = '\0';
263
264                         /* Skip leading whitespace, empty and comment lines. */
265                         for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
266                                 ;
267                         if (!*cp || *cp == '\n' || *cp == '#')
268                                 continue ;
269                         i = strtol(cp, &ep, 10);
270                         if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
271                                 int quoted = 0;
272                                 comment = cp;
273                                 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
274                                         if (*cp == '\\' && cp[1] == '"')
275                                                 cp++;   /* Skip both */
276                                         else if (*cp == '"')
277                                                 quoted = !quoted;
278                                 }
279                                 if (!*cp)
280                                         continue;
281                                 *cp++ = '\0';
282                         }
283                         ep = cp;
284                         if (auth_rsa_read_key(&cp, &ignore, e, n)) {
285                                 invalid = 0;
286                                 comment = *cp ? cp : comment;
287                                 printf("%d %s %s\n", BN_num_bits(n),
288                                     fingerprint(e, n),
289                                     comment ? comment : "no comment");
290                         }
291                 }
292                 BN_free(e);
293                 BN_free(n);
294                 fclose(f);
295         }
296         if (invalid) {
297                 printf("%s is not a valid key file.\n", identity_file);
298                 exit(1);
299         }
300         exit(0);
301 }
302
303 /*
304  * Perform changing a passphrase.  The argument is the passwd structure
305  * for the current user.
306  */
307 void
308 do_change_passphrase(struct passwd *pw)
309 {
310         char *comment;
311         char *old_passphrase, *passphrase1, *passphrase2;
312         struct stat st;
313         Key *private;
314         Key *public;
315         int type = dsa_mode ? KEY_DSA : KEY_RSA;
316
317         if (!have_identity)
318                 ask_filename(pw, "Enter file in which the key is");
319         if (stat(identity_file, &st) < 0) {
320                 perror(identity_file);
321                 exit(1);
322         }
323
324         if (type == KEY_RSA) {
325                 /* XXX this works currently only for RSA */
326                 public = key_new(type);
327                 if (!load_public_key(identity_file, public, NULL)) {
328                         printf("%s is not a valid key file.\n", identity_file);
329                         exit(1);
330                 }
331                 /* Clear the public key since we are just about to load the whole file. */
332                 key_free(public);
333         }
334
335         /* Try to load the file with empty passphrase. */
336         private = key_new(type);
337         if (!load_private_key(identity_file, "", private, &comment)) {
338                 if (identity_passphrase)
339                         old_passphrase = xstrdup(identity_passphrase);
340                 else
341                         old_passphrase = read_passphrase("Enter old passphrase: ", 1);
342                 if (!load_private_key(identity_file, old_passphrase, private, &comment)) {
343                         memset(old_passphrase, 0, strlen(old_passphrase));
344                         xfree(old_passphrase);
345                         printf("Bad passphrase.\n");
346                         exit(1);
347                 }
348                 memset(old_passphrase, 0, strlen(old_passphrase));
349                 xfree(old_passphrase);
350         }
351         printf("Key has comment '%s'\n", comment);
352
353         /* Ask the new passphrase (twice). */
354         if (identity_new_passphrase) {
355                 passphrase1 = xstrdup(identity_new_passphrase);
356                 passphrase2 = NULL;
357         } else {
358                 passphrase1 =
359                         read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
360                 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
361
362                 /* Verify that they are the same. */
363                 if (strcmp(passphrase1, passphrase2) != 0) {
364                         memset(passphrase1, 0, strlen(passphrase1));
365                         memset(passphrase2, 0, strlen(passphrase2));
366                         xfree(passphrase1);
367                         xfree(passphrase2);
368                         printf("Pass phrases do not match.  Try again.\n");
369                         exit(1);
370                 }
371                 /* Destroy the other copy. */
372                 memset(passphrase2, 0, strlen(passphrase2));
373                 xfree(passphrase2);
374         }
375
376         /* Save the file using the new passphrase. */
377         if (!save_private_key(identity_file, passphrase1, private, comment)) {
378                 printf("Saving the key failed: %s: %s.\n",
379                        identity_file, strerror(errno));
380                 memset(passphrase1, 0, strlen(passphrase1));
381                 xfree(passphrase1);
382                 key_free(private);
383                 xfree(comment);
384                 exit(1);
385         }
386         /* Destroy the passphrase and the copy of the key in memory. */
387         memset(passphrase1, 0, strlen(passphrase1));
388         xfree(passphrase1);
389         key_free(private);               /* Destroys contents */
390         xfree(comment);
391
392         printf("Your identification has been saved with the new passphrase.\n");
393         exit(0);
394 }
395
396 /*
397  * Change the comment of a private key file.
398  */
399 void
400 do_change_comment(struct passwd *pw)
401 {
402         char new_comment[1024], *comment;
403         Key *private;
404         Key *public;
405         char *passphrase;
406         struct stat st;
407         FILE *f;
408
409         if (!have_identity)
410                 ask_filename(pw, "Enter file in which the key is");
411         if (stat(identity_file, &st) < 0) {
412                 perror(identity_file);
413                 exit(1);
414         }
415         /*
416          * Try to load the public key from the file the verify that it is
417          * readable and of the proper format.
418          */
419         public = key_new(KEY_RSA);
420         if (!load_public_key(identity_file, public, NULL)) {
421                 printf("%s is not a valid key file.\n", identity_file);
422                 exit(1);
423         }
424
425         private = key_new(KEY_RSA);
426         if (load_private_key(identity_file, "", private, &comment))
427                 passphrase = xstrdup("");
428         else {
429                 if (identity_passphrase)
430                         passphrase = xstrdup(identity_passphrase);
431                 else if (identity_new_passphrase)
432                         passphrase = xstrdup(identity_new_passphrase);
433                 else
434                         passphrase = read_passphrase("Enter passphrase: ", 1);
435                 /* Try to load using the passphrase. */
436                 if (!load_private_key(identity_file, passphrase, private, &comment)) {
437                         memset(passphrase, 0, strlen(passphrase));
438                         xfree(passphrase);
439                         printf("Bad passphrase.\n");
440                         exit(1);
441                 }
442         }
443         printf("Key now has comment '%s'\n", comment);
444
445         if (identity_comment) {
446                 strlcpy(new_comment, identity_comment, sizeof(new_comment));
447         } else {
448                 printf("Enter new comment: ");
449                 fflush(stdout);
450                 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
451                         memset(passphrase, 0, strlen(passphrase));
452                         key_free(private);
453                         exit(1);
454                 }
455                 if (strchr(new_comment, '\n'))
456                         *strchr(new_comment, '\n') = 0;
457         }
458
459         /* Save the file using the new passphrase. */
460         if (!save_private_key(identity_file, passphrase, private, new_comment)) {
461                 printf("Saving the key failed: %s: %s.\n",
462                        identity_file, strerror(errno));
463                 memset(passphrase, 0, strlen(passphrase));
464                 xfree(passphrase);
465                 key_free(private);
466                 xfree(comment);
467                 exit(1);
468         }
469         memset(passphrase, 0, strlen(passphrase));
470         xfree(passphrase);
471         key_free(private);
472
473         strlcat(identity_file, ".pub", sizeof(identity_file));
474         f = fopen(identity_file, "w");
475         if (!f) {
476                 printf("Could not save your public key in %s\n", identity_file);
477                 exit(1);
478         }
479         if (!key_write(public, f))
480                 fprintf(stderr, "write key failed");
481         key_free(public);
482         fprintf(f, " %s\n", new_comment);
483         fclose(f);
484
485         xfree(comment);
486
487         printf("The comment in your key file has been changed.\n");
488         exit(0);
489 }
490
491 void
492 usage(void)
493 {
494         printf("ssh-keygen version %s\n", SSH_VERSION);
495         printf("Usage: %s [-b bits] [-c] [-d] [-f file] [-l] [-p] [-q] [-x] [-y] [-C comment] [-N new-pass] [-P pass] [-X]\n", __progname);
496         exit(1);
497 }
498
499 /*
500  * Main program for key management.
501  */
502 int
503 main(int ac, char **av)
504 {
505         char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
506         struct passwd *pw;
507         int opt;
508         struct stat st;
509         FILE *f;
510         Key *private;
511         Key *public;
512         extern int optind;
513         extern char *optarg;
514
515         OpenSSL_add_all_algorithms();
516
517         /* we need this for the home * directory.  */
518         pw = getpwuid(getuid());
519         if (!pw) {
520                 printf("You don't exist, go away!\n");
521                 exit(1);
522         }
523         if (gethostname(hostname, sizeof(hostname)) < 0) {
524                 perror("gethostname");
525                 exit(1);
526         }
527
528         while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) {
529                 switch (opt) {
530                 case 'b':
531                         bits = atoi(optarg);
532                         if (bits < 512 || bits > 32768) {
533                                 printf("Bits has bad value.\n");
534                                 exit(1);
535                         }
536                         break;
537
538                 case 'l':
539                         print_fingerprint = 1;
540                         break;
541
542                 case 'p':
543                         change_passphrase = 1;
544                         break;
545
546                 case 'c':
547                         change_comment = 1;
548                         break;
549
550                 case 'f':
551                         strlcpy(identity_file, optarg, sizeof(identity_file));
552                         have_identity = 1;
553                         break;
554
555                 case 'P':
556                         identity_passphrase = optarg;
557                         break;
558
559                 case 'N':
560                         identity_new_passphrase = optarg;
561                         break;
562
563                 case 'C':
564                         identity_comment = optarg;
565                         break;
566
567                 case 'q':
568                         quiet = 1;
569                         break;
570
571                 case 'R':
572                         if (rsa_alive() == 0)
573                                 exit(1);
574                         else
575                                 exit(0);
576                         break;
577
578                 case 'x':
579                         convert_to_ssh2 = 1;
580                         break;
581
582                 case 'X':
583                         convert_from_ssh2 = 1;
584                         break;
585
586                 case 'y':
587                         print_public = 1;
588                         break;
589
590                 case 'd':
591                         dsa_mode = 1;
592                         break;
593
594                 case '?':
595                 default:
596                         usage();
597                 }
598         }
599         if (optind < ac) {
600                 printf("Too many arguments.\n");
601                 usage();
602         }
603         if (change_passphrase && change_comment) {
604                 printf("Can only have one of -p and -c.\n");
605                 usage();
606         }
607         /* check if RSA support is needed and exists */
608         if (dsa_mode == 0 && rsa_alive() == 0) {
609                 fprintf(stderr,
610                         "%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
611                         __progname);
612                 exit(1);
613         }
614         if (print_fingerprint)
615                 do_fingerprint(pw);
616         if (change_passphrase)
617                 do_change_passphrase(pw);
618         if (change_comment)
619                 do_change_comment(pw);
620         if (convert_to_ssh2)
621                 do_convert_to_ssh2(pw);
622         if (convert_from_ssh2)
623                 do_convert_from_ssh2(pw);
624         if (print_public)
625                 do_print_public(pw);
626
627         arc4random_stir();
628
629         if (dsa_mode != 0) {
630                 if (!quiet)
631                         printf("Generating DSA parameter and key.\n");
632                 public = private = dsa_generate_key(bits);
633                 if (private == NULL) {
634                         fprintf(stderr, "dsa_generate_keys failed");
635                         exit(1);
636                 }
637         } else {
638                 if (quiet)
639                         rsa_set_verbose(0);
640                 /* Generate the rsa key pair. */
641                 public = key_new(KEY_RSA);
642                 private = key_new(KEY_RSA);
643                 rsa_generate_key(private->rsa, public->rsa, bits);
644         }
645
646         if (!have_identity)
647                 ask_filename(pw, "Enter file in which to save the key");
648
649         /* Create ~/.ssh directory if it doesn\'t already exist. */
650         snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR);
651         if (strstr(identity_file, dotsshdir) != NULL &&
652             stat(dotsshdir, &st) < 0) {
653                 if (mkdir(dotsshdir, 0755) < 0)
654                         error("Could not create directory '%s'.", dotsshdir);
655                 else if (!quiet)
656                         printf("Created directory '%s'.\n", dotsshdir);
657         }
658         /* If the file already exists, ask the user to confirm. */
659         if (stat(identity_file, &st) >= 0) {
660                 char yesno[3];
661                 printf("%s already exists.\n", identity_file);
662                 printf("Overwrite (y/n)? ");
663                 fflush(stdout);
664                 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
665                         exit(1);
666                 if (yesno[0] != 'y' && yesno[0] != 'Y')
667                         exit(1);
668         }
669         /* Ask for a passphrase (twice). */
670         if (identity_passphrase)
671                 passphrase1 = xstrdup(identity_passphrase);
672         else if (identity_new_passphrase)
673                 passphrase1 = xstrdup(identity_new_passphrase);
674         else {
675 passphrase_again:
676                 passphrase1 =
677                         read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
678                 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
679                 if (strcmp(passphrase1, passphrase2) != 0) {
680                         /* The passphrases do not match.  Clear them and retry. */
681                         memset(passphrase1, 0, strlen(passphrase1));
682                         memset(passphrase2, 0, strlen(passphrase2));
683                         xfree(passphrase1);
684                         xfree(passphrase2);
685                         printf("Passphrases do not match.  Try again.\n");
686                         goto passphrase_again;
687                 }
688                 /* Clear the other copy of the passphrase. */
689                 memset(passphrase2, 0, strlen(passphrase2));
690                 xfree(passphrase2);
691         }
692
693         if (identity_comment) {
694                 strlcpy(comment, identity_comment, sizeof(comment));
695         } else {
696                 /* Create default commend field for the passphrase. */
697                 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
698         }
699
700         /* Save the key with the given passphrase and comment. */
701         if (!save_private_key(identity_file, passphrase1, private, comment)) {
702                 printf("Saving the key failed: %s: %s.\n",
703                     identity_file, strerror(errno));
704                 memset(passphrase1, 0, strlen(passphrase1));
705                 xfree(passphrase1);
706                 exit(1);
707         }
708         /* Clear the passphrase. */
709         memset(passphrase1, 0, strlen(passphrase1));
710         xfree(passphrase1);
711
712         /* Clear the private key and the random number generator. */
713         if (private != public) {
714                 key_free(private);
715         }
716         arc4random_stir();
717
718         if (!quiet)
719                 printf("Your identification has been saved in %s.\n", identity_file);
720
721         strlcat(identity_file, ".pub", sizeof(identity_file));
722         f = fopen(identity_file, "w");
723         if (!f) {
724                 printf("Could not save your public key in %s\n", identity_file);
725                 exit(1);
726         }
727         if (!key_write(public, f))
728                 fprintf(stderr, "write key failed");
729         fprintf(f, " %s\n", comment);
730         fclose(f);
731
732         if (!quiet) {
733                 printf("Your public key has been saved in %s.\n",
734                     identity_file);
735                 printf("The key fingerprint is:\n");
736                 printf("%s %s\n", key_fingerprint(public), comment);
737         }
738
739         key_free(public);
740         exit(0);
741 }
This page took 0.083378 seconds and 3 git commands to generate.