xref: /dragonfly/crypto/openssh/ssh-keygen.c (revision cb5eb4f1)
1*cb5eb4f1SPeter Avalos /* $OpenBSD: ssh-keygen.c,v 1.173 2009/02/21 19:32:04 tobias Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Author: Tatu Ylonen <ylo@cs.hut.fi>
418de8d7fSPeter Avalos  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
518de8d7fSPeter Avalos  *                    All rights reserved
618de8d7fSPeter Avalos  * Identity and host key generation and maintenance.
718de8d7fSPeter Avalos  *
818de8d7fSPeter Avalos  * As far as I am concerned, the code I have written for this software
918de8d7fSPeter Avalos  * can be used freely for any purpose.  Any derived versions of this
1018de8d7fSPeter Avalos  * software must be clearly marked as such, and if the derived work is
1118de8d7fSPeter Avalos  * incompatible with the protocol description in the RFC file, it must be
1218de8d7fSPeter Avalos  * called by a name other than "ssh" or "Secure Shell".
1318de8d7fSPeter Avalos  */
1418de8d7fSPeter Avalos 
1518de8d7fSPeter Avalos #include "includes.h"
1618de8d7fSPeter Avalos 
1718de8d7fSPeter Avalos #include <sys/types.h>
1818de8d7fSPeter Avalos #include <sys/socket.h>
1918de8d7fSPeter Avalos #include <sys/stat.h>
2018de8d7fSPeter Avalos #include <sys/param.h>
2118de8d7fSPeter Avalos 
2218de8d7fSPeter Avalos #include <openssl/evp.h>
2318de8d7fSPeter Avalos #include <openssl/pem.h>
2418de8d7fSPeter Avalos #include "openbsd-compat/openssl-compat.h"
2518de8d7fSPeter Avalos 
2618de8d7fSPeter Avalos #include <errno.h>
2718de8d7fSPeter Avalos #include <fcntl.h>
2818de8d7fSPeter Avalos #include <netdb.h>
2918de8d7fSPeter Avalos #ifdef HAVE_PATHS_H
3018de8d7fSPeter Avalos # include <paths.h>
3118de8d7fSPeter Avalos #endif
3218de8d7fSPeter Avalos #include <pwd.h>
3318de8d7fSPeter Avalos #include <stdarg.h>
3418de8d7fSPeter Avalos #include <stdio.h>
3518de8d7fSPeter Avalos #include <stdlib.h>
3618de8d7fSPeter Avalos #include <string.h>
3718de8d7fSPeter Avalos #include <unistd.h>
3818de8d7fSPeter Avalos 
3918de8d7fSPeter Avalos #include "xmalloc.h"
4018de8d7fSPeter Avalos #include "key.h"
4118de8d7fSPeter Avalos #include "rsa.h"
4218de8d7fSPeter Avalos #include "authfile.h"
4318de8d7fSPeter Avalos #include "uuencode.h"
4418de8d7fSPeter Avalos #include "buffer.h"
4518de8d7fSPeter Avalos #include "pathnames.h"
4618de8d7fSPeter Avalos #include "log.h"
4718de8d7fSPeter Avalos #include "misc.h"
4818de8d7fSPeter Avalos #include "match.h"
4918de8d7fSPeter Avalos #include "hostfile.h"
5018de8d7fSPeter Avalos #include "dns.h"
5118de8d7fSPeter Avalos 
5218de8d7fSPeter Avalos #ifdef SMARTCARD
5318de8d7fSPeter Avalos #include "scard.h"
5418de8d7fSPeter Avalos #endif
5518de8d7fSPeter Avalos 
5618de8d7fSPeter Avalos /* Number of bits in the RSA/DSA key.  This value can be set on the command line. */
5718de8d7fSPeter Avalos #define DEFAULT_BITS		2048
5818de8d7fSPeter Avalos #define DEFAULT_BITS_DSA	1024
5918de8d7fSPeter Avalos u_int32_t bits = 0;
6018de8d7fSPeter Avalos 
6118de8d7fSPeter Avalos /*
6218de8d7fSPeter Avalos  * Flag indicating that we just want to change the passphrase.  This can be
6318de8d7fSPeter Avalos  * set on the command line.
6418de8d7fSPeter Avalos  */
6518de8d7fSPeter Avalos int change_passphrase = 0;
6618de8d7fSPeter Avalos 
6718de8d7fSPeter Avalos /*
6818de8d7fSPeter Avalos  * Flag indicating that we just want to change the comment.  This can be set
6918de8d7fSPeter Avalos  * on the command line.
7018de8d7fSPeter Avalos  */
7118de8d7fSPeter Avalos int change_comment = 0;
7218de8d7fSPeter Avalos 
7318de8d7fSPeter Avalos int quiet = 0;
7418de8d7fSPeter Avalos 
7518de8d7fSPeter Avalos int log_level = SYSLOG_LEVEL_INFO;
7618de8d7fSPeter Avalos 
7718de8d7fSPeter Avalos /* Flag indicating that we want to hash a known_hosts file */
7818de8d7fSPeter Avalos int hash_hosts = 0;
7918de8d7fSPeter Avalos /* Flag indicating that we want lookup a host in known_hosts file */
8018de8d7fSPeter Avalos int find_host = 0;
8118de8d7fSPeter Avalos /* Flag indicating that we want to delete a host from a known_hosts file */
8218de8d7fSPeter Avalos int delete_host = 0;
8318de8d7fSPeter Avalos 
8418de8d7fSPeter Avalos /* Flag indicating that we just want to see the key fingerprint */
8518de8d7fSPeter Avalos int print_fingerprint = 0;
8618de8d7fSPeter Avalos int print_bubblebabble = 0;
8718de8d7fSPeter Avalos 
8818de8d7fSPeter Avalos /* The identity file name, given on the command line or entered by the user. */
8918de8d7fSPeter Avalos char identity_file[1024];
9018de8d7fSPeter Avalos int have_identity = 0;
9118de8d7fSPeter Avalos 
9218de8d7fSPeter Avalos /* This is set to the passphrase if given on the command line. */
9318de8d7fSPeter Avalos char *identity_passphrase = NULL;
9418de8d7fSPeter Avalos 
9518de8d7fSPeter Avalos /* This is set to the new passphrase if given on the command line. */
9618de8d7fSPeter Avalos char *identity_new_passphrase = NULL;
9718de8d7fSPeter Avalos 
9818de8d7fSPeter Avalos /* This is set to the new comment if given on the command line. */
9918de8d7fSPeter Avalos char *identity_comment = NULL;
10018de8d7fSPeter Avalos 
10118de8d7fSPeter Avalos /* Dump public key file in format used by real and the original SSH 2 */
10218de8d7fSPeter Avalos int convert_to_ssh2 = 0;
10318de8d7fSPeter Avalos int convert_from_ssh2 = 0;
10418de8d7fSPeter Avalos int print_public = 0;
10518de8d7fSPeter Avalos int print_generic = 0;
10618de8d7fSPeter Avalos 
10718de8d7fSPeter Avalos char *key_type_name = NULL;
10818de8d7fSPeter Avalos 
10918de8d7fSPeter Avalos /* argv0 */
11018de8d7fSPeter Avalos extern char *__progname;
11118de8d7fSPeter Avalos 
11218de8d7fSPeter Avalos char hostname[MAXHOSTNAMELEN];
11318de8d7fSPeter Avalos 
11418de8d7fSPeter Avalos /* moduli.c */
11518de8d7fSPeter Avalos int gen_candidates(FILE *, u_int32_t, u_int32_t, BIGNUM *);
11618de8d7fSPeter Avalos int prime_test(FILE *, FILE *, u_int32_t, u_int32_t);
11718de8d7fSPeter Avalos 
11818de8d7fSPeter Avalos static void
11918de8d7fSPeter Avalos ask_filename(struct passwd *pw, const char *prompt)
12018de8d7fSPeter Avalos {
12118de8d7fSPeter Avalos 	char buf[1024];
12218de8d7fSPeter Avalos 	char *name = NULL;
12318de8d7fSPeter Avalos 
12418de8d7fSPeter Avalos 	if (key_type_name == NULL)
12518de8d7fSPeter Avalos 		name = _PATH_SSH_CLIENT_ID_RSA;
12618de8d7fSPeter Avalos 	else {
12718de8d7fSPeter Avalos 		switch (key_type_from_name(key_type_name)) {
12818de8d7fSPeter Avalos 		case KEY_RSA1:
12918de8d7fSPeter Avalos 			name = _PATH_SSH_CLIENT_IDENTITY;
13018de8d7fSPeter Avalos 			break;
13118de8d7fSPeter Avalos 		case KEY_DSA:
13218de8d7fSPeter Avalos 			name = _PATH_SSH_CLIENT_ID_DSA;
13318de8d7fSPeter Avalos 			break;
13418de8d7fSPeter Avalos 		case KEY_RSA:
13518de8d7fSPeter Avalos 			name = _PATH_SSH_CLIENT_ID_RSA;
13618de8d7fSPeter Avalos 			break;
13718de8d7fSPeter Avalos 		default:
138*cb5eb4f1SPeter Avalos 			fprintf(stderr, "bad key type\n");
13918de8d7fSPeter Avalos 			exit(1);
14018de8d7fSPeter Avalos 			break;
14118de8d7fSPeter Avalos 		}
14218de8d7fSPeter Avalos 	}
14318de8d7fSPeter Avalos 	snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
14418de8d7fSPeter Avalos 	fprintf(stderr, "%s (%s): ", prompt, identity_file);
14518de8d7fSPeter Avalos 	if (fgets(buf, sizeof(buf), stdin) == NULL)
14618de8d7fSPeter Avalos 		exit(1);
14718de8d7fSPeter Avalos 	buf[strcspn(buf, "\n")] = '\0';
14818de8d7fSPeter Avalos 	if (strcmp(buf, "") != 0)
14918de8d7fSPeter Avalos 		strlcpy(identity_file, buf, sizeof(identity_file));
15018de8d7fSPeter Avalos 	have_identity = 1;
15118de8d7fSPeter Avalos }
15218de8d7fSPeter Avalos 
15318de8d7fSPeter Avalos static Key *
15418de8d7fSPeter Avalos load_identity(char *filename)
15518de8d7fSPeter Avalos {
15618de8d7fSPeter Avalos 	char *pass;
15718de8d7fSPeter Avalos 	Key *prv;
15818de8d7fSPeter Avalos 
15918de8d7fSPeter Avalos 	prv = key_load_private(filename, "", NULL);
16018de8d7fSPeter Avalos 	if (prv == NULL) {
16118de8d7fSPeter Avalos 		if (identity_passphrase)
16218de8d7fSPeter Avalos 			pass = xstrdup(identity_passphrase);
16318de8d7fSPeter Avalos 		else
16418de8d7fSPeter Avalos 			pass = read_passphrase("Enter passphrase: ",
16518de8d7fSPeter Avalos 			    RP_ALLOW_STDIN);
16618de8d7fSPeter Avalos 		prv = key_load_private(filename, pass, NULL);
16718de8d7fSPeter Avalos 		memset(pass, 0, strlen(pass));
16818de8d7fSPeter Avalos 		xfree(pass);
16918de8d7fSPeter Avalos 	}
17018de8d7fSPeter Avalos 	return prv;
17118de8d7fSPeter Avalos }
17218de8d7fSPeter Avalos 
17318de8d7fSPeter Avalos #define SSH_COM_PUBLIC_BEGIN		"---- BEGIN SSH2 PUBLIC KEY ----"
17418de8d7fSPeter Avalos #define SSH_COM_PUBLIC_END		"---- END SSH2 PUBLIC KEY ----"
17518de8d7fSPeter Avalos #define SSH_COM_PRIVATE_BEGIN		"---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
17618de8d7fSPeter Avalos #define	SSH_COM_PRIVATE_KEY_MAGIC	0x3f6ff9eb
17718de8d7fSPeter Avalos 
17818de8d7fSPeter Avalos static void
17918de8d7fSPeter Avalos do_convert_to_ssh2(struct passwd *pw)
18018de8d7fSPeter Avalos {
18118de8d7fSPeter Avalos 	Key *k;
18218de8d7fSPeter Avalos 	u_int len;
18318de8d7fSPeter Avalos 	u_char *blob;
18418de8d7fSPeter Avalos 	struct stat st;
18518de8d7fSPeter Avalos 
18618de8d7fSPeter Avalos 	if (!have_identity)
18718de8d7fSPeter Avalos 		ask_filename(pw, "Enter file in which the key is");
18818de8d7fSPeter Avalos 	if (stat(identity_file, &st) < 0) {
18918de8d7fSPeter Avalos 		perror(identity_file);
19018de8d7fSPeter Avalos 		exit(1);
19118de8d7fSPeter Avalos 	}
19218de8d7fSPeter Avalos 	if ((k = key_load_public(identity_file, NULL)) == NULL) {
19318de8d7fSPeter Avalos 		if ((k = load_identity(identity_file)) == NULL) {
19418de8d7fSPeter Avalos 			fprintf(stderr, "load failed\n");
19518de8d7fSPeter Avalos 			exit(1);
19618de8d7fSPeter Avalos 		}
19718de8d7fSPeter Avalos 	}
19818de8d7fSPeter Avalos 	if (k->type == KEY_RSA1) {
19918de8d7fSPeter Avalos 		fprintf(stderr, "version 1 keys are not supported\n");
20018de8d7fSPeter Avalos 		exit(1);
20118de8d7fSPeter Avalos 	}
20218de8d7fSPeter Avalos 	if (key_to_blob(k, &blob, &len) <= 0) {
20318de8d7fSPeter Avalos 		fprintf(stderr, "key_to_blob failed\n");
20418de8d7fSPeter Avalos 		exit(1);
20518de8d7fSPeter Avalos 	}
20618de8d7fSPeter Avalos 	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
20718de8d7fSPeter Avalos 	fprintf(stdout,
20818de8d7fSPeter Avalos 	    "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n",
20918de8d7fSPeter Avalos 	    key_size(k), key_type(k),
21018de8d7fSPeter Avalos 	    pw->pw_name, hostname);
21118de8d7fSPeter Avalos 	dump_base64(stdout, blob, len);
21218de8d7fSPeter Avalos 	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
21318de8d7fSPeter Avalos 	key_free(k);
21418de8d7fSPeter Avalos 	xfree(blob);
21518de8d7fSPeter Avalos 	exit(0);
21618de8d7fSPeter Avalos }
21718de8d7fSPeter Avalos 
21818de8d7fSPeter Avalos static void
21918de8d7fSPeter Avalos buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
22018de8d7fSPeter Avalos {
22118de8d7fSPeter Avalos 	u_int bignum_bits = buffer_get_int(b);
22218de8d7fSPeter Avalos 	u_int bytes = (bignum_bits + 7) / 8;
22318de8d7fSPeter Avalos 
22418de8d7fSPeter Avalos 	if (buffer_len(b) < bytes)
22518de8d7fSPeter Avalos 		fatal("buffer_get_bignum_bits: input buffer too small: "
22618de8d7fSPeter Avalos 		    "need %d have %d", bytes, buffer_len(b));
22718de8d7fSPeter Avalos 	if (BN_bin2bn(buffer_ptr(b), bytes, value) == NULL)
22818de8d7fSPeter Avalos 		fatal("buffer_get_bignum_bits: BN_bin2bn failed");
22918de8d7fSPeter Avalos 	buffer_consume(b, bytes);
23018de8d7fSPeter Avalos }
23118de8d7fSPeter Avalos 
23218de8d7fSPeter Avalos static Key *
23318de8d7fSPeter Avalos do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
23418de8d7fSPeter Avalos {
23518de8d7fSPeter Avalos 	Buffer b;
23618de8d7fSPeter Avalos 	Key *key = NULL;
23718de8d7fSPeter Avalos 	char *type, *cipher;
23818de8d7fSPeter Avalos 	u_char *sig, data[] = "abcde12345";
23918de8d7fSPeter Avalos 	int magic, rlen, ktype, i1, i2, i3, i4;
24018de8d7fSPeter Avalos 	u_int slen;
24118de8d7fSPeter Avalos 	u_long e;
24218de8d7fSPeter Avalos 
24318de8d7fSPeter Avalos 	buffer_init(&b);
24418de8d7fSPeter Avalos 	buffer_append(&b, blob, blen);
24518de8d7fSPeter Avalos 
24618de8d7fSPeter Avalos 	magic = buffer_get_int(&b);
24718de8d7fSPeter Avalos 	if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
24818de8d7fSPeter Avalos 		error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
24918de8d7fSPeter Avalos 		buffer_free(&b);
25018de8d7fSPeter Avalos 		return NULL;
25118de8d7fSPeter Avalos 	}
25218de8d7fSPeter Avalos 	i1 = buffer_get_int(&b);
25318de8d7fSPeter Avalos 	type   = buffer_get_string(&b, NULL);
25418de8d7fSPeter Avalos 	cipher = buffer_get_string(&b, NULL);
25518de8d7fSPeter Avalos 	i2 = buffer_get_int(&b);
25618de8d7fSPeter Avalos 	i3 = buffer_get_int(&b);
25718de8d7fSPeter Avalos 	i4 = buffer_get_int(&b);
25818de8d7fSPeter Avalos 	debug("ignore (%d %d %d %d)", i1, i2, i3, i4);
25918de8d7fSPeter Avalos 	if (strcmp(cipher, "none") != 0) {
26018de8d7fSPeter Avalos 		error("unsupported cipher %s", cipher);
26118de8d7fSPeter Avalos 		xfree(cipher);
26218de8d7fSPeter Avalos 		buffer_free(&b);
26318de8d7fSPeter Avalos 		xfree(type);
26418de8d7fSPeter Avalos 		return NULL;
26518de8d7fSPeter Avalos 	}
26618de8d7fSPeter Avalos 	xfree(cipher);
26718de8d7fSPeter Avalos 
26818de8d7fSPeter Avalos 	if (strstr(type, "dsa")) {
26918de8d7fSPeter Avalos 		ktype = KEY_DSA;
27018de8d7fSPeter Avalos 	} else if (strstr(type, "rsa")) {
27118de8d7fSPeter Avalos 		ktype = KEY_RSA;
27218de8d7fSPeter Avalos 	} else {
27318de8d7fSPeter Avalos 		buffer_free(&b);
27418de8d7fSPeter Avalos 		xfree(type);
27518de8d7fSPeter Avalos 		return NULL;
27618de8d7fSPeter Avalos 	}
27718de8d7fSPeter Avalos 	key = key_new_private(ktype);
27818de8d7fSPeter Avalos 	xfree(type);
27918de8d7fSPeter Avalos 
28018de8d7fSPeter Avalos 	switch (key->type) {
28118de8d7fSPeter Avalos 	case KEY_DSA:
28218de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->dsa->p);
28318de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->dsa->g);
28418de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->dsa->q);
28518de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->dsa->pub_key);
28618de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->dsa->priv_key);
28718de8d7fSPeter Avalos 		break;
28818de8d7fSPeter Avalos 	case KEY_RSA:
28918de8d7fSPeter Avalos 		e = buffer_get_char(&b);
29018de8d7fSPeter Avalos 		debug("e %lx", e);
29118de8d7fSPeter Avalos 		if (e < 30) {
29218de8d7fSPeter Avalos 			e <<= 8;
29318de8d7fSPeter Avalos 			e += buffer_get_char(&b);
29418de8d7fSPeter Avalos 			debug("e %lx", e);
29518de8d7fSPeter Avalos 			e <<= 8;
29618de8d7fSPeter Avalos 			e += buffer_get_char(&b);
29718de8d7fSPeter Avalos 			debug("e %lx", e);
29818de8d7fSPeter Avalos 		}
29918de8d7fSPeter Avalos 		if (!BN_set_word(key->rsa->e, e)) {
30018de8d7fSPeter Avalos 			buffer_free(&b);
30118de8d7fSPeter Avalos 			key_free(key);
30218de8d7fSPeter Avalos 			return NULL;
30318de8d7fSPeter Avalos 		}
30418de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->rsa->d);
30518de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->rsa->n);
30618de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->rsa->iqmp);
30718de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->rsa->q);
30818de8d7fSPeter Avalos 		buffer_get_bignum_bits(&b, key->rsa->p);
30918de8d7fSPeter Avalos 		rsa_generate_additional_parameters(key->rsa);
31018de8d7fSPeter Avalos 		break;
31118de8d7fSPeter Avalos 	}
31218de8d7fSPeter Avalos 	rlen = buffer_len(&b);
31318de8d7fSPeter Avalos 	if (rlen != 0)
31418de8d7fSPeter Avalos 		error("do_convert_private_ssh2_from_blob: "
31518de8d7fSPeter Avalos 		    "remaining bytes in key blob %d", rlen);
31618de8d7fSPeter Avalos 	buffer_free(&b);
31718de8d7fSPeter Avalos 
31818de8d7fSPeter Avalos 	/* try the key */
31918de8d7fSPeter Avalos 	key_sign(key, &sig, &slen, data, sizeof(data));
32018de8d7fSPeter Avalos 	key_verify(key, sig, slen, data, sizeof(data));
32118de8d7fSPeter Avalos 	xfree(sig);
32218de8d7fSPeter Avalos 	return key;
32318de8d7fSPeter Avalos }
32418de8d7fSPeter Avalos 
32518de8d7fSPeter Avalos static int
32618de8d7fSPeter Avalos get_line(FILE *fp, char *line, size_t len)
32718de8d7fSPeter Avalos {
32818de8d7fSPeter Avalos 	int c;
32918de8d7fSPeter Avalos 	size_t pos = 0;
33018de8d7fSPeter Avalos 
33118de8d7fSPeter Avalos 	line[0] = '\0';
33218de8d7fSPeter Avalos 	while ((c = fgetc(fp)) != EOF) {
33318de8d7fSPeter Avalos 		if (pos >= len - 1) {
33418de8d7fSPeter Avalos 			fprintf(stderr, "input line too long.\n");
33518de8d7fSPeter Avalos 			exit(1);
33618de8d7fSPeter Avalos 		}
33718de8d7fSPeter Avalos 		switch (c) {
33818de8d7fSPeter Avalos 		case '\r':
33918de8d7fSPeter Avalos 			c = fgetc(fp);
34018de8d7fSPeter Avalos 			if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) {
34118de8d7fSPeter Avalos 				fprintf(stderr, "unget: %s\n", strerror(errno));
34218de8d7fSPeter Avalos 				exit(1);
34318de8d7fSPeter Avalos 			}
34418de8d7fSPeter Avalos 			return pos;
34518de8d7fSPeter Avalos 		case '\n':
34618de8d7fSPeter Avalos 			return pos;
34718de8d7fSPeter Avalos 		}
34818de8d7fSPeter Avalos 		line[pos++] = c;
34918de8d7fSPeter Avalos 		line[pos] = '\0';
35018de8d7fSPeter Avalos 	}
35118de8d7fSPeter Avalos 	/* We reached EOF */
35218de8d7fSPeter Avalos 	return -1;
35318de8d7fSPeter Avalos }
35418de8d7fSPeter Avalos 
35518de8d7fSPeter Avalos static void
35618de8d7fSPeter Avalos do_convert_from_ssh2(struct passwd *pw)
35718de8d7fSPeter Avalos {
35818de8d7fSPeter Avalos 	Key *k;
35918de8d7fSPeter Avalos 	int blen;
36018de8d7fSPeter Avalos 	u_int len;
36118de8d7fSPeter Avalos 	char line[1024];
36218de8d7fSPeter Avalos 	u_char blob[8096];
36318de8d7fSPeter Avalos 	char encoded[8096];
36418de8d7fSPeter Avalos 	struct stat st;
36518de8d7fSPeter Avalos 	int escaped = 0, private = 0, ok;
36618de8d7fSPeter Avalos 	FILE *fp;
36718de8d7fSPeter Avalos 
36818de8d7fSPeter Avalos 	if (!have_identity)
36918de8d7fSPeter Avalos 		ask_filename(pw, "Enter file in which the key is");
37018de8d7fSPeter Avalos 	if (stat(identity_file, &st) < 0) {
37118de8d7fSPeter Avalos 		perror(identity_file);
37218de8d7fSPeter Avalos 		exit(1);
37318de8d7fSPeter Avalos 	}
37418de8d7fSPeter Avalos 	fp = fopen(identity_file, "r");
37518de8d7fSPeter Avalos 	if (fp == NULL) {
37618de8d7fSPeter Avalos 		perror(identity_file);
37718de8d7fSPeter Avalos 		exit(1);
37818de8d7fSPeter Avalos 	}
37918de8d7fSPeter Avalos 	encoded[0] = '\0';
38018de8d7fSPeter Avalos 	while ((blen = get_line(fp, line, sizeof(line))) != -1) {
38118de8d7fSPeter Avalos 		if (line[blen - 1] == '\\')
38218de8d7fSPeter Avalos 			escaped++;
38318de8d7fSPeter Avalos 		if (strncmp(line, "----", 4) == 0 ||
38418de8d7fSPeter Avalos 		    strstr(line, ": ") != NULL) {
38518de8d7fSPeter Avalos 			if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
38618de8d7fSPeter Avalos 				private = 1;
38718de8d7fSPeter Avalos 			if (strstr(line, " END ") != NULL) {
38818de8d7fSPeter Avalos 				break;
38918de8d7fSPeter Avalos 			}
39018de8d7fSPeter Avalos 			/* fprintf(stderr, "ignore: %s", line); */
39118de8d7fSPeter Avalos 			continue;
39218de8d7fSPeter Avalos 		}
39318de8d7fSPeter Avalos 		if (escaped) {
39418de8d7fSPeter Avalos 			escaped--;
39518de8d7fSPeter Avalos 			/* fprintf(stderr, "escaped: %s", line); */
39618de8d7fSPeter Avalos 			continue;
39718de8d7fSPeter Avalos 		}
39818de8d7fSPeter Avalos 		strlcat(encoded, line, sizeof(encoded));
39918de8d7fSPeter Avalos 	}
40018de8d7fSPeter Avalos 	len = strlen(encoded);
40118de8d7fSPeter Avalos 	if (((len % 4) == 3) &&
40218de8d7fSPeter Avalos 	    (encoded[len-1] == '=') &&
40318de8d7fSPeter Avalos 	    (encoded[len-2] == '=') &&
40418de8d7fSPeter Avalos 	    (encoded[len-3] == '='))
40518de8d7fSPeter Avalos 		encoded[len-3] = '\0';
40618de8d7fSPeter Avalos 	blen = uudecode(encoded, blob, sizeof(blob));
40718de8d7fSPeter Avalos 	if (blen < 0) {
40818de8d7fSPeter Avalos 		fprintf(stderr, "uudecode failed.\n");
40918de8d7fSPeter Avalos 		exit(1);
41018de8d7fSPeter Avalos 	}
41118de8d7fSPeter Avalos 	k = private ?
41218de8d7fSPeter Avalos 	    do_convert_private_ssh2_from_blob(blob, blen) :
41318de8d7fSPeter Avalos 	    key_from_blob(blob, blen);
41418de8d7fSPeter Avalos 	if (k == NULL) {
41518de8d7fSPeter Avalos 		fprintf(stderr, "decode blob failed.\n");
41618de8d7fSPeter Avalos 		exit(1);
41718de8d7fSPeter Avalos 	}
41818de8d7fSPeter Avalos 	ok = private ?
41918de8d7fSPeter Avalos 	    (k->type == KEY_DSA ?
42018de8d7fSPeter Avalos 		 PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
42118de8d7fSPeter Avalos 		 PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
42218de8d7fSPeter Avalos 	    key_write(k, stdout);
42318de8d7fSPeter Avalos 	if (!ok) {
424*cb5eb4f1SPeter Avalos 		fprintf(stderr, "key write failed\n");
42518de8d7fSPeter Avalos 		exit(1);
42618de8d7fSPeter Avalos 	}
42718de8d7fSPeter Avalos 	key_free(k);
42818de8d7fSPeter Avalos 	if (!private)
42918de8d7fSPeter Avalos 		fprintf(stdout, "\n");
43018de8d7fSPeter Avalos 	fclose(fp);
43118de8d7fSPeter Avalos 	exit(0);
43218de8d7fSPeter Avalos }
43318de8d7fSPeter Avalos 
43418de8d7fSPeter Avalos static void
43518de8d7fSPeter Avalos do_print_public(struct passwd *pw)
43618de8d7fSPeter Avalos {
43718de8d7fSPeter Avalos 	Key *prv;
43818de8d7fSPeter Avalos 	struct stat st;
43918de8d7fSPeter Avalos 
44018de8d7fSPeter Avalos 	if (!have_identity)
44118de8d7fSPeter Avalos 		ask_filename(pw, "Enter file in which the key is");
44218de8d7fSPeter Avalos 	if (stat(identity_file, &st) < 0) {
44318de8d7fSPeter Avalos 		perror(identity_file);
44418de8d7fSPeter Avalos 		exit(1);
44518de8d7fSPeter Avalos 	}
44618de8d7fSPeter Avalos 	prv = load_identity(identity_file);
44718de8d7fSPeter Avalos 	if (prv == NULL) {
44818de8d7fSPeter Avalos 		fprintf(stderr, "load failed\n");
44918de8d7fSPeter Avalos 		exit(1);
45018de8d7fSPeter Avalos 	}
45118de8d7fSPeter Avalos 	if (!key_write(prv, stdout))
45218de8d7fSPeter Avalos 		fprintf(stderr, "key_write failed");
45318de8d7fSPeter Avalos 	key_free(prv);
45418de8d7fSPeter Avalos 	fprintf(stdout, "\n");
45518de8d7fSPeter Avalos 	exit(0);
45618de8d7fSPeter Avalos }
45718de8d7fSPeter Avalos 
45818de8d7fSPeter Avalos #ifdef SMARTCARD
45918de8d7fSPeter Avalos static void
46018de8d7fSPeter Avalos do_upload(struct passwd *pw, const char *sc_reader_id)
46118de8d7fSPeter Avalos {
46218de8d7fSPeter Avalos 	Key *prv = NULL;
46318de8d7fSPeter Avalos 	struct stat st;
46418de8d7fSPeter Avalos 	int ret;
46518de8d7fSPeter Avalos 
46618de8d7fSPeter Avalos 	if (!have_identity)
46718de8d7fSPeter Avalos 		ask_filename(pw, "Enter file in which the key is");
46818de8d7fSPeter Avalos 	if (stat(identity_file, &st) < 0) {
46918de8d7fSPeter Avalos 		perror(identity_file);
47018de8d7fSPeter Avalos 		exit(1);
47118de8d7fSPeter Avalos 	}
47218de8d7fSPeter Avalos 	prv = load_identity(identity_file);
47318de8d7fSPeter Avalos 	if (prv == NULL) {
47418de8d7fSPeter Avalos 		error("load failed");
47518de8d7fSPeter Avalos 		exit(1);
47618de8d7fSPeter Avalos 	}
47718de8d7fSPeter Avalos 	ret = sc_put_key(prv, sc_reader_id);
47818de8d7fSPeter Avalos 	key_free(prv);
47918de8d7fSPeter Avalos 	if (ret < 0)
48018de8d7fSPeter Avalos 		exit(1);
48118de8d7fSPeter Avalos 	logit("loading key done");
48218de8d7fSPeter Avalos 	exit(0);
48318de8d7fSPeter Avalos }
48418de8d7fSPeter Avalos 
48518de8d7fSPeter Avalos static void
48618de8d7fSPeter Avalos do_download(struct passwd *pw, const char *sc_reader_id)
48718de8d7fSPeter Avalos {
48818de8d7fSPeter Avalos 	Key **keys = NULL;
48918de8d7fSPeter Avalos 	int i;
49018de8d7fSPeter Avalos 
49118de8d7fSPeter Avalos 	keys = sc_get_keys(sc_reader_id, NULL);
49218de8d7fSPeter Avalos 	if (keys == NULL)
49318de8d7fSPeter Avalos 		fatal("cannot read public key from smartcard");
49418de8d7fSPeter Avalos 	for (i = 0; keys[i]; i++) {
49518de8d7fSPeter Avalos 		key_write(keys[i], stdout);
49618de8d7fSPeter Avalos 		key_free(keys[i]);
49718de8d7fSPeter Avalos 		fprintf(stdout, "\n");
49818de8d7fSPeter Avalos 	}
49918de8d7fSPeter Avalos 	xfree(keys);
50018de8d7fSPeter Avalos 	exit(0);
50118de8d7fSPeter Avalos }
50218de8d7fSPeter Avalos #endif /* SMARTCARD */
50318de8d7fSPeter Avalos 
50418de8d7fSPeter Avalos static void
50518de8d7fSPeter Avalos do_fingerprint(struct passwd *pw)
50618de8d7fSPeter Avalos {
50718de8d7fSPeter Avalos 	FILE *f;
50818de8d7fSPeter Avalos 	Key *public;
50918de8d7fSPeter Avalos 	char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
51018de8d7fSPeter Avalos 	int i, skip = 0, num = 0, invalid = 1;
51118de8d7fSPeter Avalos 	enum fp_rep rep;
51218de8d7fSPeter Avalos 	enum fp_type fptype;
51318de8d7fSPeter Avalos 	struct stat st;
51418de8d7fSPeter Avalos 
51518de8d7fSPeter Avalos 	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
51618de8d7fSPeter Avalos 	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
51718de8d7fSPeter Avalos 
51818de8d7fSPeter Avalos 	if (!have_identity)
51918de8d7fSPeter Avalos 		ask_filename(pw, "Enter file in which the key is");
52018de8d7fSPeter Avalos 	if (stat(identity_file, &st) < 0) {
52118de8d7fSPeter Avalos 		perror(identity_file);
52218de8d7fSPeter Avalos 		exit(1);
52318de8d7fSPeter Avalos 	}
52418de8d7fSPeter Avalos 	public = key_load_public(identity_file, &comment);
52518de8d7fSPeter Avalos 	if (public != NULL) {
52618de8d7fSPeter Avalos 		fp = key_fingerprint(public, fptype, rep);
52718de8d7fSPeter Avalos 		ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
52818de8d7fSPeter Avalos 		printf("%u %s %s (%s)\n", key_size(public), fp, comment,
52918de8d7fSPeter Avalos 		    key_type(public));
53018de8d7fSPeter Avalos 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
53118de8d7fSPeter Avalos 			printf("%s\n", ra);
53218de8d7fSPeter Avalos 		key_free(public);
53318de8d7fSPeter Avalos 		xfree(comment);
53418de8d7fSPeter Avalos 		xfree(ra);
53518de8d7fSPeter Avalos 		xfree(fp);
53618de8d7fSPeter Avalos 		exit(0);
53718de8d7fSPeter Avalos 	}
53818de8d7fSPeter Avalos 	if (comment) {
53918de8d7fSPeter Avalos 		xfree(comment);
54018de8d7fSPeter Avalos 		comment = NULL;
54118de8d7fSPeter Avalos 	}
54218de8d7fSPeter Avalos 
54318de8d7fSPeter Avalos 	f = fopen(identity_file, "r");
54418de8d7fSPeter Avalos 	if (f != NULL) {
54518de8d7fSPeter Avalos 		while (fgets(line, sizeof(line), f)) {
54618de8d7fSPeter Avalos 			if ((cp = strchr(line, '\n')) == NULL) {
54718de8d7fSPeter Avalos 				error("line %d too long: %.40s...",
54818de8d7fSPeter Avalos 				    num + 1, line);
54918de8d7fSPeter Avalos 				skip = 1;
55018de8d7fSPeter Avalos 				continue;
55118de8d7fSPeter Avalos 			}
55218de8d7fSPeter Avalos 			num++;
55318de8d7fSPeter Avalos 			if (skip) {
55418de8d7fSPeter Avalos 				skip = 0;
55518de8d7fSPeter Avalos 				continue;
55618de8d7fSPeter Avalos 			}
55718de8d7fSPeter Avalos 			*cp = '\0';
55818de8d7fSPeter Avalos 
55918de8d7fSPeter Avalos 			/* Skip leading whitespace, empty and comment lines. */
56018de8d7fSPeter Avalos 			for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
56118de8d7fSPeter Avalos 				;
56218de8d7fSPeter Avalos 			if (!*cp || *cp == '\n' || *cp == '#')
56318de8d7fSPeter Avalos 				continue;
56418de8d7fSPeter Avalos 			i = strtol(cp, &ep, 10);
56518de8d7fSPeter Avalos 			if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
56618de8d7fSPeter Avalos 				int quoted = 0;
56718de8d7fSPeter Avalos 				comment = cp;
56818de8d7fSPeter Avalos 				for (; *cp && (quoted || (*cp != ' ' &&
56918de8d7fSPeter Avalos 				    *cp != '\t')); cp++) {
57018de8d7fSPeter Avalos 					if (*cp == '\\' && cp[1] == '"')
57118de8d7fSPeter Avalos 						cp++;	/* Skip both */
57218de8d7fSPeter Avalos 					else if (*cp == '"')
57318de8d7fSPeter Avalos 						quoted = !quoted;
57418de8d7fSPeter Avalos 				}
57518de8d7fSPeter Avalos 				if (!*cp)
57618de8d7fSPeter Avalos 					continue;
57718de8d7fSPeter Avalos 				*cp++ = '\0';
57818de8d7fSPeter Avalos 			}
57918de8d7fSPeter Avalos 			ep = cp;
58018de8d7fSPeter Avalos 			public = key_new(KEY_RSA1);
58118de8d7fSPeter Avalos 			if (key_read(public, &cp) != 1) {
58218de8d7fSPeter Avalos 				cp = ep;
58318de8d7fSPeter Avalos 				key_free(public);
58418de8d7fSPeter Avalos 				public = key_new(KEY_UNSPEC);
58518de8d7fSPeter Avalos 				if (key_read(public, &cp) != 1) {
58618de8d7fSPeter Avalos 					key_free(public);
58718de8d7fSPeter Avalos 					continue;
58818de8d7fSPeter Avalos 				}
58918de8d7fSPeter Avalos 			}
59018de8d7fSPeter Avalos 			comment = *cp ? cp : comment;
59118de8d7fSPeter Avalos 			fp = key_fingerprint(public, fptype, rep);
59218de8d7fSPeter Avalos 			ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
59318de8d7fSPeter Avalos 			printf("%u %s %s (%s)\n", key_size(public), fp,
59418de8d7fSPeter Avalos 			    comment ? comment : "no comment", key_type(public));
59518de8d7fSPeter Avalos 			if (log_level >= SYSLOG_LEVEL_VERBOSE)
59618de8d7fSPeter Avalos 				printf("%s\n", ra);
59718de8d7fSPeter Avalos 			xfree(ra);
59818de8d7fSPeter Avalos 			xfree(fp);
59918de8d7fSPeter Avalos 			key_free(public);
60018de8d7fSPeter Avalos 			invalid = 0;
60118de8d7fSPeter Avalos 		}
60218de8d7fSPeter Avalos 		fclose(f);
60318de8d7fSPeter Avalos 	}
60418de8d7fSPeter Avalos 	if (invalid) {
60518de8d7fSPeter Avalos 		printf("%s is not a public key file.\n", identity_file);
60618de8d7fSPeter Avalos 		exit(1);
60718de8d7fSPeter Avalos 	}
60818de8d7fSPeter Avalos 	exit(0);
60918de8d7fSPeter Avalos }
61018de8d7fSPeter Avalos 
61118de8d7fSPeter Avalos static void
61218de8d7fSPeter Avalos print_host(FILE *f, const char *name, Key *public, int hash)
61318de8d7fSPeter Avalos {
61418de8d7fSPeter Avalos 	if (print_fingerprint) {
61518de8d7fSPeter Avalos 		enum fp_rep rep;
61618de8d7fSPeter Avalos 		enum fp_type fptype;
61718de8d7fSPeter Avalos 		char *fp, *ra;
61818de8d7fSPeter Avalos 
61918de8d7fSPeter Avalos 		fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
62018de8d7fSPeter Avalos 		rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
62118de8d7fSPeter Avalos 		fp = key_fingerprint(public, fptype, rep);
62218de8d7fSPeter Avalos 		ra = key_fingerprint(public, fptype, SSH_FP_RANDOMART);
62318de8d7fSPeter Avalos 		printf("%u %s %s (%s)\n", key_size(public), fp, name,
62418de8d7fSPeter Avalos 		    key_type(public));
62518de8d7fSPeter Avalos 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
62618de8d7fSPeter Avalos 			printf("%s\n", ra);
62718de8d7fSPeter Avalos 		xfree(ra);
62818de8d7fSPeter Avalos 		xfree(fp);
62918de8d7fSPeter Avalos 	} else {
63018de8d7fSPeter Avalos 		if (hash && (name = host_hash(name, NULL, 0)) == NULL)
63118de8d7fSPeter Avalos 			fatal("hash_host failed");
63218de8d7fSPeter Avalos 		fprintf(f, "%s ", name);
63318de8d7fSPeter Avalos 		if (!key_write(public, f))
63418de8d7fSPeter Avalos 			fatal("key_write failed");
63518de8d7fSPeter Avalos 		fprintf(f, "\n");
63618de8d7fSPeter Avalos 	}
63718de8d7fSPeter Avalos }
63818de8d7fSPeter Avalos 
63918de8d7fSPeter Avalos static void
64018de8d7fSPeter Avalos do_known_hosts(struct passwd *pw, const char *name)
64118de8d7fSPeter Avalos {
64218de8d7fSPeter Avalos 	FILE *in, *out = stdout;
64318de8d7fSPeter Avalos 	Key *public;
64418de8d7fSPeter Avalos 	char *cp, *cp2, *kp, *kp2;
64518de8d7fSPeter Avalos 	char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
64618de8d7fSPeter Avalos 	int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
64718de8d7fSPeter Avalos 
64818de8d7fSPeter Avalos 	if (!have_identity) {
64918de8d7fSPeter Avalos 		cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
65018de8d7fSPeter Avalos 		if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
65118de8d7fSPeter Avalos 		    sizeof(identity_file))
65218de8d7fSPeter Avalos 			fatal("Specified known hosts path too long");
65318de8d7fSPeter Avalos 		xfree(cp);
65418de8d7fSPeter Avalos 		have_identity = 1;
65518de8d7fSPeter Avalos 	}
65618de8d7fSPeter Avalos 	if ((in = fopen(identity_file, "r")) == NULL)
65718de8d7fSPeter Avalos 		fatal("fopen: %s", strerror(errno));
65818de8d7fSPeter Avalos 
65918de8d7fSPeter Avalos 	/*
66018de8d7fSPeter Avalos 	 * Find hosts goes to stdout, hash and deletions happen in-place
66118de8d7fSPeter Avalos 	 * A corner case is ssh-keygen -HF foo, which should go to stdout
66218de8d7fSPeter Avalos 	 */
66318de8d7fSPeter Avalos 	if (!find_host && (hash_hosts || delete_host)) {
66418de8d7fSPeter Avalos 		if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
66518de8d7fSPeter Avalos 		    strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
66618de8d7fSPeter Avalos 		    strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
66718de8d7fSPeter Avalos 		    strlcat(old, ".old", sizeof(old)) >= sizeof(old))
66818de8d7fSPeter Avalos 			fatal("known_hosts path too long");
66918de8d7fSPeter Avalos 		umask(077);
67018de8d7fSPeter Avalos 		if ((c = mkstemp(tmp)) == -1)
67118de8d7fSPeter Avalos 			fatal("mkstemp: %s", strerror(errno));
67218de8d7fSPeter Avalos 		if ((out = fdopen(c, "w")) == NULL) {
67318de8d7fSPeter Avalos 			c = errno;
67418de8d7fSPeter Avalos 			unlink(tmp);
67518de8d7fSPeter Avalos 			fatal("fdopen: %s", strerror(c));
67618de8d7fSPeter Avalos 		}
67718de8d7fSPeter Avalos 		inplace = 1;
67818de8d7fSPeter Avalos 	}
67918de8d7fSPeter Avalos 
68018de8d7fSPeter Avalos 	while (fgets(line, sizeof(line), in)) {
68118de8d7fSPeter Avalos 		if ((cp = strchr(line, '\n')) == NULL) {
68218de8d7fSPeter Avalos 			error("line %d too long: %.40s...", num + 1, line);
68318de8d7fSPeter Avalos 			skip = 1;
68418de8d7fSPeter Avalos 			invalid = 1;
68518de8d7fSPeter Avalos 			continue;
68618de8d7fSPeter Avalos 		}
68718de8d7fSPeter Avalos 		num++;
68818de8d7fSPeter Avalos 		if (skip) {
68918de8d7fSPeter Avalos 			skip = 0;
69018de8d7fSPeter Avalos 			continue;
69118de8d7fSPeter Avalos 		}
69218de8d7fSPeter Avalos 		*cp = '\0';
69318de8d7fSPeter Avalos 
69418de8d7fSPeter Avalos 		/* Skip leading whitespace, empty and comment lines. */
69518de8d7fSPeter Avalos 		for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
69618de8d7fSPeter Avalos 			;
69718de8d7fSPeter Avalos 		if (!*cp || *cp == '\n' || *cp == '#') {
69818de8d7fSPeter Avalos 			if (inplace)
69918de8d7fSPeter Avalos 				fprintf(out, "%s\n", cp);
70018de8d7fSPeter Avalos 			continue;
70118de8d7fSPeter Avalos 		}
70218de8d7fSPeter Avalos 		/* Find the end of the host name portion. */
70318de8d7fSPeter Avalos 		for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
70418de8d7fSPeter Avalos 			;
70518de8d7fSPeter Avalos 		if (*kp == '\0' || *(kp + 1) == '\0') {
70618de8d7fSPeter Avalos 			error("line %d missing key: %.40s...",
70718de8d7fSPeter Avalos 			    num, line);
70818de8d7fSPeter Avalos 			invalid = 1;
70918de8d7fSPeter Avalos 			continue;
71018de8d7fSPeter Avalos 		}
71118de8d7fSPeter Avalos 		*kp++ = '\0';
71218de8d7fSPeter Avalos 		kp2 = kp;
71318de8d7fSPeter Avalos 
71418de8d7fSPeter Avalos 		public = key_new(KEY_RSA1);
71518de8d7fSPeter Avalos 		if (key_read(public, &kp) != 1) {
71618de8d7fSPeter Avalos 			kp = kp2;
71718de8d7fSPeter Avalos 			key_free(public);
71818de8d7fSPeter Avalos 			public = key_new(KEY_UNSPEC);
71918de8d7fSPeter Avalos 			if (key_read(public, &kp) != 1) {
72018de8d7fSPeter Avalos 				error("line %d invalid key: %.40s...",
72118de8d7fSPeter Avalos 				    num, line);
72218de8d7fSPeter Avalos 				key_free(public);
72318de8d7fSPeter Avalos 				invalid = 1;
72418de8d7fSPeter Avalos 				continue;
72518de8d7fSPeter Avalos 			}
72618de8d7fSPeter Avalos 		}
72718de8d7fSPeter Avalos 
72818de8d7fSPeter Avalos 		if (*cp == HASH_DELIM) {
72918de8d7fSPeter Avalos 			if (find_host || delete_host) {
73018de8d7fSPeter Avalos 				cp2 = host_hash(name, cp, strlen(cp));
73118de8d7fSPeter Avalos 				if (cp2 == NULL) {
73218de8d7fSPeter Avalos 					error("line %d: invalid hashed "
73318de8d7fSPeter Avalos 					    "name: %.64s...", num, line);
73418de8d7fSPeter Avalos 					invalid = 1;
73518de8d7fSPeter Avalos 					continue;
73618de8d7fSPeter Avalos 				}
73718de8d7fSPeter Avalos 				c = (strcmp(cp2, cp) == 0);
73818de8d7fSPeter Avalos 				if (find_host && c) {
73918de8d7fSPeter Avalos 					printf("# Host %s found: "
74018de8d7fSPeter Avalos 					    "line %d type %s\n", name,
74118de8d7fSPeter Avalos 					    num, key_type(public));
74218de8d7fSPeter Avalos 					print_host(out, cp, public, 0);
74318de8d7fSPeter Avalos 				}
74418de8d7fSPeter Avalos 				if (delete_host && !c)
74518de8d7fSPeter Avalos 					print_host(out, cp, public, 0);
74618de8d7fSPeter Avalos 			} else if (hash_hosts)
74718de8d7fSPeter Avalos 				print_host(out, cp, public, 0);
74818de8d7fSPeter Avalos 		} else {
74918de8d7fSPeter Avalos 			if (find_host || delete_host) {
75018de8d7fSPeter Avalos 				c = (match_hostname(name, cp,
75118de8d7fSPeter Avalos 				    strlen(cp)) == 1);
75218de8d7fSPeter Avalos 				if (find_host && c) {
75318de8d7fSPeter Avalos 					printf("# Host %s found: "
75418de8d7fSPeter Avalos 					    "line %d type %s\n", name,
75518de8d7fSPeter Avalos 					    num, key_type(public));
75618de8d7fSPeter Avalos 					print_host(out, name, public,
75718de8d7fSPeter Avalos 					    hash_hosts);
75818de8d7fSPeter Avalos 				}
75918de8d7fSPeter Avalos 				if (delete_host && !c)
76018de8d7fSPeter Avalos 					print_host(out, cp, public, 0);
76118de8d7fSPeter Avalos 			} else if (hash_hosts) {
76218de8d7fSPeter Avalos 				for (cp2 = strsep(&cp, ",");
76318de8d7fSPeter Avalos 				    cp2 != NULL && *cp2 != '\0';
76418de8d7fSPeter Avalos 				    cp2 = strsep(&cp, ",")) {
76518de8d7fSPeter Avalos 					if (strcspn(cp2, "*?!") != strlen(cp2))
76618de8d7fSPeter Avalos 						fprintf(stderr, "Warning: "
76718de8d7fSPeter Avalos 						    "ignoring host name with "
76818de8d7fSPeter Avalos 						    "metacharacters: %.64s\n",
76918de8d7fSPeter Avalos 						    cp2);
77018de8d7fSPeter Avalos 					else
77118de8d7fSPeter Avalos 						print_host(out, cp2, public, 1);
77218de8d7fSPeter Avalos 				}
77318de8d7fSPeter Avalos 				has_unhashed = 1;
77418de8d7fSPeter Avalos 			}
77518de8d7fSPeter Avalos 		}
77618de8d7fSPeter Avalos 		key_free(public);
77718de8d7fSPeter Avalos 	}
77818de8d7fSPeter Avalos 	fclose(in);
77918de8d7fSPeter Avalos 
78018de8d7fSPeter Avalos 	if (invalid) {
78118de8d7fSPeter Avalos 		fprintf(stderr, "%s is not a valid known_hosts file.\n",
78218de8d7fSPeter Avalos 		    identity_file);
78318de8d7fSPeter Avalos 		if (inplace) {
78418de8d7fSPeter Avalos 			fprintf(stderr, "Not replacing existing known_hosts "
78518de8d7fSPeter Avalos 			    "file because of errors\n");
78618de8d7fSPeter Avalos 			fclose(out);
78718de8d7fSPeter Avalos 			unlink(tmp);
78818de8d7fSPeter Avalos 		}
78918de8d7fSPeter Avalos 		exit(1);
79018de8d7fSPeter Avalos 	}
79118de8d7fSPeter Avalos 
79218de8d7fSPeter Avalos 	if (inplace) {
79318de8d7fSPeter Avalos 		fclose(out);
79418de8d7fSPeter Avalos 
79518de8d7fSPeter Avalos 		/* Backup existing file */
79618de8d7fSPeter Avalos 		if (unlink(old) == -1 && errno != ENOENT)
79718de8d7fSPeter Avalos 			fatal("unlink %.100s: %s", old, strerror(errno));
79818de8d7fSPeter Avalos 		if (link(identity_file, old) == -1)
79918de8d7fSPeter Avalos 			fatal("link %.100s to %.100s: %s", identity_file, old,
80018de8d7fSPeter Avalos 			    strerror(errno));
80118de8d7fSPeter Avalos 		/* Move new one into place */
80218de8d7fSPeter Avalos 		if (rename(tmp, identity_file) == -1) {
80318de8d7fSPeter Avalos 			error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
80418de8d7fSPeter Avalos 			    strerror(errno));
80518de8d7fSPeter Avalos 			unlink(tmp);
80618de8d7fSPeter Avalos 			unlink(old);
80718de8d7fSPeter Avalos 			exit(1);
80818de8d7fSPeter Avalos 		}
80918de8d7fSPeter Avalos 
81018de8d7fSPeter Avalos 		fprintf(stderr, "%s updated.\n", identity_file);
81118de8d7fSPeter Avalos 		fprintf(stderr, "Original contents retained as %s\n", old);
81218de8d7fSPeter Avalos 		if (has_unhashed) {
81318de8d7fSPeter Avalos 			fprintf(stderr, "WARNING: %s contains unhashed "
81418de8d7fSPeter Avalos 			    "entries\n", old);
81518de8d7fSPeter Avalos 			fprintf(stderr, "Delete this file to ensure privacy "
81618de8d7fSPeter Avalos 			    "of hostnames\n");
81718de8d7fSPeter Avalos 		}
81818de8d7fSPeter Avalos 	}
81918de8d7fSPeter Avalos 
82018de8d7fSPeter Avalos 	exit(0);
82118de8d7fSPeter Avalos }
82218de8d7fSPeter Avalos 
82318de8d7fSPeter Avalos /*
82418de8d7fSPeter Avalos  * Perform changing a passphrase.  The argument is the passwd structure
82518de8d7fSPeter Avalos  * for the current user.
82618de8d7fSPeter Avalos  */
82718de8d7fSPeter Avalos static void
82818de8d7fSPeter Avalos do_change_passphrase(struct passwd *pw)
82918de8d7fSPeter Avalos {
83018de8d7fSPeter Avalos 	char *comment;
83118de8d7fSPeter Avalos 	char *old_passphrase, *passphrase1, *passphrase2;
83218de8d7fSPeter Avalos 	struct stat st;
83318de8d7fSPeter Avalos 	Key *private;
83418de8d7fSPeter Avalos 
83518de8d7fSPeter Avalos 	if (!have_identity)
83618de8d7fSPeter Avalos 		ask_filename(pw, "Enter file in which the key is");
83718de8d7fSPeter Avalos 	if (stat(identity_file, &st) < 0) {
83818de8d7fSPeter Avalos 		perror(identity_file);
83918de8d7fSPeter Avalos 		exit(1);
84018de8d7fSPeter Avalos 	}
84118de8d7fSPeter Avalos 	/* Try to load the file with empty passphrase. */
84218de8d7fSPeter Avalos 	private = key_load_private(identity_file, "", &comment);
84318de8d7fSPeter Avalos 	if (private == NULL) {
84418de8d7fSPeter Avalos 		if (identity_passphrase)
84518de8d7fSPeter Avalos 			old_passphrase = xstrdup(identity_passphrase);
84618de8d7fSPeter Avalos 		else
84718de8d7fSPeter Avalos 			old_passphrase =
84818de8d7fSPeter Avalos 			    read_passphrase("Enter old passphrase: ",
84918de8d7fSPeter Avalos 			    RP_ALLOW_STDIN);
85018de8d7fSPeter Avalos 		private = key_load_private(identity_file, old_passphrase,
85118de8d7fSPeter Avalos 		    &comment);
85218de8d7fSPeter Avalos 		memset(old_passphrase, 0, strlen(old_passphrase));
85318de8d7fSPeter Avalos 		xfree(old_passphrase);
85418de8d7fSPeter Avalos 		if (private == NULL) {
85518de8d7fSPeter Avalos 			printf("Bad passphrase.\n");
85618de8d7fSPeter Avalos 			exit(1);
85718de8d7fSPeter Avalos 		}
85818de8d7fSPeter Avalos 	}
85918de8d7fSPeter Avalos 	printf("Key has comment '%s'\n", comment);
86018de8d7fSPeter Avalos 
86118de8d7fSPeter Avalos 	/* Ask the new passphrase (twice). */
86218de8d7fSPeter Avalos 	if (identity_new_passphrase) {
86318de8d7fSPeter Avalos 		passphrase1 = xstrdup(identity_new_passphrase);
86418de8d7fSPeter Avalos 		passphrase2 = NULL;
86518de8d7fSPeter Avalos 	} else {
86618de8d7fSPeter Avalos 		passphrase1 =
86718de8d7fSPeter Avalos 			read_passphrase("Enter new passphrase (empty for no "
86818de8d7fSPeter Avalos 			    "passphrase): ", RP_ALLOW_STDIN);
86918de8d7fSPeter Avalos 		passphrase2 = read_passphrase("Enter same passphrase again: ",
87018de8d7fSPeter Avalos 		    RP_ALLOW_STDIN);
87118de8d7fSPeter Avalos 
87218de8d7fSPeter Avalos 		/* Verify that they are the same. */
87318de8d7fSPeter Avalos 		if (strcmp(passphrase1, passphrase2) != 0) {
87418de8d7fSPeter Avalos 			memset(passphrase1, 0, strlen(passphrase1));
87518de8d7fSPeter Avalos 			memset(passphrase2, 0, strlen(passphrase2));
87618de8d7fSPeter Avalos 			xfree(passphrase1);
87718de8d7fSPeter Avalos 			xfree(passphrase2);
87818de8d7fSPeter Avalos 			printf("Pass phrases do not match.  Try again.\n");
87918de8d7fSPeter Avalos 			exit(1);
88018de8d7fSPeter Avalos 		}
88118de8d7fSPeter Avalos 		/* Destroy the other copy. */
88218de8d7fSPeter Avalos 		memset(passphrase2, 0, strlen(passphrase2));
88318de8d7fSPeter Avalos 		xfree(passphrase2);
88418de8d7fSPeter Avalos 	}
88518de8d7fSPeter Avalos 
88618de8d7fSPeter Avalos 	/* Save the file using the new passphrase. */
88718de8d7fSPeter Avalos 	if (!key_save_private(private, identity_file, passphrase1, comment)) {
88818de8d7fSPeter Avalos 		printf("Saving the key failed: %s.\n", identity_file);
88918de8d7fSPeter Avalos 		memset(passphrase1, 0, strlen(passphrase1));
89018de8d7fSPeter Avalos 		xfree(passphrase1);
89118de8d7fSPeter Avalos 		key_free(private);
89218de8d7fSPeter Avalos 		xfree(comment);
89318de8d7fSPeter Avalos 		exit(1);
89418de8d7fSPeter Avalos 	}
89518de8d7fSPeter Avalos 	/* Destroy the passphrase and the copy of the key in memory. */
89618de8d7fSPeter Avalos 	memset(passphrase1, 0, strlen(passphrase1));
89718de8d7fSPeter Avalos 	xfree(passphrase1);
89818de8d7fSPeter Avalos 	key_free(private);		 /* Destroys contents */
89918de8d7fSPeter Avalos 	xfree(comment);
90018de8d7fSPeter Avalos 
90118de8d7fSPeter Avalos 	printf("Your identification has been saved with the new passphrase.\n");
90218de8d7fSPeter Avalos 	exit(0);
90318de8d7fSPeter Avalos }
90418de8d7fSPeter Avalos 
90518de8d7fSPeter Avalos /*
90618de8d7fSPeter Avalos  * Print the SSHFP RR.
90718de8d7fSPeter Avalos  */
90818de8d7fSPeter Avalos static int
90918de8d7fSPeter Avalos do_print_resource_record(struct passwd *pw, char *fname, char *hname)
91018de8d7fSPeter Avalos {
91118de8d7fSPeter Avalos 	Key *public;
91218de8d7fSPeter Avalos 	char *comment = NULL;
91318de8d7fSPeter Avalos 	struct stat st;
91418de8d7fSPeter Avalos 
91518de8d7fSPeter Avalos 	if (fname == NULL)
91618de8d7fSPeter Avalos 		ask_filename(pw, "Enter file in which the key is");
91718de8d7fSPeter Avalos 	if (stat(fname, &st) < 0) {
91818de8d7fSPeter Avalos 		if (errno == ENOENT)
91918de8d7fSPeter Avalos 			return 0;
92018de8d7fSPeter Avalos 		perror(fname);
92118de8d7fSPeter Avalos 		exit(1);
92218de8d7fSPeter Avalos 	}
92318de8d7fSPeter Avalos 	public = key_load_public(fname, &comment);
92418de8d7fSPeter Avalos 	if (public != NULL) {
92518de8d7fSPeter Avalos 		export_dns_rr(hname, public, stdout, print_generic);
92618de8d7fSPeter Avalos 		key_free(public);
92718de8d7fSPeter Avalos 		xfree(comment);
92818de8d7fSPeter Avalos 		return 1;
92918de8d7fSPeter Avalos 	}
93018de8d7fSPeter Avalos 	if (comment)
93118de8d7fSPeter Avalos 		xfree(comment);
93218de8d7fSPeter Avalos 
93318de8d7fSPeter Avalos 	printf("failed to read v2 public key from %s.\n", fname);
93418de8d7fSPeter Avalos 	exit(1);
93518de8d7fSPeter Avalos }
93618de8d7fSPeter Avalos 
93718de8d7fSPeter Avalos /*
93818de8d7fSPeter Avalos  * Change the comment of a private key file.
93918de8d7fSPeter Avalos  */
94018de8d7fSPeter Avalos static void
94118de8d7fSPeter Avalos do_change_comment(struct passwd *pw)
94218de8d7fSPeter Avalos {
94318de8d7fSPeter Avalos 	char new_comment[1024], *comment, *passphrase;
94418de8d7fSPeter Avalos 	Key *private;
94518de8d7fSPeter Avalos 	Key *public;
94618de8d7fSPeter Avalos 	struct stat st;
94718de8d7fSPeter Avalos 	FILE *f;
94818de8d7fSPeter Avalos 	int fd;
94918de8d7fSPeter Avalos 
95018de8d7fSPeter Avalos 	if (!have_identity)
95118de8d7fSPeter Avalos 		ask_filename(pw, "Enter file in which the key is");
95218de8d7fSPeter Avalos 	if (stat(identity_file, &st) < 0) {
95318de8d7fSPeter Avalos 		perror(identity_file);
95418de8d7fSPeter Avalos 		exit(1);
95518de8d7fSPeter Avalos 	}
95618de8d7fSPeter Avalos 	private = key_load_private(identity_file, "", &comment);
95718de8d7fSPeter Avalos 	if (private == NULL) {
95818de8d7fSPeter Avalos 		if (identity_passphrase)
95918de8d7fSPeter Avalos 			passphrase = xstrdup(identity_passphrase);
96018de8d7fSPeter Avalos 		else if (identity_new_passphrase)
96118de8d7fSPeter Avalos 			passphrase = xstrdup(identity_new_passphrase);
96218de8d7fSPeter Avalos 		else
96318de8d7fSPeter Avalos 			passphrase = read_passphrase("Enter passphrase: ",
96418de8d7fSPeter Avalos 			    RP_ALLOW_STDIN);
96518de8d7fSPeter Avalos 		/* Try to load using the passphrase. */
96618de8d7fSPeter Avalos 		private = key_load_private(identity_file, passphrase, &comment);
96718de8d7fSPeter Avalos 		if (private == NULL) {
96818de8d7fSPeter Avalos 			memset(passphrase, 0, strlen(passphrase));
96918de8d7fSPeter Avalos 			xfree(passphrase);
97018de8d7fSPeter Avalos 			printf("Bad passphrase.\n");
97118de8d7fSPeter Avalos 			exit(1);
97218de8d7fSPeter Avalos 		}
97318de8d7fSPeter Avalos 	} else {
97418de8d7fSPeter Avalos 		passphrase = xstrdup("");
97518de8d7fSPeter Avalos 	}
97618de8d7fSPeter Avalos 	if (private->type != KEY_RSA1) {
97718de8d7fSPeter Avalos 		fprintf(stderr, "Comments are only supported for RSA1 keys.\n");
97818de8d7fSPeter Avalos 		key_free(private);
97918de8d7fSPeter Avalos 		exit(1);
98018de8d7fSPeter Avalos 	}
98118de8d7fSPeter Avalos 	printf("Key now has comment '%s'\n", comment);
98218de8d7fSPeter Avalos 
98318de8d7fSPeter Avalos 	if (identity_comment) {
98418de8d7fSPeter Avalos 		strlcpy(new_comment, identity_comment, sizeof(new_comment));
98518de8d7fSPeter Avalos 	} else {
98618de8d7fSPeter Avalos 		printf("Enter new comment: ");
98718de8d7fSPeter Avalos 		fflush(stdout);
98818de8d7fSPeter Avalos 		if (!fgets(new_comment, sizeof(new_comment), stdin)) {
98918de8d7fSPeter Avalos 			memset(passphrase, 0, strlen(passphrase));
99018de8d7fSPeter Avalos 			key_free(private);
99118de8d7fSPeter Avalos 			exit(1);
99218de8d7fSPeter Avalos 		}
99318de8d7fSPeter Avalos 		new_comment[strcspn(new_comment, "\n")] = '\0';
99418de8d7fSPeter Avalos 	}
99518de8d7fSPeter Avalos 
99618de8d7fSPeter Avalos 	/* Save the file using the new passphrase. */
99718de8d7fSPeter Avalos 	if (!key_save_private(private, identity_file, passphrase, new_comment)) {
99818de8d7fSPeter Avalos 		printf("Saving the key failed: %s.\n", identity_file);
99918de8d7fSPeter Avalos 		memset(passphrase, 0, strlen(passphrase));
100018de8d7fSPeter Avalos 		xfree(passphrase);
100118de8d7fSPeter Avalos 		key_free(private);
100218de8d7fSPeter Avalos 		xfree(comment);
100318de8d7fSPeter Avalos 		exit(1);
100418de8d7fSPeter Avalos 	}
100518de8d7fSPeter Avalos 	memset(passphrase, 0, strlen(passphrase));
100618de8d7fSPeter Avalos 	xfree(passphrase);
100718de8d7fSPeter Avalos 	public = key_from_private(private);
100818de8d7fSPeter Avalos 	key_free(private);
100918de8d7fSPeter Avalos 
101018de8d7fSPeter Avalos 	strlcat(identity_file, ".pub", sizeof(identity_file));
101118de8d7fSPeter Avalos 	fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
101218de8d7fSPeter Avalos 	if (fd == -1) {
101318de8d7fSPeter Avalos 		printf("Could not save your public key in %s\n", identity_file);
101418de8d7fSPeter Avalos 		exit(1);
101518de8d7fSPeter Avalos 	}
101618de8d7fSPeter Avalos 	f = fdopen(fd, "w");
101718de8d7fSPeter Avalos 	if (f == NULL) {
1018*cb5eb4f1SPeter Avalos 		printf("fdopen %s failed\n", identity_file);
101918de8d7fSPeter Avalos 		exit(1);
102018de8d7fSPeter Avalos 	}
102118de8d7fSPeter Avalos 	if (!key_write(public, f))
1022*cb5eb4f1SPeter Avalos 		fprintf(stderr, "write key failed\n");
102318de8d7fSPeter Avalos 	key_free(public);
102418de8d7fSPeter Avalos 	fprintf(f, " %s\n", new_comment);
102518de8d7fSPeter Avalos 	fclose(f);
102618de8d7fSPeter Avalos 
102718de8d7fSPeter Avalos 	xfree(comment);
102818de8d7fSPeter Avalos 
102918de8d7fSPeter Avalos 	printf("The comment in your key file has been changed.\n");
103018de8d7fSPeter Avalos 	exit(0);
103118de8d7fSPeter Avalos }
103218de8d7fSPeter Avalos 
103318de8d7fSPeter Avalos static void
103418de8d7fSPeter Avalos usage(void)
103518de8d7fSPeter Avalos {
103618de8d7fSPeter Avalos 	fprintf(stderr, "usage: %s [options]\n", __progname);
103718de8d7fSPeter Avalos 	fprintf(stderr, "Options:\n");
103818de8d7fSPeter Avalos 	fprintf(stderr, "  -a trials   Number of trials for screening DH-GEX moduli.\n");
103918de8d7fSPeter Avalos 	fprintf(stderr, "  -B          Show bubblebabble digest of key file.\n");
104018de8d7fSPeter Avalos 	fprintf(stderr, "  -b bits     Number of bits in the key to create.\n");
104118de8d7fSPeter Avalos 	fprintf(stderr, "  -C comment  Provide new comment.\n");
104218de8d7fSPeter Avalos 	fprintf(stderr, "  -c          Change comment in private and public key files.\n");
104318de8d7fSPeter Avalos #ifdef SMARTCARD
104418de8d7fSPeter Avalos 	fprintf(stderr, "  -D reader   Download public key from smartcard.\n");
104518de8d7fSPeter Avalos #endif /* SMARTCARD */
104618de8d7fSPeter Avalos 	fprintf(stderr, "  -e          Convert OpenSSH to RFC 4716 key file.\n");
104718de8d7fSPeter Avalos 	fprintf(stderr, "  -F hostname Find hostname in known hosts file.\n");
104818de8d7fSPeter Avalos 	fprintf(stderr, "  -f filename Filename of the key file.\n");
104918de8d7fSPeter Avalos 	fprintf(stderr, "  -G file     Generate candidates for DH-GEX moduli.\n");
105018de8d7fSPeter Avalos 	fprintf(stderr, "  -g          Use generic DNS resource record format.\n");
105118de8d7fSPeter Avalos 	fprintf(stderr, "  -H          Hash names in known_hosts file.\n");
105218de8d7fSPeter Avalos 	fprintf(stderr, "  -i          Convert RFC 4716 to OpenSSH key file.\n");
105318de8d7fSPeter Avalos 	fprintf(stderr, "  -l          Show fingerprint of key file.\n");
105418de8d7fSPeter Avalos 	fprintf(stderr, "  -M memory   Amount of memory (MB) to use for generating DH-GEX moduli.\n");
105518de8d7fSPeter Avalos 	fprintf(stderr, "  -N phrase   Provide new passphrase.\n");
105618de8d7fSPeter Avalos 	fprintf(stderr, "  -P phrase   Provide old passphrase.\n");
105718de8d7fSPeter Avalos 	fprintf(stderr, "  -p          Change passphrase of private key file.\n");
105818de8d7fSPeter Avalos 	fprintf(stderr, "  -q          Quiet.\n");
105918de8d7fSPeter Avalos 	fprintf(stderr, "  -R hostname Remove host from known_hosts file.\n");
106018de8d7fSPeter Avalos 	fprintf(stderr, "  -r hostname Print DNS resource record.\n");
106118de8d7fSPeter Avalos 	fprintf(stderr, "  -S start    Start point (hex) for generating DH-GEX moduli.\n");
106218de8d7fSPeter Avalos 	fprintf(stderr, "  -T file     Screen candidates for DH-GEX moduli.\n");
106318de8d7fSPeter Avalos 	fprintf(stderr, "  -t type     Specify type of key to create.\n");
106418de8d7fSPeter Avalos #ifdef SMARTCARD
106518de8d7fSPeter Avalos 	fprintf(stderr, "  -U reader   Upload private key to smartcard.\n");
106618de8d7fSPeter Avalos #endif /* SMARTCARD */
106718de8d7fSPeter Avalos 	fprintf(stderr, "  -v          Verbose.\n");
106818de8d7fSPeter Avalos 	fprintf(stderr, "  -W gen      Generator to use for generating DH-GEX moduli.\n");
106918de8d7fSPeter Avalos 	fprintf(stderr, "  -y          Read private key file and print public key.\n");
107018de8d7fSPeter Avalos 
107118de8d7fSPeter Avalos 	exit(1);
107218de8d7fSPeter Avalos }
107318de8d7fSPeter Avalos 
107418de8d7fSPeter Avalos /*
107518de8d7fSPeter Avalos  * Main program for key management.
107618de8d7fSPeter Avalos  */
107718de8d7fSPeter Avalos int
107818de8d7fSPeter Avalos main(int argc, char **argv)
107918de8d7fSPeter Avalos {
108018de8d7fSPeter Avalos 	char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
108118de8d7fSPeter Avalos 	char out_file[MAXPATHLEN], *reader_id = NULL;
108218de8d7fSPeter Avalos 	char *rr_hostname = NULL;
108318de8d7fSPeter Avalos 	Key *private, *public;
108418de8d7fSPeter Avalos 	struct passwd *pw;
108518de8d7fSPeter Avalos 	struct stat st;
108618de8d7fSPeter Avalos 	int opt, type, fd, download = 0;
108718de8d7fSPeter Avalos 	u_int32_t memory = 0, generator_wanted = 0, trials = 100;
108818de8d7fSPeter Avalos 	int do_gen_candidates = 0, do_screen_candidates = 0;
108918de8d7fSPeter Avalos 	BIGNUM *start = NULL;
109018de8d7fSPeter Avalos 	FILE *f;
109118de8d7fSPeter Avalos 	const char *errstr;
109218de8d7fSPeter Avalos 
109318de8d7fSPeter Avalos 	extern int optind;
109418de8d7fSPeter Avalos 	extern char *optarg;
109518de8d7fSPeter Avalos 
109618de8d7fSPeter Avalos 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
109718de8d7fSPeter Avalos 	sanitise_stdfd();
109818de8d7fSPeter Avalos 
109918de8d7fSPeter Avalos 	__progname = ssh_get_progname(argv[0]);
110018de8d7fSPeter Avalos 
110118de8d7fSPeter Avalos 	SSLeay_add_all_algorithms();
110218de8d7fSPeter Avalos 	log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
110318de8d7fSPeter Avalos 
110418de8d7fSPeter Avalos 	init_rng();
110518de8d7fSPeter Avalos 	seed_rng();
110618de8d7fSPeter Avalos 
110718de8d7fSPeter Avalos 	/* we need this for the home * directory.  */
110818de8d7fSPeter Avalos 	pw = getpwuid(getuid());
110918de8d7fSPeter Avalos 	if (!pw) {
111018de8d7fSPeter Avalos 		printf("You don't exist, go away!\n");
111118de8d7fSPeter Avalos 		exit(1);
111218de8d7fSPeter Avalos 	}
111318de8d7fSPeter Avalos 	if (gethostname(hostname, sizeof(hostname)) < 0) {
111418de8d7fSPeter Avalos 		perror("gethostname");
111518de8d7fSPeter Avalos 		exit(1);
111618de8d7fSPeter Avalos 	}
111718de8d7fSPeter Avalos 
111818de8d7fSPeter Avalos 	while ((opt = getopt(argc, argv,
111918de8d7fSPeter Avalos 	    "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
112018de8d7fSPeter Avalos 		switch (opt) {
112118de8d7fSPeter Avalos 		case 'b':
112218de8d7fSPeter Avalos 			bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
112318de8d7fSPeter Avalos 			if (errstr)
112418de8d7fSPeter Avalos 				fatal("Bits has bad value %s (%s)",
112518de8d7fSPeter Avalos 					optarg, errstr);
112618de8d7fSPeter Avalos 			break;
112718de8d7fSPeter Avalos 		case 'F':
112818de8d7fSPeter Avalos 			find_host = 1;
112918de8d7fSPeter Avalos 			rr_hostname = optarg;
113018de8d7fSPeter Avalos 			break;
113118de8d7fSPeter Avalos 		case 'H':
113218de8d7fSPeter Avalos 			hash_hosts = 1;
113318de8d7fSPeter Avalos 			break;
113418de8d7fSPeter Avalos 		case 'R':
113518de8d7fSPeter Avalos 			delete_host = 1;
113618de8d7fSPeter Avalos 			rr_hostname = optarg;
113718de8d7fSPeter Avalos 			break;
113818de8d7fSPeter Avalos 		case 'l':
113918de8d7fSPeter Avalos 			print_fingerprint = 1;
114018de8d7fSPeter Avalos 			break;
114118de8d7fSPeter Avalos 		case 'B':
114218de8d7fSPeter Avalos 			print_bubblebabble = 1;
114318de8d7fSPeter Avalos 			break;
114418de8d7fSPeter Avalos 		case 'p':
114518de8d7fSPeter Avalos 			change_passphrase = 1;
114618de8d7fSPeter Avalos 			break;
114718de8d7fSPeter Avalos 		case 'c':
114818de8d7fSPeter Avalos 			change_comment = 1;
114918de8d7fSPeter Avalos 			break;
115018de8d7fSPeter Avalos 		case 'f':
115118de8d7fSPeter Avalos 			if (strlcpy(identity_file, optarg, sizeof(identity_file)) >=
115218de8d7fSPeter Avalos 			    sizeof(identity_file))
115318de8d7fSPeter Avalos 				fatal("Identity filename too long");
115418de8d7fSPeter Avalos 			have_identity = 1;
115518de8d7fSPeter Avalos 			break;
115618de8d7fSPeter Avalos 		case 'g':
115718de8d7fSPeter Avalos 			print_generic = 1;
115818de8d7fSPeter Avalos 			break;
115918de8d7fSPeter Avalos 		case 'P':
116018de8d7fSPeter Avalos 			identity_passphrase = optarg;
116118de8d7fSPeter Avalos 			break;
116218de8d7fSPeter Avalos 		case 'N':
116318de8d7fSPeter Avalos 			identity_new_passphrase = optarg;
116418de8d7fSPeter Avalos 			break;
116518de8d7fSPeter Avalos 		case 'C':
116618de8d7fSPeter Avalos 			identity_comment = optarg;
116718de8d7fSPeter Avalos 			break;
116818de8d7fSPeter Avalos 		case 'q':
116918de8d7fSPeter Avalos 			quiet = 1;
117018de8d7fSPeter Avalos 			break;
117118de8d7fSPeter Avalos 		case 'e':
117218de8d7fSPeter Avalos 		case 'x':
117318de8d7fSPeter Avalos 			/* export key */
117418de8d7fSPeter Avalos 			convert_to_ssh2 = 1;
117518de8d7fSPeter Avalos 			break;
117618de8d7fSPeter Avalos 		case 'i':
117718de8d7fSPeter Avalos 		case 'X':
117818de8d7fSPeter Avalos 			/* import key */
117918de8d7fSPeter Avalos 			convert_from_ssh2 = 1;
118018de8d7fSPeter Avalos 			break;
118118de8d7fSPeter Avalos 		case 'y':
118218de8d7fSPeter Avalos 			print_public = 1;
118318de8d7fSPeter Avalos 			break;
118418de8d7fSPeter Avalos 		case 'd':
118518de8d7fSPeter Avalos 			key_type_name = "dsa";
118618de8d7fSPeter Avalos 			break;
118718de8d7fSPeter Avalos 		case 't':
118818de8d7fSPeter Avalos 			key_type_name = optarg;
118918de8d7fSPeter Avalos 			break;
119018de8d7fSPeter Avalos 		case 'D':
119118de8d7fSPeter Avalos 			download = 1;
119218de8d7fSPeter Avalos 			/*FALLTHROUGH*/
119318de8d7fSPeter Avalos 		case 'U':
119418de8d7fSPeter Avalos 			reader_id = optarg;
119518de8d7fSPeter Avalos 			break;
119618de8d7fSPeter Avalos 		case 'v':
119718de8d7fSPeter Avalos 			if (log_level == SYSLOG_LEVEL_INFO)
119818de8d7fSPeter Avalos 				log_level = SYSLOG_LEVEL_DEBUG1;
119918de8d7fSPeter Avalos 			else {
120018de8d7fSPeter Avalos 				if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
120118de8d7fSPeter Avalos 				    log_level < SYSLOG_LEVEL_DEBUG3)
120218de8d7fSPeter Avalos 					log_level++;
120318de8d7fSPeter Avalos 			}
120418de8d7fSPeter Avalos 			break;
120518de8d7fSPeter Avalos 		case 'r':
120618de8d7fSPeter Avalos 			rr_hostname = optarg;
120718de8d7fSPeter Avalos 			break;
120818de8d7fSPeter Avalos 		case 'W':
120918de8d7fSPeter Avalos 			generator_wanted = (u_int32_t)strtonum(optarg, 1,
121018de8d7fSPeter Avalos 			    UINT_MAX, &errstr);
121118de8d7fSPeter Avalos 			if (errstr)
121218de8d7fSPeter Avalos 				fatal("Desired generator has bad value: %s (%s)",
121318de8d7fSPeter Avalos 					optarg, errstr);
121418de8d7fSPeter Avalos 			break;
121518de8d7fSPeter Avalos 		case 'a':
121618de8d7fSPeter Avalos 			trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
121718de8d7fSPeter Avalos 			if (errstr)
121818de8d7fSPeter Avalos 				fatal("Invalid number of trials: %s (%s)",
121918de8d7fSPeter Avalos 					optarg, errstr);
122018de8d7fSPeter Avalos 			break;
122118de8d7fSPeter Avalos 		case 'M':
122218de8d7fSPeter Avalos 			memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
122318de8d7fSPeter Avalos 			if (errstr) {
122418de8d7fSPeter Avalos 				fatal("Memory limit is %s: %s", errstr, optarg);
122518de8d7fSPeter Avalos 			}
122618de8d7fSPeter Avalos 			break;
122718de8d7fSPeter Avalos 		case 'G':
122818de8d7fSPeter Avalos 			do_gen_candidates = 1;
122918de8d7fSPeter Avalos 			if (strlcpy(out_file, optarg, sizeof(out_file)) >=
123018de8d7fSPeter Avalos 			    sizeof(out_file))
123118de8d7fSPeter Avalos 				fatal("Output filename too long");
123218de8d7fSPeter Avalos 			break;
123318de8d7fSPeter Avalos 		case 'T':
123418de8d7fSPeter Avalos 			do_screen_candidates = 1;
123518de8d7fSPeter Avalos 			if (strlcpy(out_file, optarg, sizeof(out_file)) >=
123618de8d7fSPeter Avalos 			    sizeof(out_file))
123718de8d7fSPeter Avalos 				fatal("Output filename too long");
123818de8d7fSPeter Avalos 			break;
123918de8d7fSPeter Avalos 		case 'S':
124018de8d7fSPeter Avalos 			/* XXX - also compare length against bits */
124118de8d7fSPeter Avalos 			if (BN_hex2bn(&start, optarg) == 0)
124218de8d7fSPeter Avalos 				fatal("Invalid start point.");
124318de8d7fSPeter Avalos 			break;
124418de8d7fSPeter Avalos 		case '?':
124518de8d7fSPeter Avalos 		default:
124618de8d7fSPeter Avalos 			usage();
124718de8d7fSPeter Avalos 		}
124818de8d7fSPeter Avalos 	}
124918de8d7fSPeter Avalos 
125018de8d7fSPeter Avalos 	/* reinit */
125118de8d7fSPeter Avalos 	log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
125218de8d7fSPeter Avalos 
125318de8d7fSPeter Avalos 	if (optind < argc) {
125418de8d7fSPeter Avalos 		printf("Too many arguments.\n");
125518de8d7fSPeter Avalos 		usage();
125618de8d7fSPeter Avalos 	}
125718de8d7fSPeter Avalos 	if (change_passphrase && change_comment) {
125818de8d7fSPeter Avalos 		printf("Can only have one of -p and -c.\n");
125918de8d7fSPeter Avalos 		usage();
126018de8d7fSPeter Avalos 	}
126118de8d7fSPeter Avalos 	if (print_fingerprint && (delete_host || hash_hosts)) {
126218de8d7fSPeter Avalos 		printf("Cannot use -l with -D or -R.\n");
126318de8d7fSPeter Avalos 		usage();
126418de8d7fSPeter Avalos 	}
126518de8d7fSPeter Avalos 	if (delete_host || hash_hosts || find_host)
126618de8d7fSPeter Avalos 		do_known_hosts(pw, rr_hostname);
126718de8d7fSPeter Avalos 	if (print_fingerprint || print_bubblebabble)
126818de8d7fSPeter Avalos 		do_fingerprint(pw);
126918de8d7fSPeter Avalos 	if (change_passphrase)
127018de8d7fSPeter Avalos 		do_change_passphrase(pw);
127118de8d7fSPeter Avalos 	if (change_comment)
127218de8d7fSPeter Avalos 		do_change_comment(pw);
127318de8d7fSPeter Avalos 	if (convert_to_ssh2)
127418de8d7fSPeter Avalos 		do_convert_to_ssh2(pw);
127518de8d7fSPeter Avalos 	if (convert_from_ssh2)
127618de8d7fSPeter Avalos 		do_convert_from_ssh2(pw);
127718de8d7fSPeter Avalos 	if (print_public)
127818de8d7fSPeter Avalos 		do_print_public(pw);
127918de8d7fSPeter Avalos 	if (rr_hostname != NULL) {
128018de8d7fSPeter Avalos 		unsigned int n = 0;
128118de8d7fSPeter Avalos 
128218de8d7fSPeter Avalos 		if (have_identity) {
128318de8d7fSPeter Avalos 			n = do_print_resource_record(pw,
128418de8d7fSPeter Avalos 			    identity_file, rr_hostname);
128518de8d7fSPeter Avalos 			if (n == 0) {
128618de8d7fSPeter Avalos 				perror(identity_file);
128718de8d7fSPeter Avalos 				exit(1);
128818de8d7fSPeter Avalos 			}
128918de8d7fSPeter Avalos 			exit(0);
129018de8d7fSPeter Avalos 		} else {
129118de8d7fSPeter Avalos 
129218de8d7fSPeter Avalos 			n += do_print_resource_record(pw,
129318de8d7fSPeter Avalos 			    _PATH_HOST_RSA_KEY_FILE, rr_hostname);
129418de8d7fSPeter Avalos 			n += do_print_resource_record(pw,
129518de8d7fSPeter Avalos 			    _PATH_HOST_DSA_KEY_FILE, rr_hostname);
129618de8d7fSPeter Avalos 
129718de8d7fSPeter Avalos 			if (n == 0)
129818de8d7fSPeter Avalos 				fatal("no keys found.");
129918de8d7fSPeter Avalos 			exit(0);
130018de8d7fSPeter Avalos 		}
130118de8d7fSPeter Avalos 	}
130218de8d7fSPeter Avalos 	if (reader_id != NULL) {
130318de8d7fSPeter Avalos #ifdef SMARTCARD
130418de8d7fSPeter Avalos 		if (download)
130518de8d7fSPeter Avalos 			do_download(pw, reader_id);
130618de8d7fSPeter Avalos 		else
130718de8d7fSPeter Avalos 			do_upload(pw, reader_id);
130818de8d7fSPeter Avalos #else /* SMARTCARD */
130918de8d7fSPeter Avalos 		fatal("no support for smartcards.");
131018de8d7fSPeter Avalos #endif /* SMARTCARD */
131118de8d7fSPeter Avalos 	}
131218de8d7fSPeter Avalos 
131318de8d7fSPeter Avalos 	if (do_gen_candidates) {
131418de8d7fSPeter Avalos 		FILE *out = fopen(out_file, "w");
131518de8d7fSPeter Avalos 
131618de8d7fSPeter Avalos 		if (out == NULL) {
131718de8d7fSPeter Avalos 			error("Couldn't open modulus candidate file \"%s\": %s",
131818de8d7fSPeter Avalos 			    out_file, strerror(errno));
131918de8d7fSPeter Avalos 			return (1);
132018de8d7fSPeter Avalos 		}
132118de8d7fSPeter Avalos 		if (bits == 0)
132218de8d7fSPeter Avalos 			bits = DEFAULT_BITS;
132318de8d7fSPeter Avalos 		if (gen_candidates(out, memory, bits, start) != 0)
132418de8d7fSPeter Avalos 			fatal("modulus candidate generation failed");
132518de8d7fSPeter Avalos 
132618de8d7fSPeter Avalos 		return (0);
132718de8d7fSPeter Avalos 	}
132818de8d7fSPeter Avalos 
132918de8d7fSPeter Avalos 	if (do_screen_candidates) {
133018de8d7fSPeter Avalos 		FILE *in;
133118de8d7fSPeter Avalos 		FILE *out = fopen(out_file, "w");
133218de8d7fSPeter Avalos 
133318de8d7fSPeter Avalos 		if (have_identity && strcmp(identity_file, "-") != 0) {
133418de8d7fSPeter Avalos 			if ((in = fopen(identity_file, "r")) == NULL) {
133518de8d7fSPeter Avalos 				fatal("Couldn't open modulus candidate "
133618de8d7fSPeter Avalos 				    "file \"%s\": %s", identity_file,
133718de8d7fSPeter Avalos 				    strerror(errno));
133818de8d7fSPeter Avalos 			}
133918de8d7fSPeter Avalos 		} else
134018de8d7fSPeter Avalos 			in = stdin;
134118de8d7fSPeter Avalos 
134218de8d7fSPeter Avalos 		if (out == NULL) {
134318de8d7fSPeter Avalos 			fatal("Couldn't open moduli file \"%s\": %s",
134418de8d7fSPeter Avalos 			    out_file, strerror(errno));
134518de8d7fSPeter Avalos 		}
134618de8d7fSPeter Avalos 		if (prime_test(in, out, trials, generator_wanted) != 0)
134718de8d7fSPeter Avalos 			fatal("modulus screening failed");
134818de8d7fSPeter Avalos 		return (0);
134918de8d7fSPeter Avalos 	}
135018de8d7fSPeter Avalos 
135118de8d7fSPeter Avalos 	arc4random_stir();
135218de8d7fSPeter Avalos 
135318de8d7fSPeter Avalos 	if (key_type_name == NULL)
135418de8d7fSPeter Avalos 		key_type_name = "rsa";
135518de8d7fSPeter Avalos 
135618de8d7fSPeter Avalos 	type = key_type_from_name(key_type_name);
135718de8d7fSPeter Avalos 	if (type == KEY_UNSPEC) {
135818de8d7fSPeter Avalos 		fprintf(stderr, "unknown key type %s\n", key_type_name);
135918de8d7fSPeter Avalos 		exit(1);
136018de8d7fSPeter Avalos 	}
136118de8d7fSPeter Avalos 	if (bits == 0)
136218de8d7fSPeter Avalos 		bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS;
136318de8d7fSPeter Avalos 	if (type == KEY_DSA && bits != 1024)
136418de8d7fSPeter Avalos 		fatal("DSA keys must be 1024 bits");
136518de8d7fSPeter Avalos 	if (!quiet)
136618de8d7fSPeter Avalos 		printf("Generating public/private %s key pair.\n", key_type_name);
136718de8d7fSPeter Avalos 	private = key_generate(type, bits);
136818de8d7fSPeter Avalos 	if (private == NULL) {
1369*cb5eb4f1SPeter Avalos 		fprintf(stderr, "key_generate failed\n");
137018de8d7fSPeter Avalos 		exit(1);
137118de8d7fSPeter Avalos 	}
137218de8d7fSPeter Avalos 	public  = key_from_private(private);
137318de8d7fSPeter Avalos 
137418de8d7fSPeter Avalos 	if (!have_identity)
137518de8d7fSPeter Avalos 		ask_filename(pw, "Enter file in which to save the key");
137618de8d7fSPeter Avalos 
137718de8d7fSPeter Avalos 	/* Create ~/.ssh directory if it doesn't already exist. */
137818de8d7fSPeter Avalos 	snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
137918de8d7fSPeter Avalos 	if (strstr(identity_file, dotsshdir) != NULL &&
138018de8d7fSPeter Avalos 	    stat(dotsshdir, &st) < 0) {
138118de8d7fSPeter Avalos 		if (mkdir(dotsshdir, 0700) < 0)
138218de8d7fSPeter Avalos 			error("Could not create directory '%s'.", dotsshdir);
138318de8d7fSPeter Avalos 		else if (!quiet)
138418de8d7fSPeter Avalos 			printf("Created directory '%s'.\n", dotsshdir);
138518de8d7fSPeter Avalos 	}
138618de8d7fSPeter Avalos 	/* If the file already exists, ask the user to confirm. */
138718de8d7fSPeter Avalos 	if (stat(identity_file, &st) >= 0) {
138818de8d7fSPeter Avalos 		char yesno[3];
138918de8d7fSPeter Avalos 		printf("%s already exists.\n", identity_file);
139018de8d7fSPeter Avalos 		printf("Overwrite (y/n)? ");
139118de8d7fSPeter Avalos 		fflush(stdout);
139218de8d7fSPeter Avalos 		if (fgets(yesno, sizeof(yesno), stdin) == NULL)
139318de8d7fSPeter Avalos 			exit(1);
139418de8d7fSPeter Avalos 		if (yesno[0] != 'y' && yesno[0] != 'Y')
139518de8d7fSPeter Avalos 			exit(1);
139618de8d7fSPeter Avalos 	}
139718de8d7fSPeter Avalos 	/* Ask for a passphrase (twice). */
139818de8d7fSPeter Avalos 	if (identity_passphrase)
139918de8d7fSPeter Avalos 		passphrase1 = xstrdup(identity_passphrase);
140018de8d7fSPeter Avalos 	else if (identity_new_passphrase)
140118de8d7fSPeter Avalos 		passphrase1 = xstrdup(identity_new_passphrase);
140218de8d7fSPeter Avalos 	else {
140318de8d7fSPeter Avalos passphrase_again:
140418de8d7fSPeter Avalos 		passphrase1 =
140518de8d7fSPeter Avalos 			read_passphrase("Enter passphrase (empty for no "
140618de8d7fSPeter Avalos 			    "passphrase): ", RP_ALLOW_STDIN);
140718de8d7fSPeter Avalos 		passphrase2 = read_passphrase("Enter same passphrase again: ",
140818de8d7fSPeter Avalos 		    RP_ALLOW_STDIN);
140918de8d7fSPeter Avalos 		if (strcmp(passphrase1, passphrase2) != 0) {
141018de8d7fSPeter Avalos 			/*
141118de8d7fSPeter Avalos 			 * The passphrases do not match.  Clear them and
141218de8d7fSPeter Avalos 			 * retry.
141318de8d7fSPeter Avalos 			 */
141418de8d7fSPeter Avalos 			memset(passphrase1, 0, strlen(passphrase1));
141518de8d7fSPeter Avalos 			memset(passphrase2, 0, strlen(passphrase2));
141618de8d7fSPeter Avalos 			xfree(passphrase1);
141718de8d7fSPeter Avalos 			xfree(passphrase2);
141818de8d7fSPeter Avalos 			printf("Passphrases do not match.  Try again.\n");
141918de8d7fSPeter Avalos 			goto passphrase_again;
142018de8d7fSPeter Avalos 		}
142118de8d7fSPeter Avalos 		/* Clear the other copy of the passphrase. */
142218de8d7fSPeter Avalos 		memset(passphrase2, 0, strlen(passphrase2));
142318de8d7fSPeter Avalos 		xfree(passphrase2);
142418de8d7fSPeter Avalos 	}
142518de8d7fSPeter Avalos 
142618de8d7fSPeter Avalos 	if (identity_comment) {
142718de8d7fSPeter Avalos 		strlcpy(comment, identity_comment, sizeof(comment));
142818de8d7fSPeter Avalos 	} else {
1429*cb5eb4f1SPeter Avalos 		/* Create default comment field for the passphrase. */
143018de8d7fSPeter Avalos 		snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
143118de8d7fSPeter Avalos 	}
143218de8d7fSPeter Avalos 
143318de8d7fSPeter Avalos 	/* Save the key with the given passphrase and comment. */
143418de8d7fSPeter Avalos 	if (!key_save_private(private, identity_file, passphrase1, comment)) {
143518de8d7fSPeter Avalos 		printf("Saving the key failed: %s.\n", identity_file);
143618de8d7fSPeter Avalos 		memset(passphrase1, 0, strlen(passphrase1));
143718de8d7fSPeter Avalos 		xfree(passphrase1);
143818de8d7fSPeter Avalos 		exit(1);
143918de8d7fSPeter Avalos 	}
144018de8d7fSPeter Avalos 	/* Clear the passphrase. */
144118de8d7fSPeter Avalos 	memset(passphrase1, 0, strlen(passphrase1));
144218de8d7fSPeter Avalos 	xfree(passphrase1);
144318de8d7fSPeter Avalos 
144418de8d7fSPeter Avalos 	/* Clear the private key and the random number generator. */
144518de8d7fSPeter Avalos 	key_free(private);
144618de8d7fSPeter Avalos 	arc4random_stir();
144718de8d7fSPeter Avalos 
144818de8d7fSPeter Avalos 	if (!quiet)
144918de8d7fSPeter Avalos 		printf("Your identification has been saved in %s.\n", identity_file);
145018de8d7fSPeter Avalos 
145118de8d7fSPeter Avalos 	strlcat(identity_file, ".pub", sizeof(identity_file));
145218de8d7fSPeter Avalos 	fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
145318de8d7fSPeter Avalos 	if (fd == -1) {
145418de8d7fSPeter Avalos 		printf("Could not save your public key in %s\n", identity_file);
145518de8d7fSPeter Avalos 		exit(1);
145618de8d7fSPeter Avalos 	}
145718de8d7fSPeter Avalos 	f = fdopen(fd, "w");
145818de8d7fSPeter Avalos 	if (f == NULL) {
1459*cb5eb4f1SPeter Avalos 		printf("fdopen %s failed\n", identity_file);
146018de8d7fSPeter Avalos 		exit(1);
146118de8d7fSPeter Avalos 	}
146218de8d7fSPeter Avalos 	if (!key_write(public, f))
1463*cb5eb4f1SPeter Avalos 		fprintf(stderr, "write key failed\n");
146418de8d7fSPeter Avalos 	fprintf(f, " %s\n", comment);
146518de8d7fSPeter Avalos 	fclose(f);
146618de8d7fSPeter Avalos 
146718de8d7fSPeter Avalos 	if (!quiet) {
146818de8d7fSPeter Avalos 		char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
146918de8d7fSPeter Avalos 		char *ra = key_fingerprint(public, SSH_FP_MD5,
147018de8d7fSPeter Avalos 		    SSH_FP_RANDOMART);
147118de8d7fSPeter Avalos 		printf("Your public key has been saved in %s.\n",
147218de8d7fSPeter Avalos 		    identity_file);
147318de8d7fSPeter Avalos 		printf("The key fingerprint is:\n");
147418de8d7fSPeter Avalos 		printf("%s %s\n", fp, comment);
147518de8d7fSPeter Avalos 		printf("The key's randomart image is:\n");
147618de8d7fSPeter Avalos 		printf("%s\n", ra);
147718de8d7fSPeter Avalos 		xfree(ra);
147818de8d7fSPeter Avalos 		xfree(fp);
147918de8d7fSPeter Avalos 	}
148018de8d7fSPeter Avalos 
148118de8d7fSPeter Avalos 	key_free(public);
148218de8d7fSPeter Avalos 	exit(0);
148318de8d7fSPeter Avalos }
1484