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