xref: /freebsd/crypto/openssh/ssh-keygen.c (revision b601c69bdbe8755d26570261d7fd4c02ee4eff74)
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: ssh-keygen.c,v 1.26 2000/05/30 17:32:06 markus Exp $");
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 extern char *__progname;
67 
68 char hostname[MAXHOSTNAMELEN];
69 
70 void
71 ask_filename(struct passwd *pw, const char *prompt)
72 {
73 	char buf[1024];
74 	snprintf(identity_file, sizeof(identity_file), "%s/%s",
75 	    pw->pw_dir,
76 	    dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY);
77 	printf("%s (%s): ", prompt, identity_file);
78 	fflush(stdout);
79 	if (fgets(buf, sizeof(buf), stdin) == NULL)
80 		exit(1);
81 	if (strchr(buf, '\n'))
82 		*strchr(buf, '\n') = 0;
83 	if (strcmp(buf, "") != 0)
84 		strlcpy(identity_file, buf, sizeof(identity_file));
85 	have_identity = 1;
86 }
87 
88 int
89 try_load_key(char *filename, Key *k)
90 {
91 	int success = 1;
92 	if (!load_private_key(filename, "", k, NULL)) {
93 		char *pass = read_passphrase("Enter passphrase: ", 1);
94 		if (!load_private_key(filename, pass, k, NULL)) {
95 			success = 0;
96 		}
97 		memset(pass, 0, strlen(pass));
98 		xfree(pass);
99 	}
100 	return success;
101 }
102 
103 #define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----"
104 #define SSH_COM_MAGIC_END   "---- END SSH2 PUBLIC KEY ----"
105 
106 void
107 do_convert_to_ssh2(struct passwd *pw)
108 {
109 	Key *k;
110 	int len;
111 	unsigned char *blob;
112 	struct stat st;
113 
114 	if (!have_identity)
115 		ask_filename(pw, "Enter file in which the key is");
116 	if (stat(identity_file, &st) < 0) {
117 		perror(identity_file);
118 		exit(1);
119 	}
120 	k = key_new(KEY_DSA);
121 	if (!try_load_key(identity_file, k)) {
122 		fprintf(stderr, "load failed\n");
123 		exit(1);
124 	}
125 	dsa_make_key_blob(k, &blob, &len);
126 	fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n");
127 	fprintf(stdout,
128 	    "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n",
129 	    BN_num_bits(k->dsa->p),
130 	    pw->pw_name, hostname);
131 	dump_base64(stdout, blob, len);
132 	fprintf(stdout, SSH_COM_MAGIC_END "\n");
133 	key_free(k);
134 	xfree(blob);
135 	exit(0);
136 }
137 
138 void
139 do_convert_from_ssh2(struct passwd *pw)
140 {
141 	Key *k;
142 	int blen;
143 	char line[1024], *p;
144 	char blob[8096];
145 	char encoded[8096];
146 	struct stat st;
147 	int escaped = 0;
148 	FILE *fp;
149 
150 	if (!have_identity)
151 		ask_filename(pw, "Enter file in which the key is");
152 	if (stat(identity_file, &st) < 0) {
153 		perror(identity_file);
154 		exit(1);
155 	}
156 	fp = fopen(identity_file, "r");
157 	if (fp == NULL) {
158 		perror(identity_file);
159 		exit(1);
160 	}
161 	encoded[0] = '\0';
162 	while (fgets(line, sizeof(line), fp)) {
163 		if (!(p = strchr(line, '\n'))) {
164 			fprintf(stderr, "input line too long.\n");
165 			exit(1);
166 		}
167 		if (p > line && p[-1] == '\\')
168 			escaped++;
169 		if (strncmp(line, "----", 4) == 0 ||
170 		    strstr(line, ": ") != NULL) {
171 			fprintf(stderr, "ignore: %s", line);
172 			continue;
173 		}
174 		if (escaped) {
175 			escaped--;
176 			fprintf(stderr, "escaped: %s", line);
177 			continue;
178 		}
179 		*p = '\0';
180 		strlcat(encoded, line, sizeof(encoded));
181 	}
182 	blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob));
183 	if (blen < 0) {
184 		fprintf(stderr, "uudecode failed.\n");
185 		exit(1);
186 	}
187 	k = dsa_key_from_blob(blob, blen);
188 	if (!key_write(k, stdout))
189 		fprintf(stderr, "key_write failed");
190 	key_free(k);
191 	fprintf(stdout, "\n");
192 	fclose(fp);
193 	exit(0);
194 }
195 
196 void
197 do_print_public(struct passwd *pw)
198 {
199 	Key *k;
200 	int len;
201 	unsigned char *blob;
202 	struct stat st;
203 
204 	if (!have_identity)
205 		ask_filename(pw, "Enter file in which the key is");
206 	if (stat(identity_file, &st) < 0) {
207 		perror(identity_file);
208 		exit(1);
209 	}
210 	k = key_new(KEY_DSA);
211 	if (!try_load_key(identity_file, k)) {
212 		fprintf(stderr, "load failed\n");
213 		exit(1);
214 	}
215 	dsa_make_key_blob(k, &blob, &len);
216 	if (!key_write(k, stdout))
217 		fprintf(stderr, "key_write failed");
218 	key_free(k);
219 	xfree(blob);
220 	fprintf(stdout, "\n");
221 	exit(0);
222 }
223 
224 void
225 do_fingerprint(struct passwd *pw)
226 {
227 	FILE *f;
228 	BIGNUM *e, *n;
229 	Key *public;
230 	char *comment = NULL, *cp, *ep, line[16*1024];
231 	int i, skip = 0, num = 1, invalid = 1;
232 	unsigned int ignore;
233 	struct stat st;
234 
235 	if (!have_identity)
236 		ask_filename(pw, "Enter file in which the key is");
237 	if (stat(identity_file, &st) < 0) {
238 		perror(identity_file);
239 		exit(1);
240 	}
241 	public = key_new(KEY_RSA);
242 	if (load_public_key(identity_file, public, &comment)) {
243 		printf("%d %s %s\n", BN_num_bits(public->rsa->n),
244 		    key_fingerprint(public), comment);
245 		key_free(public);
246 		exit(0);
247 	}
248 	key_free(public);
249 
250 	/* XXX */
251 	f = fopen(identity_file, "r");
252 	if (f != NULL) {
253 		n = BN_new();
254 		e = BN_new();
255 		while (fgets(line, sizeof(line), f)) {
256 			i = strlen(line) - 1;
257 			if (line[i] != '\n') {
258 				error("line %d too long: %.40s...", num, line);
259 				skip = 1;
260 				continue;
261 			}
262 			num++;
263 			if (skip) {
264 				skip = 0;
265 				continue;
266 			}
267 			line[i] = '\0';
268 
269 			/* Skip leading whitespace, empty and comment lines. */
270 			for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
271 				;
272 			if (!*cp || *cp == '\n' || *cp == '#')
273 				continue ;
274 			i = strtol(cp, &ep, 10);
275 			if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
276 				int quoted = 0;
277 				comment = cp;
278 				for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
279 					if (*cp == '\\' && cp[1] == '"')
280 						cp++;	/* Skip both */
281 					else if (*cp == '"')
282 						quoted = !quoted;
283 				}
284 				if (!*cp)
285 					continue;
286 				*cp++ = '\0';
287 			}
288 			ep = cp;
289 			if (auth_rsa_read_key(&cp, &ignore, e, n)) {
290 				invalid = 0;
291 				comment = *cp ? cp : comment;
292 				printf("%d %s %s\n", BN_num_bits(n),
293 				    fingerprint(e, n),
294 				    comment ? comment : "no comment");
295 			}
296 		}
297 		BN_free(e);
298 		BN_free(n);
299 		fclose(f);
300 	}
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, 0755) < 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