ssh-keygen.c revision 181111
1/* $OpenBSD: ssh-keygen.c,v 1.171 2008/07/13 21:22:52 sthen Exp $ */
2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 *                    All rights reserved
6 * Identity and host key generation and maintenance.
7 *
8 * As far as I am concerned, the code I have written for this software
9 * can be used freely for any purpose.  Any derived versions of this
10 * software must be clearly marked as such, and if the derived work is
11 * incompatible with the protocol description in the RFC file, it must be
12 * called by a name other than "ssh" or "Secure Shell".
13 */
14
15#include "includes.h"
16
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <sys/stat.h>
20#include <sys/param.h>
21
22#include <openssl/evp.h>
23#include <openssl/pem.h>
24#include "openbsd-compat/openssl-compat.h"
25
26#include <errno.h>
27#include <fcntl.h>
28#include <netdb.h>
29#ifdef HAVE_PATHS_H
30# include <paths.h>
31#endif
32#include <pwd.h>
33#include <stdarg.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38
39#include "xmalloc.h"
40#include "key.h"
41#include "rsa.h"
42#include "authfile.h"
43#include "uuencode.h"
44#include "buffer.h"
45#include "pathnames.h"
46#include "log.h"
47#include "misc.h"
48#include "match.h"
49#include "hostfile.h"
50#include "dns.h"
51
52#ifdef SMARTCARD
53#include "scard.h"
54#endif
55
56/* Number of bits in the RSA/DSA key.  This value can be set on the command line. */
57#define DEFAULT_BITS		2048
58#define DEFAULT_BITS_DSA	1024
59u_int32_t bits = 0;
60
61/*
62 * Flag indicating that we just want to change the passphrase.  This can be
63 * set on the command line.
64 */
65int change_passphrase = 0;
66
67/*
68 * Flag indicating that we just want to change the comment.  This can be set
69 * on the command line.
70 */
71int change_comment = 0;
72
73int quiet = 0;
74
75int log_level = SYSLOG_LEVEL_INFO;
76
77/* Flag indicating that we want to hash a known_hosts file */
78int hash_hosts = 0;
79/* Flag indicating that we want lookup a host in known_hosts file */
80int find_host = 0;
81/* Flag indicating that we want to delete a host from a known_hosts file */
82int delete_host = 0;
83
84/* Flag indicating that we just want to see the key fingerprint */
85int print_fingerprint = 0;
86int print_bubblebabble = 0;
87
88/* The identity file name, given on the command line or entered by the user. */
89char identity_file[1024];
90int have_identity = 0;
91
92/* This is set to the passphrase if given on the command line. */
93char *identity_passphrase = NULL;
94
95/* This is set to the new passphrase if given on the command line. */
96char *identity_new_passphrase = NULL;
97
98/* This is set to the new comment if given on the command line. */
99char *identity_comment = NULL;
100
101/* Dump public key file in format used by real and the original SSH 2 */
102int convert_to_ssh2 = 0;
103int convert_from_ssh2 = 0;
104int print_public = 0;
105int print_generic = 0;
106
107char *key_type_name = NULL;
108
109/* argv0 */
110extern char *__progname;
111
112char hostname[MAXHOSTNAMELEN];
113
114/* moduli.c */
115int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
116int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
117
118static void
119ask_filename(struct passwd *pw, const char *prompt)
120{
121	char buf[1024];
122	char *name = NULL;
123
124	if (key_type_name == NULL)
125		name = _PATH_SSH_CLIENT_ID_RSA;
126	else {
127		switch (key_type_from_name(key_type_name)) {
128		case KEY_RSA1:
129			name = _PATH_SSH_CLIENT_IDENTITY;
130			break;
131		case KEY_DSA:
132			name = _PATH_SSH_CLIENT_ID_DSA;
133			break;
134		case KEY_RSA:
135			name = _PATH_SSH_CLIENT_ID_RSA;
136			break;
137		default:
138			fprintf(stderr, "bad key type");
139			exit(1);
140			break;
141		}
142	}
143	snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
144	fprintf(stderr, "%s (%s): ", prompt, identity_file);
145	if (fgets(buf, sizeof(buf), stdin) == NULL)
146		exit(1);
147	buf[strcspn(buf, "\n")] = '\0';
148	if (strcmp(buf, "") != 0)
149		strlcpy(identity_file, buf, sizeof(identity_file));
150	have_identity = 1;
151}
152
153static Key *
154load_identity(char *filename)
155{
156	char *pass;
157	Key *prv;
158
159	prv = key_load_private(filename, "", NULL);
160	if (prv == NULL) {
161		if (identity_passphrase)
162			pass = xstrdup(identity_passphrase);
163		else
164			pass = read_passphrase("Enter passphrase: ",
165			    RP_ALLOW_STDIN);
166		prv = key_load_private(filename, pass, NULL);
167		memset(pass, 0, strlen(pass));
168		xfree(pass);
169	}
170	return prv;
171}
172
173#define SSH_COM_PUBLIC_BEGIN		"---- BEGIN SSH2 PUBLIC KEY ----"
174#define SSH_COM_PUBLIC_END		"---- END SSH2 PUBLIC KEY ----"
175#define SSH_COM_PRIVATE_BEGIN		"---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
176#define	SSH_COM_PRIVATE_KEY_MAGIC	0x3f6ff9eb
177
178static void
179do_convert_to_ssh2(struct passwd *pw)
180{
181	Key *k;
182	u_int len;
183	u_char *blob;
184	struct stat st;
185
186	if (!have_identity)
187		ask_filename(pw, "Enter file in which the key is");
188	if (stat(identity_file, &st) < 0) {
189		perror(identity_file);
190		exit(1);
191	}
192	if ((k = key_load_public(identity_file, NULL)) == NULL) {
193		if ((k = load_identity(identity_file)) == NULL) {
194			fprintf(stderr, "load failed\n");
195			exit(1);
196		}
197	}
198	if (k->type == KEY_RSA1) {
199		fprintf(stderr, "version 1 keys are not supported\n");
200		exit(1);
201	}
202	if (key_to_blob(k, &blob, &len) <= 0) {
203		fprintf(stderr, "key_to_blob failed\n");
204		exit(1);
205	}
206	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
207	fprintf(stdout,
208	    "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n",
209	    key_size(k), key_type(k),
210	    pw->pw_name, hostname);
211	dump_base64(stdout, blob, len);
212	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
213	key_free(k);
214	xfree(blob);
215	exit(0);
216}
217
218static void
219buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
220{
221	u_int bignum_bits = buffer_get_int(b);
222	u_int bytes = (bignum_bits + 7) / 8;
223
224	if (buffer_len(b) < bytes)
225		fatal("buffer_get_bignum_bits: input buffer too small: "
226		    "need %d have %d", bytes, buffer_len(b));
227	if (BN_bin2bn(buffer_ptr(b), bytes, value) == NULL)
228		fatal("buffer_get_bignum_bits: BN_bin2bn failed");
229	buffer_consume(b, bytes);
230}
231
232static Key *
233do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
234{
235	Buffer b;
236	Key *key = NULL;
237	char *type, *cipher;
238	u_char *sig, data[] = "abcde12345";
239	int magic, rlen, ktype, i1, i2, i3, i4;
240	u_int slen;
241	u_long e;
242
243	buffer_init(&b);
244	buffer_append(&b, blob, blen);
245
246	magic = buffer_get_int(&b);
247	if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
248		error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
249		buffer_free(&b);
250		return NULL;
251	}
252	i1 = buffer_get_int(&b);
253	type   = buffer_get_string(&b, NULL);
254	cipher = buffer_get_string(&b, NULL);
255	i2 = buffer_get_int(&b);
256	i3 = buffer_get_int(&b);
257	i4 = buffer_get_int(&b);
258	debug("ignore (%d %d %d %d)", i1, i2, i3, i4);
259	if (strcmp(cipher, "none") != 0) {
260		error("unsupported cipher %s", cipher);
261		xfree(cipher);
262		buffer_free(&b);
263		xfree(type);
264		return NULL;
265	}
266	xfree(cipher);
267
268	if (strstr(type, "dsa")) {
269		ktype = KEY_DSA;
270	} else if (strstr(type, "rsa")) {
271		ktype = KEY_RSA;
272	} else {
273		buffer_free(&b);
274		xfree(type);
275		return NULL;
276	}
277	key = key_new_private(ktype);
278	xfree(type);
279
280	switch (key->type) {
281	case KEY_DSA:
282		buffer_get_bignum_bits(&b, key->dsa->p);
283		buffer_get_bignum_bits(&b, key->dsa->g);
284		buffer_get_bignum_bits(&b, key->dsa->q);
285		buffer_get_bignum_bits(&b, key->dsa->pub_key);
286		buffer_get_bignum_bits(&b, key->dsa->priv_key);
287		break;
288	case KEY_RSA:
289		e = buffer_get_char(&b);
290		debug("e %lx", e);
291		if (e < 30) {
292			e <<= 8;
293			e += buffer_get_char(&b);
294			debug("e %lx", e);
295			e <<= 8;
296			e += buffer_get_char(&b);
297			debug("e %lx", e);
298		}
299		if (!BN_set_word(key->rsa->e, e)) {
300			buffer_free(&b);
301			key_free(key);
302			return NULL;
303		}
304		buffer_get_bignum_bits(&b, key->rsa->d);
305		buffer_get_bignum_bits(&b, key->rsa->n);
306		buffer_get_bignum_bits(&b, key->rsa->iqmp);
307		buffer_get_bignum_bits(&b, key->rsa->q);
308		buffer_get_bignum_bits(&b, key->rsa->p);
309		rsa_generate_additional_parameters(key->rsa);
310		break;
311	}
312	rlen = buffer_len(&b);
313	if (rlen != 0)
314		error("do_convert_private_ssh2_from_blob: "
315		    "remaining bytes in key blob %d", rlen);
316	buffer_free(&b);
317
318	/* try the key */
319	key_sign(key, &sig, &slen, data, sizeof(data));
320	key_verify(key, sig, slen, data, sizeof(data));
321	xfree(sig);
322	return key;
323}
324
325static int
326get_line(FILE *fp, char *line, size_t len)
327{
328	int c;
329	size_t pos = 0;
330
331	line[0] = '\0';
332	while ((c = fgetc(fp)) != EOF) {
333		if (pos >= len - 1) {
334			fprintf(stderr, "input line too long.\n");
335			exit(1);
336		}
337		switch (c) {
338		case '\r':
339			c = fgetc(fp);
340			if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) {
341				fprintf(stderr, "unget: %s\n", strerror(errno));
342				exit(1);
343			}
344			return pos;
345		case '\n':
346			return pos;
347		}
348		line[pos++] = c;
349		line[pos] = '\0';
350	}
351	/* We reached EOF */
352	return -1;
353}
354
355static void
356do_convert_from_ssh2(struct passwd *pw)
357{
358	Key *k;
359	int blen;
360	u_int len;
361	char line[1024];
362	u_char blob[8096];
363	char encoded[8096];
364	struct stat st;
365	int escaped = 0, private = 0, ok;
366	FILE *fp;
367
368	if (!have_identity)
369		ask_filename(pw, "Enter file in which the key is");
370	if (stat(identity_file, &st) < 0) {
371		perror(identity_file);
372		exit(1);
373	}
374	fp = fopen(identity_file, "r");
375	if (fp == NULL) {
376		perror(identity_file);
377		exit(1);
378	}
379	encoded[0] = '\0';
380	while ((blen = get_line(fp, line, sizeof(line))) != -1) {
381		if (line[blen - 1] == '\\')
382			escaped++;
383		if (strncmp(line, "----", 4) == 0 ||
384		    strstr(line, ": ") != NULL) {
385			if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
386				private = 1;
387			if (strstr(line, " END ") != NULL) {
388				break;
389			}
390			/* fprintf(stderr, "ignore: %s", line); */
391			continue;
392		}
393		if (escaped) {
394			escaped--;
395			/* fprintf(stderr, "escaped: %s", line); */
396			continue;
397		}
398		strlcat(encoded, line, sizeof(encoded));
399	}
400	len = strlen(encoded);
401	if (((len % 4) == 3) &&
402	    (encoded[len-1] == '=') &&
403	    (encoded[len-2] == '=') &&
404	    (encoded[len-3] == '='))
405		encoded[len-3] = '\0';
406	blen = uudecode(encoded, blob, sizeof(blob));
407	if (blen < 0) {
408		fprintf(stderr, "uudecode failed.\n");
409		exit(1);
410	}
411	k = private ?
412	    do_convert_private_ssh2_from_blob(blob, blen) :
413	    key_from_blob(blob, blen);
414	if (k == NULL) {
415		fprintf(stderr, "decode blob failed.\n");
416		exit(1);
417	}
418	ok = private ?
419	    (k->type == KEY_DSA ?
420		 PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
421		 PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
422	    key_write(k, stdout);
423	if (!ok) {
424		fprintf(stderr, "key write failed");
425		exit(1);
426	}
427	key_free(k);
428	if (!private)
429		fprintf(stdout, "\n");
430	fclose(fp);
431	exit(0);
432}
433
434static void
435do_print_public(struct passwd *pw)
436{
437	Key *prv;
438	struct stat st;
439
440	if (!have_identity)
441		ask_filename(pw, "Enter file in which the key is");
442	if (stat(identity_file, &st) < 0) {
443		perror(identity_file);
444		exit(1);
445	}
446	prv = load_identity(identity_file);
447	if (prv == NULL) {
448		fprintf(stderr, "load failed\n");
449		exit(1);
450	}
451	if (!key_write(prv, stdout))
452		fprintf(stderr, "key_write failed");
453	key_free(prv);
454	fprintf(stdout, "\n");
455	exit(0);
456}
457
458#ifdef SMARTCARD
459static void
460do_upload(struct passwd *pw, const char *sc_reader_id)
461{
462	Key *prv = NULL;
463	struct stat st;
464	int ret;
465
466	if (!have_identity)
467		ask_filename(pw, "Enter file in which the key is");
468	if (stat(identity_file, &st) < 0) {
469		perror(identity_file);
470		exit(1);
471	}
472	prv = load_identity(identity_file);
473	if (prv == NULL) {
474		error("load failed");
475		exit(1);
476	}
477	ret = sc_put_key(prv, sc_reader_id);
478	key_free(prv);
479	if (ret < 0)
480		exit(1);
481	logit("loading key done");
482	exit(0);
483}
484
485static void
486do_download(struct passwd *pw, const char *sc_reader_id)
487{
488	Key **keys = NULL;
489	int i;
490
491	keys = sc_get_keys(sc_reader_id, NULL);
492	if (keys == NULL)
493		fatal("cannot read public key from smartcard");
494	for (i = 0; keys[i]; i++) {
495		key_write(keys[i], stdout);
496		key_free(keys[i]);
497		fprintf(stdout, "\n");
498	}
499	xfree(keys);
500	exit(0);
501}
502#endif /* SMARTCARD */
503
504static void
505do_fingerprint(struct passwd *pw)
506{
507	FILE *f;
508	Key *public;
509	char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
510	int i, skip = 0, num = 0, invalid = 1;
511	enum fp_rep rep;
512	enum fp_type fptype;
513	struct stat st;
514
515	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
516	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
517
518	if (!have_identity)
519		ask_filename(pw, "Enter file in which the key is");
520	if (stat(identity_file, &st) < 0) {
521		perror(identity_file);
522		exit(1);
523	}
524	public = key_load_public(identity_file, &comment);
525	if (public != NULL) {
526		fp = key_fingerprint(public, fptype, rep);
527		ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
528		printf("%u %s %s (%s)\n", key_size(public), fp, comment,
529		    key_type(public));
530		if (log_level >= SYSLOG_LEVEL_VERBOSE)
531			printf("%s\n", ra);
532		key_free(public);
533		xfree(comment);
534		xfree(ra);
535		xfree(fp);
536		exit(0);
537	}
538	if (comment) {
539		xfree(comment);
540		comment = NULL;
541	}
542
543	f = fopen(identity_file, "r");
544	if (f != NULL) {
545		while (fgets(line, sizeof(line), f)) {
546			if ((cp = strchr(line, '\n')) == NULL) {
547				error("line %d too long: %.40s...",
548				    num + 1, line);
549				skip = 1;
550				continue;
551			}
552			num++;
553			if (skip) {
554				skip = 0;
555				continue;
556			}
557			*cp = '\0';
558
559			/* Skip leading whitespace, empty and comment lines. */
560			for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
561				;
562			if (!*cp || *cp == '\n' || *cp == '#')
563				continue;
564			i = strtol(cp, &ep, 10);
565			if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
566				int quoted = 0;
567				comment = cp;
568				for (; *cp && (quoted || (*cp != ' ' &&
569				    *cp != '\t')); cp++) {
570					if (*cp == '\\' && cp[1] == '"')
571						cp++;	/* Skip both */
572					else if (*cp == '"')
573						quoted = !quoted;
574				}
575				if (!*cp)
576					continue;
577				*cp++ = '\0';
578			}
579			ep = cp;
580			public = key_new(KEY_RSA1);
581			if (key_read(public, &cp) != 1) {
582				cp = ep;
583				key_free(public);
584				public = key_new(KEY_UNSPEC);
585				if (key_read(public, &cp) != 1) {
586					key_free(public);
587					continue;
588				}
589			}
590			comment = *cp ? cp : comment;
591			fp = key_fingerprint(public, fptype, rep);
592			ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
593			printf("%u %s %s (%s)\n", key_size(public), fp,
594			    comment ? comment : "no comment", key_type(public));
595			if (log_level >= SYSLOG_LEVEL_VERBOSE)
596				printf("%s\n", ra);
597			xfree(ra);
598			xfree(fp);
599			key_free(public);
600			invalid = 0;
601		}
602		fclose(f);
603	}
604	if (invalid) {
605		printf("%s is not a public key file.\n", identity_file);
606		exit(1);
607	}
608	exit(0);
609}
610
611static void
612print_host(FILE *f, const char *name, Key *public, int hash)
613{
614	if (print_fingerprint) {
615		enum fp_rep rep;
616		enum fp_type fptype;
617		char *fp, *ra;
618
619		fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
620		rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
621		fp = key_fingerprint(public, fptype, rep);
622		ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
623		printf("%u %s %s (%s)\n", key_size(public), fp, name,
624		    key_type(public));
625		if (log_level >= SYSLOG_LEVEL_VERBOSE)
626			printf("%s\n", ra);
627		xfree(ra);
628		xfree(fp);
629	} else {
630		if (hash && (name = host_hash(name, NULL, 0)) == NULL)
631			fatal("hash_host failed");
632		fprintf(f, "%s ", name);
633		if (!key_write(public, f))
634			fatal("key_write failed");
635		fprintf(f, "\n");
636	}
637}
638
639static void
640do_known_hosts(struct passwd *pw, const char *name)
641{
642	FILE *in, *out = stdout;
643	Key *public;
644	char *cp, *cp2, *kp, *kp2;
645	char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
646	int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
647
648	if (!have_identity) {
649		cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
650		if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
651		    sizeof(identity_file))
652			fatal("Specified known hosts path too long");
653		xfree(cp);
654		have_identity = 1;
655	}
656	if ((in = fopen(identity_file, "r")) == NULL)
657		fatal("fopen: %s", strerror(errno));
658
659	/*
660	 * Find hosts goes to stdout, hash and deletions happen in-place
661	 * A corner case is ssh-keygen -HF foo, which should go to stdout
662	 */
663	if (!find_host && (hash_hosts || delete_host)) {
664		if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
665		    strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
666		    strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
667		    strlcat(old, ".old", sizeof(old)) >= sizeof(old))
668			fatal("known_hosts path too long");
669		umask(077);
670		if ((c = mkstemp(tmp)) == -1)
671			fatal("mkstemp: %s", strerror(errno));
672		if ((out = fdopen(c, "w")) == NULL) {
673			c = errno;
674			unlink(tmp);
675			fatal("fdopen: %s", strerror(c));
676		}
677		inplace = 1;
678	}
679
680	while (fgets(line, sizeof(line), in)) {
681		if ((cp = strchr(line, '\n')) == NULL) {
682			error("line %d too long: %.40s...", num + 1, line);
683			skip = 1;
684			invalid = 1;
685			continue;
686		}
687		num++;
688		if (skip) {
689			skip = 0;
690			continue;
691		}
692		*cp = '\0';
693
694		/* Skip leading whitespace, empty and comment lines. */
695		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
696			;
697		if (!*cp || *cp == '\n' || *cp == '#') {
698			if (inplace)
699				fprintf(out, "%s\n", cp);
700			continue;
701		}
702		/* Find the end of the host name portion. */
703		for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
704			;
705		if (*kp == '\0' || *(kp + 1) == '\0') {
706			error("line %d missing key: %.40s...",
707			    num, line);
708			invalid = 1;
709			continue;
710		}
711		*kp++ = '\0';
712		kp2 = kp;
713
714		public = key_new(KEY_RSA1);
715		if (key_read(public, &kp) != 1) {
716			kp = kp2;
717			key_free(public);
718			public = key_new(KEY_UNSPEC);
719			if (key_read(public, &kp) != 1) {
720				error("line %d invalid key: %.40s...",
721				    num, line);
722				key_free(public);
723				invalid = 1;
724				continue;
725			}
726		}
727
728		if (*cp == HASH_DELIM) {
729			if (find_host || delete_host) {
730				cp2 = host_hash(name, cp, strlen(cp));
731				if (cp2 == NULL) {
732					error("line %d: invalid hashed "
733					    "name: %.64s...", num, line);
734					invalid = 1;
735					continue;
736				}
737				c = (strcmp(cp2, cp) == 0);
738				if (find_host && c) {
739					printf("# Host %s found: "
740					    "line %d type %s\n", name,
741					    num, key_type(public));
742					print_host(out, cp, public, 0);
743				}
744				if (delete_host && !c)
745					print_host(out, cp, public, 0);
746			} else if (hash_hosts)
747				print_host(out, cp, public, 0);
748		} else {
749			if (find_host || delete_host) {
750				c = (match_hostname(name, cp,
751				    strlen(cp)) == 1);
752				if (find_host && c) {
753					printf("# Host %s found: "
754					    "line %d type %s\n", name,
755					    num, key_type(public));
756					print_host(out, name, public,
757					    hash_hosts);
758				}
759				if (delete_host && !c)
760					print_host(out, cp, public, 0);
761			} else if (hash_hosts) {
762				for (cp2 = strsep(&cp, ",");
763				    cp2 != NULL && *cp2 != '\0';
764				    cp2 = strsep(&cp, ",")) {
765					if (strcspn(cp2, "*?!") != strlen(cp2))
766						fprintf(stderr, "Warning: "
767						    "ignoring host name with "
768						    "metacharacters: %.64s\n",
769						    cp2);
770					else
771						print_host(out, cp2, public, 1);
772				}
773				has_unhashed = 1;
774			}
775		}
776		key_free(public);
777	}
778	fclose(in);
779
780	if (invalid) {
781		fprintf(stderr, "%s is not a valid known_hosts file.\n",
782		    identity_file);
783		if (inplace) {
784			fprintf(stderr, "Not replacing existing known_hosts "
785			    "file because of errors\n");
786			fclose(out);
787			unlink(tmp);
788		}
789		exit(1);
790	}
791
792	if (inplace) {
793		fclose(out);
794
795		/* Backup existing file */
796		if (unlink(old) == -1 && errno != ENOENT)
797			fatal("unlink %.100s: %s", old, strerror(errno));
798		if (link(identity_file, old) == -1)
799			fatal("link %.100s to %.100s: %s", identity_file, old,
800			    strerror(errno));
801		/* Move new one into place */
802		if (rename(tmp, identity_file) == -1) {
803			error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
804			    strerror(errno));
805			unlink(tmp);
806			unlink(old);
807			exit(1);
808		}
809
810		fprintf(stderr, "%s updated.\n", identity_file);
811		fprintf(stderr, "Original contents retained as %s\n", old);
812		if (has_unhashed) {
813			fprintf(stderr, "WARNING: %s contains unhashed "
814			    "entries\n", old);
815			fprintf(stderr, "Delete this file to ensure privacy "
816			    "of hostnames\n");
817		}
818	}
819
820	exit(0);
821}
822
823/*
824 * Perform changing a passphrase.  The argument is the passwd structure
825 * for the current user.
826 */
827static void
828do_change_passphrase(struct passwd *pw)
829{
830	char *comment;
831	char *old_passphrase, *passphrase1, *passphrase2;
832	struct stat st;
833	Key *private;
834
835	if (!have_identity)
836		ask_filename(pw, "Enter file in which the key is");
837	if (stat(identity_file, &st) < 0) {
838		perror(identity_file);
839		exit(1);
840	}
841	/* Try to load the file with empty passphrase. */
842	private = key_load_private(identity_file, "", &comment);
843	if (private == NULL) {
844		if (identity_passphrase)
845			old_passphrase = xstrdup(identity_passphrase);
846		else
847			old_passphrase =
848			    read_passphrase("Enter old passphrase: ",
849			    RP_ALLOW_STDIN);
850		private = key_load_private(identity_file, old_passphrase,
851		    &comment);
852		memset(old_passphrase, 0, strlen(old_passphrase));
853		xfree(old_passphrase);
854		if (private == NULL) {
855			printf("Bad passphrase.\n");
856			exit(1);
857		}
858	}
859	printf("Key has comment '%s'\n", comment);
860
861	/* Ask the new passphrase (twice). */
862	if (identity_new_passphrase) {
863		passphrase1 = xstrdup(identity_new_passphrase);
864		passphrase2 = NULL;
865	} else {
866		passphrase1 =
867			read_passphrase("Enter new passphrase (empty for no "
868			    "passphrase): ", RP_ALLOW_STDIN);
869		passphrase2 = read_passphrase("Enter same passphrase again: ",
870		    RP_ALLOW_STDIN);
871
872		/* Verify that they are the same. */
873		if (strcmp(passphrase1, passphrase2) != 0) {
874			memset(passphrase1, 0, strlen(passphrase1));
875			memset(passphrase2, 0, strlen(passphrase2));
876			xfree(passphrase1);
877			xfree(passphrase2);
878			printf("Pass phrases do not match.  Try again.\n");
879			exit(1);
880		}
881		/* Destroy the other copy. */
882		memset(passphrase2, 0, strlen(passphrase2));
883		xfree(passphrase2);
884	}
885
886	/* Save the file using the new passphrase. */
887	if (!key_save_private(private, identity_file, passphrase1, comment)) {
888		printf("Saving the key failed: %s.\n", identity_file);
889		memset(passphrase1, 0, strlen(passphrase1));
890		xfree(passphrase1);
891		key_free(private);
892		xfree(comment);
893		exit(1);
894	}
895	/* Destroy the passphrase and the copy of the key in memory. */
896	memset(passphrase1, 0, strlen(passphrase1));
897	xfree(passphrase1);
898	key_free(private);		 /* Destroys contents */
899	xfree(comment);
900
901	printf("Your identification has been saved with the new passphrase.\n");
902	exit(0);
903}
904
905/*
906 * Print the SSHFP RR.
907 */
908static int
909do_print_resource_record(struct passwd *pw, char *fname, char *hname)
910{
911	Key *public;
912	char *comment = NULL;
913	struct stat st;
914
915	if (fname == NULL)
916		ask_filename(pw, "Enter file in which the key is");
917	if (stat(fname, &st) < 0) {
918		if (errno == ENOENT)
919			return 0;
920		perror(fname);
921		exit(1);
922	}
923	public = key_load_public(fname, &comment);
924	if (public != NULL) {
925		export_dns_rr(hname, public, stdout, print_generic);
926		key_free(public);
927		xfree(comment);
928		return 1;
929	}
930	if (comment)
931		xfree(comment);
932
933	printf("failed to read v2 public key from %s.\n", fname);
934	exit(1);
935}
936
937/*
938 * Change the comment of a private key file.
939 */
940static void
941do_change_comment(struct passwd *pw)
942{
943	char new_comment[1024], *comment, *passphrase;
944	Key *private;
945	Key *public;
946	struct stat st;
947	FILE *f;
948	int fd;
949
950	if (!have_identity)
951		ask_filename(pw, "Enter file in which the key is");
952	if (stat(identity_file, &st) < 0) {
953		perror(identity_file);
954		exit(1);
955	}
956	private = key_load_private(identity_file, "", &comment);
957	if (private == NULL) {
958		if (identity_passphrase)
959			passphrase = xstrdup(identity_passphrase);
960		else if (identity_new_passphrase)
961			passphrase = xstrdup(identity_new_passphrase);
962		else
963			passphrase = read_passphrase("Enter passphrase: ",
964			    RP_ALLOW_STDIN);
965		/* Try to load using the passphrase. */
966		private = key_load_private(identity_file, passphrase, &comment);
967		if (private == NULL) {
968			memset(passphrase, 0, strlen(passphrase));
969			xfree(passphrase);
970			printf("Bad passphrase.\n");
971			exit(1);
972		}
973	} else {
974		passphrase = xstrdup("");
975	}
976	if (private->type != KEY_RSA1) {
977		fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
978		key_free(private);
979		exit(1);
980	}
981	printf("Key now has comment '%s'\n", comment);
982
983	if (identity_comment) {
984		strlcpy(new_comment, identity_comment, sizeof(new_comment));
985	} else {
986		printf("Enter new comment: ");
987		fflush(stdout);
988		if (!fgets(new_comment, sizeof(new_comment), stdin)) {
989			memset(passphrase, 0, strlen(passphrase));
990			key_free(private);
991			exit(1);
992		}
993		new_comment[strcspn(new_comment, "\n")] = '\0';
994	}
995
996	/* Save the file using the new passphrase. */
997	if (!key_save_private(private, identity_file, passphrase, new_comment)) {
998		printf("Saving the key failed: %s.\n", identity_file);
999		memset(passphrase, 0, strlen(passphrase));
1000		xfree(passphrase);
1001		key_free(private);
1002		xfree(comment);
1003		exit(1);
1004	}
1005	memset(passphrase, 0, strlen(passphrase));
1006	xfree(passphrase);
1007	public = key_from_private(private);
1008	key_free(private);
1009
1010	strlcat(identity_file, ".pub", sizeof(identity_file));
1011	fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1012	if (fd == -1) {
1013		printf("Could not save your public key in %s\n", identity_file);
1014		exit(1);
1015	}
1016	f = fdopen(fd, "w");
1017	if (f == NULL) {
1018		printf("fdopen %s failed", identity_file);
1019		exit(1);
1020	}
1021	if (!key_write(public, f))
1022		fprintf(stderr, "write key failed");
1023	key_free(public);
1024	fprintf(f, " %s\n", new_comment);
1025	fclose(f);
1026
1027	xfree(comment);
1028
1029	printf("The comment in your key file has been changed.\n");
1030	exit(0);
1031}
1032
1033static void
1034usage(void)
1035{
1036	fprintf(stderr, "usage: %s [options]\n", __progname);
1037	fprintf(stderr, "Options:\n");
1038	fprintf(stderr, "  -a trials   Number of trials for screening DH-GEX moduli.\n");
1039	fprintf(stderr, "  -B          Show bubblebabble digest of key file.\n");
1040	fprintf(stderr, "  -b bits     Number of bits in the key to create.\n");
1041	fprintf(stderr, "  -C comment  Provide new comment.\n");
1042	fprintf(stderr, "  -c          Change comment in private and public key files.\n");
1043#ifdef SMARTCARD
1044	fprintf(stderr, "  -D reader   Download public key from smartcard.\n");
1045#endif /* SMARTCARD */
1046	fprintf(stderr, "  -e          Convert OpenSSH to RFC 4716 key file.\n");
1047	fprintf(stderr, "  -F hostname Find hostname in known hosts file.\n");
1048	fprintf(stderr, "  -f filename Filename of the key file.\n");
1049	fprintf(stderr, "  -G file     Generate candidates for DH-GEX moduli.\n");
1050	fprintf(stderr, "  -g          Use generic DNS resource record format.\n");
1051	fprintf(stderr, "  -H          Hash names in known_hosts file.\n");
1052	fprintf(stderr, "  -i          Convert RFC 4716 to OpenSSH key file.\n");
1053	fprintf(stderr, "  -l          Show fingerprint of key file.\n");
1054	fprintf(stderr, "  -M memory   Amount of memory (MB) to use for generating DH-GEX moduli.\n");
1055	fprintf(stderr, "  -N phrase   Provide new passphrase.\n");
1056	fprintf(stderr, "  -P phrase   Provide old passphrase.\n");
1057	fprintf(stderr, "  -p          Change passphrase of private key file.\n");
1058	fprintf(stderr, "  -q          Quiet.\n");
1059	fprintf(stderr, "  -R hostname Remove host from known_hosts file.\n");
1060	fprintf(stderr, "  -r hostname Print DNS resource record.\n");
1061	fprintf(stderr, "  -S start    Start point (hex) for generating DH-GEX moduli.\n");
1062	fprintf(stderr, "  -T file     Screen candidates for DH-GEX moduli.\n");
1063	fprintf(stderr, "  -t type     Specify type of key to create.\n");
1064#ifdef SMARTCARD
1065	fprintf(stderr, "  -U reader   Upload private key to smartcard.\n");
1066#endif /* SMARTCARD */
1067	fprintf(stderr, "  -v          Verbose.\n");
1068	fprintf(stderr, "  -W gen      Generator to use for generating DH-GEX moduli.\n");
1069	fprintf(stderr, "  -y          Read private key file and print public key.\n");
1070
1071	exit(1);
1072}
1073
1074/*
1075 * Main program for key management.
1076 */
1077int
1078main(int argc, char **argv)
1079{
1080	char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
1081	char out_file[MAXPATHLEN], *reader_id = NULL;
1082	char *rr_hostname = NULL;
1083	Key *private, *public;
1084	struct passwd *pw;
1085	struct stat st;
1086	int opt, type, fd, download = 0;
1087	u_int32_t memory = 0, generator_wanted = 0, trials = 100;
1088	int do_gen_candidates = 0, do_screen_candidates = 0;
1089	BIGNUM *start = NULL;
1090	FILE *f;
1091	const char *errstr;
1092
1093	extern int optind;
1094	extern char *optarg;
1095
1096	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
1097	sanitise_stdfd();
1098
1099	__progname = ssh_get_progname(argv[0]);
1100
1101	SSLeay_add_all_algorithms();
1102	log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
1103
1104	init_rng();
1105	seed_rng();
1106
1107	/* we need this for the home * directory.  */
1108	pw = getpwuid(getuid());
1109	if (!pw) {
1110		printf("You don't exist, go away!\n");
1111		exit(1);
1112	}
1113	if (gethostname(hostname, sizeof(hostname)) < 0) {
1114		perror("gethostname");
1115		exit(1);
1116	}
1117
1118	while ((opt = getopt(argc, argv,
1119	    "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
1120		switch (opt) {
1121		case 'b':
1122			bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
1123			if (errstr)
1124				fatal("Bits has bad value %s (%s)",
1125					optarg, errstr);
1126			break;
1127		case 'F':
1128			find_host = 1;
1129			rr_hostname = optarg;
1130			break;
1131		case 'H':
1132			hash_hosts = 1;
1133			break;
1134		case 'R':
1135			delete_host = 1;
1136			rr_hostname = optarg;
1137			break;
1138		case 'l':
1139			print_fingerprint = 1;
1140			break;
1141		case 'B':
1142			print_bubblebabble = 1;
1143			break;
1144		case 'p':
1145			change_passphrase = 1;
1146			break;
1147		case 'c':
1148			change_comment = 1;
1149			break;
1150		case 'f':
1151			if (strlcpy(identity_file, optarg, sizeof(identity_file)) >=
1152			    sizeof(identity_file))
1153				fatal("Identity filename too long");
1154			have_identity = 1;
1155			break;
1156		case 'g':
1157			print_generic = 1;
1158			break;
1159		case 'P':
1160			identity_passphrase = optarg;
1161			break;
1162		case 'N':
1163			identity_new_passphrase = optarg;
1164			break;
1165		case 'C':
1166			identity_comment = optarg;
1167			break;
1168		case 'q':
1169			quiet = 1;
1170			break;
1171		case 'e':
1172		case 'x':
1173			/* export key */
1174			convert_to_ssh2 = 1;
1175			break;
1176		case 'i':
1177		case 'X':
1178			/* import key */
1179			convert_from_ssh2 = 1;
1180			break;
1181		case 'y':
1182			print_public = 1;
1183			break;
1184		case 'd':
1185			key_type_name = "dsa";
1186			break;
1187		case 't':
1188			key_type_name = optarg;
1189			break;
1190		case 'D':
1191			download = 1;
1192			/*FALLTHROUGH*/
1193		case 'U':
1194			reader_id = optarg;
1195			break;
1196		case 'v':
1197			if (log_level == SYSLOG_LEVEL_INFO)
1198				log_level = SYSLOG_LEVEL_DEBUG1;
1199			else {
1200				if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
1201				    log_level < SYSLOG_LEVEL_DEBUG3)
1202					log_level++;
1203			}
1204			break;
1205		case 'r':
1206			rr_hostname = optarg;
1207			break;
1208		case 'W':
1209			generator_wanted = (u_int32_t)strtonum(optarg, 1,
1210			    UINT_MAX, &errstr);
1211			if (errstr)
1212				fatal("Desired generator has bad value: %s (%s)",
1213					optarg, errstr);
1214			break;
1215		case 'a':
1216			trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
1217			if (errstr)
1218				fatal("Invalid number of trials: %s (%s)",
1219					optarg, errstr);
1220			break;
1221		case 'M':
1222			memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
1223			if (errstr) {
1224				fatal("Memory limit is %s: %s", errstr, optarg);
1225			}
1226			break;
1227		case 'G':
1228			do_gen_candidates = 1;
1229			if (strlcpy(out_file, optarg, sizeof(out_file)) >=
1230			    sizeof(out_file))
1231				fatal("Output filename too long");
1232			break;
1233		case 'T':
1234			do_screen_candidates = 1;
1235			if (strlcpy(out_file, optarg, sizeof(out_file)) >=
1236			    sizeof(out_file))
1237				fatal("Output filename too long");
1238			break;
1239		case 'S':
1240			/* XXX - also compare length against bits */
1241			if (BN_hex2bn(&start, optarg) == 0)
1242				fatal("Invalid start point.");
1243			break;
1244		case '?':
1245		default:
1246			usage();
1247		}
1248	}
1249
1250	/* reinit */
1251	log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
1252
1253	if (optind < argc) {
1254		printf("Too many arguments.\n");
1255		usage();
1256	}
1257	if (change_passphrase && change_comment) {
1258		printf("Can only have one of -p and -c.\n");
1259		usage();
1260	}
1261	if (print_fingerprint && (delete_host || hash_hosts)) {
1262		printf("Cannot use -l with -D or -R.\n");
1263		usage();
1264	}
1265	if (delete_host || hash_hosts || find_host)
1266		do_known_hosts(pw, rr_hostname);
1267	if (print_fingerprint || print_bubblebabble)
1268		do_fingerprint(pw);
1269	if (change_passphrase)
1270		do_change_passphrase(pw);
1271	if (change_comment)
1272		do_change_comment(pw);
1273	if (convert_to_ssh2)
1274		do_convert_to_ssh2(pw);
1275	if (convert_from_ssh2)
1276		do_convert_from_ssh2(pw);
1277	if (print_public)
1278		do_print_public(pw);
1279	if (rr_hostname != NULL) {
1280		unsigned int n = 0;
1281
1282		if (have_identity) {
1283			n = do_print_resource_record(pw,
1284			    identity_file, rr_hostname);
1285			if (n == 0) {
1286				perror(identity_file);
1287				exit(1);
1288			}
1289			exit(0);
1290		} else {
1291
1292			n += do_print_resource_record(pw,
1293			    _PATH_HOST_RSA_KEY_FILE, rr_hostname);
1294			n += do_print_resource_record(pw,
1295			    _PATH_HOST_DSA_KEY_FILE, rr_hostname);
1296
1297			if (n == 0)
1298				fatal("no keys found.");
1299			exit(0);
1300		}
1301	}
1302	if (reader_id != NULL) {
1303#ifdef SMARTCARD
1304		if (download)
1305			do_download(pw, reader_id);
1306		else
1307			do_upload(pw, reader_id);
1308#else /* SMARTCARD */
1309		fatal("no support for smartcards.");
1310#endif /* SMARTCARD */
1311	}
1312
1313	if (do_gen_candidates) {
1314		FILE *out = fopen(out_file, "w");
1315
1316		if (out == NULL) {
1317			error("Couldn't open modulus candidate file \"%s\": %s",
1318			    out_file, strerror(errno));
1319			return (1);
1320		}
1321		if (bits == 0)
1322			bits = DEFAULT_BITS;
1323		if (gen_candidates(out, memory, bits, start) != 0)
1324			fatal("modulus candidate generation failed");
1325
1326		return (0);
1327	}
1328
1329	if (do_screen_candidates) {
1330		FILE *in;
1331		FILE *out = fopen(out_file, "w");
1332
1333		if (have_identity && strcmp(identity_file, "-") != 0) {
1334			if ((in = fopen(identity_file, "r")) == NULL) {
1335				fatal("Couldn't open modulus candidate "
1336				    "file \"%s\": %s", identity_file,
1337				    strerror(errno));
1338			}
1339		} else
1340			in = stdin;
1341
1342		if (out == NULL) {
1343			fatal("Couldn't open moduli file \"%s\": %s",
1344			    out_file, strerror(errno));
1345		}
1346		if (prime_test(in, out, trials, generator_wanted) != 0)
1347			fatal("modulus screening failed");
1348		return (0);
1349	}
1350
1351	arc4random_stir();
1352
1353	if (key_type_name == NULL)
1354		key_type_name = "rsa";
1355
1356	type = key_type_from_name(key_type_name);
1357	if (type == KEY_UNSPEC) {
1358		fprintf(stderr, "unknown key type %s\n", key_type_name);
1359		exit(1);
1360	}
1361	if (bits == 0)
1362		bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS;
1363	if (type == KEY_DSA && bits != 1024)
1364		fatal("DSA keys must be 1024 bits");
1365	if (!quiet)
1366		printf("Generating public/private %s key pair.\n", key_type_name);
1367	private = key_generate(type, bits);
1368	if (private == NULL) {
1369		fprintf(stderr, "key_generate failed");
1370		exit(1);
1371	}
1372	public  = key_from_private(private);
1373
1374	if (!have_identity)
1375		ask_filename(pw, "Enter file in which to save the key");
1376
1377	/* Create ~/.ssh directory if it doesn't already exist. */
1378	snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1379	if (strstr(identity_file, dotsshdir) != NULL &&
1380	    stat(dotsshdir, &st) < 0) {
1381		if (mkdir(dotsshdir, 0700) < 0)
1382			error("Could not create directory '%s'.", dotsshdir);
1383		else if (!quiet)
1384			printf("Created directory '%s'.\n", dotsshdir);
1385	}
1386	/* If the file already exists, ask the user to confirm. */
1387	if (stat(identity_file, &st) >= 0) {
1388		char yesno[3];
1389		printf("%s already exists.\n", identity_file);
1390		printf("Overwrite (y/n)? ");
1391		fflush(stdout);
1392		if (fgets(yesno, sizeof(yesno), stdin) == NULL)
1393			exit(1);
1394		if (yesno[0] != 'y' && yesno[0] != 'Y')
1395			exit(1);
1396	}
1397	/* Ask for a passphrase (twice). */
1398	if (identity_passphrase)
1399		passphrase1 = xstrdup(identity_passphrase);
1400	else if (identity_new_passphrase)
1401		passphrase1 = xstrdup(identity_new_passphrase);
1402	else {
1403passphrase_again:
1404		passphrase1 =
1405			read_passphrase("Enter passphrase (empty for no "
1406			    "passphrase): ", RP_ALLOW_STDIN);
1407		passphrase2 = read_passphrase("Enter same passphrase again: ",
1408		    RP_ALLOW_STDIN);
1409		if (strcmp(passphrase1, passphrase2) != 0) {
1410			/*
1411			 * The passphrases do not match.  Clear them and
1412			 * retry.
1413			 */
1414			memset(passphrase1, 0, strlen(passphrase1));
1415			memset(passphrase2, 0, strlen(passphrase2));
1416			xfree(passphrase1);
1417			xfree(passphrase2);
1418			printf("Passphrases do not match.  Try again.\n");
1419			goto passphrase_again;
1420		}
1421		/* Clear the other copy of the passphrase. */
1422		memset(passphrase2, 0, strlen(passphrase2));
1423		xfree(passphrase2);
1424	}
1425
1426	if (identity_comment) {
1427		strlcpy(comment, identity_comment, sizeof(comment));
1428	} else {
1429		/* Create default commend field for the passphrase. */
1430		snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
1431	}
1432
1433	/* Save the key with the given passphrase and comment. */
1434	if (!key_save_private(private, identity_file, passphrase1, comment)) {
1435		printf("Saving the key failed: %s.\n", identity_file);
1436		memset(passphrase1, 0, strlen(passphrase1));
1437		xfree(passphrase1);
1438		exit(1);
1439	}
1440	/* Clear the passphrase. */
1441	memset(passphrase1, 0, strlen(passphrase1));
1442	xfree(passphrase1);
1443
1444	/* Clear the private key and the random number generator. */
1445	key_free(private);
1446	arc4random_stir();
1447
1448	if (!quiet)
1449		printf("Your identification has been saved in %s.\n", identity_file);
1450
1451	strlcat(identity_file, ".pub", sizeof(identity_file));
1452	fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1453	if (fd == -1) {
1454		printf("Could not save your public key in %s\n", identity_file);
1455		exit(1);
1456	}
1457	f = fdopen(fd, "w");
1458	if (f == NULL) {
1459		printf("fdopen %s failed", identity_file);
1460		exit(1);
1461	}
1462	if (!key_write(public, f))
1463		fprintf(stderr, "write key failed");
1464	fprintf(f, " %s\n", comment);
1465	fclose(f);
1466
1467	if (!quiet) {
1468		char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
1469		char *ra = key_fingerprint(public, SSH_FP_MD5,
1470		    SSH_FP_RANDOMART);
1471		printf("Your public key has been saved in %s.\n",
1472		    identity_file);
1473		printf("The key fingerprint is:\n");
1474		printf("%s %s\n", fp, comment);
1475		printf("The key's randomart image is:\n");
1476		printf("%s\n", ra);
1477		xfree(ra);
1478		xfree(fp);
1479	}
1480
1481	key_free(public);
1482	exit(0);
1483}
1484