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