]> andersk Git - openssh.git/blob - ssh-keygen.c
- markus@cvs.openbsd.org 2001/03/26 08:07:09
[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  * Identity and host key generation and maintenance.
6  *
7  * As far as I am concerned, the code I have written for this software
8  * can be used freely for any purpose.  Any derived versions of this
9  * software must be clearly marked as such, and if the derived work is
10  * incompatible with the protocol description in the RFC file, it must be
11  * called by a name other than "ssh" or "Secure Shell".
12  */
13
14 #include "includes.h"
15 RCSID("$OpenBSD: ssh-keygen.c,v 1.52 2001/03/26 08:07:09 markus Exp $");
16
17 #include <openssl/evp.h>
18 #include <openssl/pem.h>
19
20 #include "xmalloc.h"
21 #include "key.h"
22 #include "authfile.h"
23 #include "uuencode.h"
24 #include "buffer.h"
25 #include "bufaux.h"
26 #include "pathnames.h"
27 #include "log.h"
28 #include "readpass.h"
29
30 /* Number of bits in the RSA/DSA key.  This value can be changed on the command line. */
31 int bits = 1024;
32
33 /*
34  * Flag indicating that we just want to change the passphrase.  This can be
35  * set on the command line.
36  */
37 int change_passphrase = 0;
38
39 /*
40  * Flag indicating that we just want to change the comment.  This can be set
41  * on the command line.
42  */
43 int change_comment = 0;
44
45 int quiet = 0;
46
47 /* Flag indicating that we just want to see the key fingerprint */
48 int print_fingerprint = 0;
49 int print_bubblebabble = 0;
50
51 /* The identity file name, given on the command line or entered by the user. */
52 char identity_file[1024];
53 int have_identity = 0;
54
55 /* This is set to the passphrase if given on the command line. */
56 char *identity_passphrase = NULL;
57
58 /* This is set to the new passphrase if given on the command line. */
59 char *identity_new_passphrase = NULL;
60
61 /* This is set to the new comment if given on the command line. */
62 char *identity_comment = NULL;
63
64 /* Dump public key file in format used by real and the original SSH 2 */
65 int convert_to_ssh2 = 0;
66 int convert_from_ssh2 = 0;
67 int print_public = 0;
68
69 /* default to RSA for SSH-1 */
70 char *key_type_name = "rsa1";
71
72 /* argv0 */
73 #ifdef HAVE___PROGNAME
74 extern char *__progname;
75 #else
76 char *__progname;
77 #endif
78
79 char hostname[MAXHOSTNAMELEN];
80
81 void
82 ask_filename(struct passwd *pw, const char *prompt)
83 {
84         char buf[1024];
85         char *name = NULL;
86
87         switch (key_type_from_name(key_type_name)) {
88         case KEY_RSA1:
89                 name = _PATH_SSH_CLIENT_IDENTITY;
90                 break;
91         case KEY_DSA:
92                 name = _PATH_SSH_CLIENT_ID_DSA;
93                 break;
94         case KEY_RSA:
95                 name = _PATH_SSH_CLIENT_ID_RSA;
96                 break;
97         default:
98                 fprintf(stderr, "bad key type");
99                 exit(1);
100                 break;
101         }
102         snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
103         fprintf(stderr, "%s (%s): ", prompt, identity_file);
104         fflush(stderr);
105         if (fgets(buf, sizeof(buf), stdin) == NULL)
106                 exit(1);
107         if (strchr(buf, '\n'))
108                 *strchr(buf, '\n') = 0;
109         if (strcmp(buf, "") != 0)
110                 strlcpy(identity_file, buf, sizeof(identity_file));
111         have_identity = 1;
112 }
113
114 Key *
115 try_load_pem_key(char *filename)
116 {
117         char *pass;
118         Key *prv;
119
120         prv = key_load_private(filename, "", NULL);
121         if (prv == NULL) {
122                 pass = read_passphrase("Enter passphrase: ", 1);
123                 prv = key_load_private(filename, pass, NULL);
124                 memset(pass, 0, strlen(pass));
125                 xfree(pass);
126         }
127         return prv;
128 }
129
130 #define SSH_COM_PUBLIC_BEGIN            "---- BEGIN SSH2 PUBLIC KEY ----"
131 #define SSH_COM_PUBLIC_END              "---- END SSH2 PUBLIC KEY ----"
132 #define SSH_COM_PRIVATE_BEGIN           "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
133 #define SSH_COM_PRIVATE_KEY_MAGIC       0x3f6ff9eb
134
135 void
136 do_convert_to_ssh2(struct passwd *pw)
137 {
138         Key *prv;
139         int len;
140         u_char *blob;
141         struct stat st;
142
143         if (!have_identity)
144                 ask_filename(pw, "Enter file in which the key is");
145         if (stat(identity_file, &st) < 0) {
146                 perror(identity_file);
147                 exit(1);
148         }
149         prv = try_load_pem_key(identity_file);
150         if (prv == NULL) {
151                 fprintf(stderr, "load failed\n");
152                 exit(1);
153         }
154         key_to_blob(prv, &blob, &len);
155         fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
156         fprintf(stdout,
157             "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n",
158             key_size(prv), key_type(prv),
159             pw->pw_name, hostname);
160         dump_base64(stdout, blob, len);
161         fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
162         key_free(prv);
163         xfree(blob);
164         exit(0);
165 }
166
167 void
168 buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
169 {
170         int bits = buffer_get_int(b);
171         int bytes = (bits + 7) / 8;
172         if (buffer_len(b) < bytes)
173                 fatal("buffer_get_bignum_bits: input buffer too small");
174         BN_bin2bn((u_char *)buffer_ptr(b), bytes, value);
175         buffer_consume(b, bytes);
176 }
177
178 Key *
179 do_convert_private_ssh2_from_blob(char *blob, int blen)
180 {
181         Buffer b;
182         DSA *dsa;
183         Key *key = NULL;
184         int ignore, magic, rlen;
185         char *type, *cipher;
186
187         buffer_init(&b);
188         buffer_append(&b, blob, blen);
189
190         magic  = buffer_get_int(&b);
191         if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
192                 error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
193                 buffer_free(&b);
194                 return NULL;
195         }
196         ignore = buffer_get_int(&b);
197         type   = buffer_get_string(&b, NULL);
198         cipher = buffer_get_string(&b, NULL);
199         ignore = buffer_get_int(&b);
200         ignore = buffer_get_int(&b);
201         ignore = buffer_get_int(&b);
202         xfree(type);
203
204         if (strcmp(cipher, "none") != 0) {
205                 error("unsupported cipher %s", cipher);
206                 xfree(cipher);
207                 buffer_free(&b);
208                 return NULL;
209         }
210         xfree(cipher);
211
212         key = key_new(KEY_DSA);
213         dsa = key->dsa;
214         dsa->priv_key = BN_new();
215         if (dsa->priv_key == NULL) {
216                 error("alloc priv_key failed");
217                 key_free(key);
218                 return NULL;
219         }
220         buffer_get_bignum_bits(&b, dsa->p);
221         buffer_get_bignum_bits(&b, dsa->g);
222         buffer_get_bignum_bits(&b, dsa->q);
223         buffer_get_bignum_bits(&b, dsa->pub_key);
224         buffer_get_bignum_bits(&b, dsa->priv_key);
225         rlen = buffer_len(&b);
226         if(rlen != 0)
227                 error("do_convert_private_ssh2_from_blob: remaining bytes in key blob %d", rlen);
228         buffer_free(&b);
229         return key;
230 }
231
232 void
233 do_convert_from_ssh2(struct passwd *pw)
234 {
235         Key *k;
236         int blen;
237         char line[1024], *p;
238         char blob[8096];
239         char encoded[8096];
240         struct stat st;
241         int escaped = 0, private = 0, ok;
242         FILE *fp;
243
244         if (!have_identity)
245                 ask_filename(pw, "Enter file in which the key is");
246         if (stat(identity_file, &st) < 0) {
247                 perror(identity_file);
248                 exit(1);
249         }
250         fp = fopen(identity_file, "r");
251         if (fp == NULL) {
252                 perror(identity_file);
253                 exit(1);
254         }
255         encoded[0] = '\0';
256         while (fgets(line, sizeof(line), fp)) {
257                 if (!(p = strchr(line, '\n'))) {
258                         fprintf(stderr, "input line too long.\n");
259                         exit(1);
260                 }
261                 if (p > line && p[-1] == '\\')
262                         escaped++;
263                 if (strncmp(line, "----", 4) == 0 ||
264                     strstr(line, ": ") != NULL) {
265                         if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
266                                 private = 1;
267                         fprintf(stderr, "ignore: %s", line);
268                         continue;
269                 }
270                 if (escaped) {
271                         escaped--;
272                         fprintf(stderr, "escaped: %s", line);
273                         continue;
274                 }
275                 *p = '\0';
276                 strlcat(encoded, line, sizeof(encoded));
277         }
278         blen = uudecode(encoded, (u_char *)blob, sizeof(blob));
279         if (blen < 0) {
280                 fprintf(stderr, "uudecode failed.\n");
281                 exit(1);
282         }
283         k = private ?
284             do_convert_private_ssh2_from_blob(blob, blen) :
285             key_from_blob(blob, blen);
286         if (k == NULL) {
287                 fprintf(stderr, "decode blob failed.\n");
288                 exit(1);
289         }
290         ok = private ?
291             PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
292             key_write(k, stdout);
293         if (!ok) {
294                 fprintf(stderr, "key write failed");
295                 exit(1);
296         }
297         key_free(k);
298         fprintf(stdout, "\n");
299         fclose(fp);
300         exit(0);
301 }
302
303 void
304 do_print_public(struct passwd *pw)
305 {
306         Key *prv;
307         struct stat st;
308
309         if (!have_identity)
310                 ask_filename(pw, "Enter file in which the key is");
311         if (stat(identity_file, &st) < 0) {
312                 perror(identity_file);
313                 exit(1);
314         }
315         prv = try_load_pem_key(identity_file);
316         if (prv == NULL) {
317                 fprintf(stderr, "load failed\n");
318                 exit(1);
319         }
320         if (!key_write(prv, stdout))
321                 fprintf(stderr, "key_write failed");
322         key_free(prv);
323         fprintf(stdout, "\n");
324         exit(0);
325 }
326
327 void
328 do_fingerprint(struct passwd *pw)
329 {
330         FILE *f;
331         Key *public;
332         char *comment = NULL, *cp, *ep, line[16*1024], *fp;
333         int i, skip = 0, num = 1, invalid = 1, rep, fptype;
334         struct stat st;
335
336         fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
337         rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
338
339         if (!have_identity)
340                 ask_filename(pw, "Enter file in which the key is");
341         if (stat(identity_file, &st) < 0) {
342                 perror(identity_file);
343                 exit(1);
344         }
345         public = key_load_public(identity_file, &comment);
346         if (public != NULL) {
347                 fp = key_fingerprint(public, fptype, rep);
348                 printf("%d %s %s\n", key_size(public), fp, comment);
349                 key_free(public);
350                 xfree(comment);
351                 xfree(fp);
352                 exit(0);
353         }
354         if (comment)
355                 xfree(comment);
356
357         f = fopen(identity_file, "r");
358         if (f != NULL) {
359                 while (fgets(line, sizeof(line), f)) {
360                         i = strlen(line) - 1;
361                         if (line[i] != '\n') {
362                                 error("line %d too long: %.40s...", num, line);
363                                 skip = 1;
364                                 continue;
365                         }
366                         num++;
367                         if (skip) {
368                                 skip = 0;
369                                 continue;
370                         }
371                         line[i] = '\0';
372
373                         /* Skip leading whitespace, empty and comment lines. */
374                         for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
375                                 ;
376                         if (!*cp || *cp == '\n' || *cp == '#')
377                                 continue ;
378                         i = strtol(cp, &ep, 10);
379                         if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
380                                 int quoted = 0;
381                                 comment = cp;
382                                 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
383                                         if (*cp == '\\' && cp[1] == '"')
384                                                 cp++;   /* Skip both */
385                                         else if (*cp == '"')
386                                                 quoted = !quoted;
387                                 }
388                                 if (!*cp)
389                                         continue;
390                                 *cp++ = '\0';
391                         }
392                         ep = cp;
393                         public = key_new(KEY_RSA1);
394                         if (key_read(public, &cp) != 1) {
395                                 cp = ep;
396                                 key_free(public);
397                                 public = key_new(KEY_UNSPEC);
398                                 if (key_read(public, &cp) != 1) {
399                                         key_free(public);
400                                         continue;
401                                 }
402                         }
403                         comment = *cp ? cp : comment;
404                         fp = key_fingerprint(public, fptype, rep);
405                         printf("%d %s %s\n", key_size(public), fp,
406                             comment ? comment : "no comment");
407                         xfree(fp);
408                         key_free(public);
409                         invalid = 0;
410                 }
411                 fclose(f);
412         }
413         if (invalid) {
414                 printf("%s is not a valid key file.\n", identity_file);
415                 exit(1);
416         }
417         exit(0);
418 }
419
420 /*
421  * Perform changing a passphrase.  The argument is the passwd structure
422  * for the current user.
423  */
424 void
425 do_change_passphrase(struct passwd *pw)
426 {
427         char *comment;
428         char *old_passphrase, *passphrase1, *passphrase2;
429         struct stat st;
430         Key *private;
431
432         if (!have_identity)
433                 ask_filename(pw, "Enter file in which the key is");
434         if (stat(identity_file, &st) < 0) {
435                 perror(identity_file);
436                 exit(1);
437         }
438         /* Try to load the file with empty passphrase. */
439         private = key_load_private(identity_file, "", &comment);
440         if (private == NULL) {
441                 if (identity_passphrase)
442                         old_passphrase = xstrdup(identity_passphrase);
443                 else
444                         old_passphrase = read_passphrase("Enter old passphrase: ", 1);
445                 private = key_load_private(identity_file, old_passphrase , &comment);
446                 memset(old_passphrase, 0, strlen(old_passphrase));
447                 xfree(old_passphrase);
448                 if (private == NULL) {
449                         printf("Bad passphrase.\n");
450                         exit(1);
451                 }
452         }
453         printf("Key has comment '%s'\n", comment);
454
455         /* Ask the new passphrase (twice). */
456         if (identity_new_passphrase) {
457                 passphrase1 = xstrdup(identity_new_passphrase);
458                 passphrase2 = NULL;
459         } else {
460                 passphrase1 =
461                         read_passphrase("Enter new passphrase (empty for no passphrase): ", 1);
462                 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
463
464                 /* Verify that they are the same. */
465                 if (strcmp(passphrase1, passphrase2) != 0) {
466                         memset(passphrase1, 0, strlen(passphrase1));
467                         memset(passphrase2, 0, strlen(passphrase2));
468                         xfree(passphrase1);
469                         xfree(passphrase2);
470                         printf("Pass phrases do not match.  Try again.\n");
471                         exit(1);
472                 }
473                 /* Destroy the other copy. */
474                 memset(passphrase2, 0, strlen(passphrase2));
475                 xfree(passphrase2);
476         }
477
478         /* Save the file using the new passphrase. */
479         if (!key_save_private(private, identity_file, passphrase1, comment)) {
480                 printf("Saving the key failed: %s: %s.\n",
481                        identity_file, strerror(errno));
482                 memset(passphrase1, 0, strlen(passphrase1));
483                 xfree(passphrase1);
484                 key_free(private);
485                 xfree(comment);
486                 exit(1);
487         }
488         /* Destroy the passphrase and the copy of the key in memory. */
489         memset(passphrase1, 0, strlen(passphrase1));
490         xfree(passphrase1);
491         key_free(private);               /* Destroys contents */
492         xfree(comment);
493
494         printf("Your identification has been saved with the new passphrase.\n");
495         exit(0);
496 }
497
498 /*
499  * Change the comment of a private key file.
500  */
501 void
502 do_change_comment(struct passwd *pw)
503 {
504         char new_comment[1024], *comment, *passphrase;
505         Key *private;
506         Key *public;
507         struct stat st;
508         FILE *f;
509         int fd;
510
511         if (!have_identity)
512                 ask_filename(pw, "Enter file in which the key is");
513         if (stat(identity_file, &st) < 0) {
514                 perror(identity_file);
515                 exit(1);
516         }
517         private = key_load_private(identity_file, "", &comment);
518         if (private == NULL) {
519                 if (identity_passphrase)
520                         passphrase = xstrdup(identity_passphrase);
521                 else if (identity_new_passphrase)
522                         passphrase = xstrdup(identity_new_passphrase);
523                 else
524                         passphrase = read_passphrase("Enter passphrase: ", 1);
525                 /* Try to load using the passphrase. */
526                 private = key_load_private(identity_file, passphrase, &comment);
527                 if (private == NULL) {
528                         memset(passphrase, 0, strlen(passphrase));
529                         xfree(passphrase);
530                         printf("Bad passphrase.\n");
531                         exit(1);
532                 }
533         } else {
534                 passphrase = xstrdup("");
535         }
536         if (private->type != KEY_RSA1) {
537                 fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
538                 key_free(private);
539                 exit(1);
540         }       
541         printf("Key now has comment '%s'\n", comment);
542
543         if (identity_comment) {
544                 strlcpy(new_comment, identity_comment, sizeof(new_comment));
545         } else {
546                 printf("Enter new comment: ");
547                 fflush(stdout);
548                 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
549                         memset(passphrase, 0, strlen(passphrase));
550                         key_free(private);
551                         exit(1);
552                 }
553                 if (strchr(new_comment, '\n'))
554                         *strchr(new_comment, '\n') = 0;
555         }
556
557         /* Save the file using the new passphrase. */
558         if (!key_save_private(private, identity_file, passphrase, new_comment)) {
559                 printf("Saving the key failed: %s: %s.\n",
560                        identity_file, strerror(errno));
561                 memset(passphrase, 0, strlen(passphrase));
562                 xfree(passphrase);
563                 key_free(private);
564                 xfree(comment);
565                 exit(1);
566         }
567         memset(passphrase, 0, strlen(passphrase));
568         xfree(passphrase);
569         public = key_from_private(private);
570         key_free(private);
571
572         strlcat(identity_file, ".pub", sizeof(identity_file));
573         fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
574         if (fd == -1) {
575                 printf("Could not save your public key in %s\n", identity_file);
576                 exit(1);
577         }
578         f = fdopen(fd, "w");
579         if (f == NULL) {
580                 printf("fdopen %s failed", identity_file);
581                 exit(1);
582         }
583         if (!key_write(public, f))
584                 fprintf(stderr, "write key failed");
585         key_free(public);
586         fprintf(f, " %s\n", new_comment);
587         fclose(f);
588
589         xfree(comment);
590
591         printf("The comment in your key file has been changed.\n");
592         exit(0);
593 }
594
595 void
596 usage(void)
597 {
598         printf("Usage: %s [-lBpqxXyc] [-t type] [-b bits] [-f file] [-C comment] "
599             "[-N new-pass] [-P pass]\n", __progname);
600         exit(1);
601 }
602
603 /*
604  * Main program for key management.
605  */
606 int
607 main(int ac, char **av)
608 {
609         char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2;
610         Key *private, *public;
611         struct passwd *pw;
612         int opt, type, fd;
613         struct stat st;
614         FILE *f;
615
616         extern int optind;
617         extern char *optarg;
618
619         __progname = get_progname(av[0]);
620         init_rng();
621         seed_rng();
622
623         SSLeay_add_all_algorithms();
624
625         /* we need this for the home * directory.  */
626         pw = getpwuid(getuid());
627         if (!pw) {
628                 printf("You don't exist, go away!\n");
629                 exit(1);
630         }
631         if (gethostname(hostname, sizeof(hostname)) < 0) {
632                 perror("gethostname");
633                 exit(1);
634         }
635
636         while ((opt = getopt(ac, av, "dqpclBRxXyb:f:t:P:N:C:")) != -1) {
637                 switch (opt) {
638                 case 'b':
639                         bits = atoi(optarg);
640                         if (bits < 512 || bits > 32768) {
641                                 printf("Bits has bad value.\n");
642                                 exit(1);
643                         }
644                         break;
645
646                 case 'l':
647                         print_fingerprint = 1;
648                         break;
649
650                 case 'B':
651                         print_bubblebabble = 1;
652                         break;
653
654                 case 'p':
655                         change_passphrase = 1;
656                         break;
657
658                 case 'c':
659                         change_comment = 1;
660                         break;
661
662                 case 'f':
663                         strlcpy(identity_file, optarg, sizeof(identity_file));
664                         have_identity = 1;
665                         break;
666
667                 case 'P':
668                         identity_passphrase = optarg;
669                         break;
670
671                 case 'N':
672                         identity_new_passphrase = optarg;
673                         break;
674
675                 case 'C':
676                         identity_comment = optarg;
677                         break;
678
679                 case 'q':
680                         quiet = 1;
681                         break;
682
683                 case 'R':
684                         /* unused */
685                         exit(0);
686                         break;
687
688                 case 'x':
689                         convert_to_ssh2 = 1;
690                         break;
691
692                 case 'X':
693                         convert_from_ssh2 = 1;
694                         break;
695
696                 case 'y':
697                         print_public = 1;
698                         break;
699
700                 case 'd':
701                         key_type_name = "dsa";
702                         break;
703
704                 case 't':
705                         key_type_name = optarg;
706                         break;
707
708                 case '?':
709                 default:
710                         usage();
711                 }
712         }
713         if (optind < ac) {
714                 printf("Too many arguments.\n");
715                 usage();
716         }
717         if (change_passphrase && change_comment) {
718                 printf("Can only have one of -p and -c.\n");
719                 usage();
720         }
721         if (print_fingerprint || print_bubblebabble)
722                 do_fingerprint(pw);
723         if (change_passphrase)
724                 do_change_passphrase(pw);
725         if (change_comment)
726                 do_change_comment(pw);
727         if (convert_to_ssh2)
728                 do_convert_to_ssh2(pw);
729         if (convert_from_ssh2)
730                 do_convert_from_ssh2(pw);
731         if (print_public)
732                 do_print_public(pw);
733
734         arc4random_stir();
735
736         type = key_type_from_name(key_type_name);
737         if (type == KEY_UNSPEC) {
738                 fprintf(stderr, "unknown key type %s\n", key_type_name);
739                 exit(1);
740         }
741         if (!quiet)
742                 printf("Generating public/private %s key pair.\n", key_type_name);
743         private = key_generate(type, bits);
744         if (private == NULL) {
745                 fprintf(stderr, "key_generate failed");
746                 exit(1);
747         }
748         public  = key_from_private(private);
749
750         if (!have_identity)
751                 ask_filename(pw, "Enter file in which to save the key");
752
753         /* Create ~/.ssh directory if it doesn\'t already exist. */
754         snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
755         if (strstr(identity_file, dotsshdir) != NULL &&
756             stat(dotsshdir, &st) < 0) {
757                 if (mkdir(dotsshdir, 0700) < 0)
758                         error("Could not create directory '%s'.", dotsshdir);
759                 else if (!quiet)
760                         printf("Created directory '%s'.\n", dotsshdir);
761         }
762         /* If the file already exists, ask the user to confirm. */
763         if (stat(identity_file, &st) >= 0) {
764                 char yesno[3];
765                 printf("%s already exists.\n", identity_file);
766                 printf("Overwrite (y/n)? ");
767                 fflush(stdout);
768                 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
769                         exit(1);
770                 if (yesno[0] != 'y' && yesno[0] != 'Y')
771                         exit(1);
772         }
773         /* Ask for a passphrase (twice). */
774         if (identity_passphrase)
775                 passphrase1 = xstrdup(identity_passphrase);
776         else if (identity_new_passphrase)
777                 passphrase1 = xstrdup(identity_new_passphrase);
778         else {
779 passphrase_again:
780                 passphrase1 =
781                         read_passphrase("Enter passphrase (empty for no passphrase): ", 1);
782                 passphrase2 = read_passphrase("Enter same passphrase again: ", 1);
783                 if (strcmp(passphrase1, passphrase2) != 0) {
784                         /* The passphrases do not match.  Clear them and retry. */
785                         memset(passphrase1, 0, strlen(passphrase1));
786                         memset(passphrase2, 0, strlen(passphrase2));
787                         xfree(passphrase1);
788                         xfree(passphrase2);
789                         printf("Passphrases do not match.  Try again.\n");
790                         goto passphrase_again;
791                 }
792                 /* Clear the other copy of the passphrase. */
793                 memset(passphrase2, 0, strlen(passphrase2));
794                 xfree(passphrase2);
795         }
796
797         if (identity_comment) {
798                 strlcpy(comment, identity_comment, sizeof(comment));
799         } else {
800                 /* Create default commend field for the passphrase. */
801                 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
802         }
803
804         /* Save the key with the given passphrase and comment. */
805         if (!key_save_private(private, identity_file, passphrase1, comment)) {
806                 printf("Saving the key failed: %s: %s.\n",
807                     identity_file, strerror(errno));
808                 memset(passphrase1, 0, strlen(passphrase1));
809                 xfree(passphrase1);
810                 exit(1);
811         }
812         /* Clear the passphrase. */
813         memset(passphrase1, 0, strlen(passphrase1));
814         xfree(passphrase1);
815
816         /* Clear the private key and the random number generator. */
817         key_free(private);
818         arc4random_stir();
819
820         if (!quiet)
821                 printf("Your identification has been saved in %s.\n", identity_file);
822
823         strlcat(identity_file, ".pub", sizeof(identity_file));
824         fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
825         if (fd == -1) {
826                 printf("Could not save your public key in %s\n", identity_file);
827                 exit(1);
828         }
829         f = fdopen(fd, "w");
830         if (f == NULL) {
831                 printf("fdopen %s failed", identity_file);
832                 exit(1);
833         }
834         if (!key_write(public, f))
835                 fprintf(stderr, "write key failed");
836         fprintf(f, " %s\n", comment);
837         fclose(f);
838
839         if (!quiet) {
840                 char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
841                 printf("Your public key has been saved in %s.\n",
842                     identity_file);
843                 printf("The key fingerprint is:\n");
844                 printf("%s %s\n", fp, comment);
845                 xfree(fp);
846         }
847
848         key_free(public);
849         exit(0);
850 }
This page took 0.104828 seconds and 5 git commands to generate.