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