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