diff options
Diffstat (limited to 'usr/src/cmd/ssh/ssh-keygen/ssh-keygen.c')
| -rw-r--r-- | usr/src/cmd/ssh/ssh-keygen/ssh-keygen.c | 276 | 
1 files changed, 222 insertions, 54 deletions
| diff --git a/usr/src/cmd/ssh/ssh-keygen/ssh-keygen.c b/usr/src/cmd/ssh/ssh-keygen/ssh-keygen.c index ebad79b0f8..e4b7d1e5eb 100644 --- a/usr/src/cmd/ssh/ssh-keygen/ssh-keygen.c +++ b/usr/src/cmd/ssh/ssh-keygen/ssh-keygen.c @@ -11,7 +11,7 @@   * called by a name other than "ssh" or "Secure Shell".   */ -/* $OpenBSD: ssh-keygen.c,v 1.160 2007/01/21 01:41:54 stevesk Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.205 2011/01/11 06:13:10 djm Exp $ */  #include "includes.h"  #include <openssl/evp.h> @@ -76,9 +76,14 @@ char *identity_new_passphrase = NULL;  /* This is set to the new comment if given on the command line. */  char *identity_comment = NULL; -/* Dump public key file in format used by real and the original SSH 2 */ -int convert_to_ssh2 = 0; -int convert_from_ssh2 = 0; +/* Conversion to/from various formats */ +int convert_to = 0; +int convert_from = 0; +enum { +	FMT_RFC4716, +	FMT_PKCS8, +	FMT_PEM +} convert_format = FMT_RFC4716;  int print_public = 0;  char *key_type_name = NULL; @@ -154,41 +159,105 @@ load_identity(char *filename)  #define	SSH_COM_PRIVATE_KEY_MAGIC	0x3f6ff9eb  static void -do_convert_to_ssh2(struct passwd *pw) +do_convert_to_ssh2(struct passwd *pw, Key *k)  { -	Key *k;  	u_int len;  	u_char *blob; -	struct stat st; +	char comment[61]; -	if (!have_identity) -		ask_filename(pw, gettext("Enter file in which the key is")); -	if (stat(identity_file, &st) < 0) { -		perror(identity_file); +	if (key_to_blob(k, &blob, &len) <= 0) { +		fprintf(stderr, "key_to_blob failed\n");  		exit(1);  	} +	/* Comment + surrounds must fit into 72 chars (RFC 4716 sec 3.3) */ +	snprintf(comment, sizeof(comment), +		"%u-bit %s, converted by %s@%s from OpenSSH", +		key_size(k), key_type(k), +		pw->pw_name, hostname); + +	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); +	fprintf(stdout, "Comment: \"%s\"\n", comment); +	dump_base64(stdout, blob, len); +	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); +	key_free(k); +	xfree(blob); +	exit(0); +} + +static void +do_convert_to_pkcs8(Key *k) +{ +	switch (key_type_plain(k->type)) { +	case KEY_RSA: +		if (!PEM_write_RSA_PUBKEY(stdout, k->rsa)) +			fatal("PEM_write_RSA_PUBKEY failed"); +		break; +	case KEY_DSA: +		if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) +			fatal("PEM_write_DSA_PUBKEY failed"); +		break; +	default: +		fatal("%s: unsupported key type %s", __func__, key_type(k)); +	} +	exit(0); +} + +static void +do_convert_to_pem(Key *k) +{ +	switch (key_type_plain(k->type)) { +	case KEY_RSA: +		if (!PEM_write_RSAPublicKey(stdout, k->rsa)) +			fatal("PEM_write_RSAPublicKey failed"); +		break; +	case KEY_DSA: +		if (!PEM_write_DSA_PUBKEY(stdout, k->dsa)) +			fatal("PEM_write_DSAPublicKey failed"); +		break; +	default: +		fatal("%s: unsupported key type %s", __func__, key_type(k)); +	} +	exit(0); +} + +static void +do_convert_to(struct passwd *pw) +{ +	Key *k; +	struct stat st; + +	if (!have_identity) +		ask_filename(pw, "Enter file in which the key is"); +	if (stat(identity_file, &st) < 0) +		fatal("%s: %s: %s", __progname, identity_file, strerror(errno));  	if ((k = key_load_public(identity_file, NULL)) == NULL) {  		if ((k = load_identity(identity_file)) == NULL) { -			fprintf(stderr, gettext("load failed\n")); +			fprintf(stderr, "load failed\n");  			exit(1);  		}  	} -	if (key_to_blob(k, &blob, &len) <= 0) { -		fprintf(stderr, gettext("key_to_blob failed\n")); +	if (k->type == KEY_RSA1) { +		fprintf(stderr, "version 1 keys are not supported\n");  		exit(1);  	} -	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); -	fprintf(stdout, gettext( -	    "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n"), -	    key_size(k), key_type(k), -	    pw->pw_name, hostname); -	dump_base64(stdout, blob, len); -	fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); -	key_free(k); -	xfree(blob); + +	switch (convert_format) { +	case FMT_RFC4716: +		do_convert_to_ssh2(pw, k); +		break; +	case FMT_PKCS8: +		do_convert_to_pkcs8(k); +		break; +	case FMT_PEM: +		do_convert_to_pem(k); +		break; +	default: +		fatal("%s: unknown key format %d", __func__, convert_format); +	}  	exit(0);  } +  static void  buffer_get_bignum_bits(Buffer *b, BIGNUM *value)  { @@ -327,24 +396,16 @@ get_line(FILE *fp, char *line, size_t len)  }  static void -do_convert_from_ssh2(struct passwd *pw) +do_convert_from_ssh2(struct passwd *pw, Key **k, int *private)  { -	Key *k;  	int blen;  	u_int len;  	char line[1024];  	u_char blob[8096];  	char encoded[8096]; -	struct stat st; -	int escaped = 0, private = 0, ok; +	int escaped = 0;  	FILE *fp; -	if (!have_identity) -		ask_filename(pw, gettext("Enter file in which the key is")); -	if (stat(identity_file, &st) < 0) { -		perror(identity_file); -		exit(1); -	}  	fp = fopen(identity_file, "r");  	if (fp == NULL) {  		perror(identity_file); @@ -357,7 +418,7 @@ do_convert_from_ssh2(struct passwd *pw)  		if (strncmp(line, "----", 4) == 0 ||  		    strstr(line, ": ") != NULL) {  			if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) -				private = 1; +				*private = 1;  			if (strstr(line, " END ") != NULL) {  				break;  			} @@ -382,26 +443,117 @@ do_convert_from_ssh2(struct passwd *pw)  		fprintf(stderr, gettext("uudecode failed.\n"));  		exit(1);  	} -	k = private ? +	*k = *private ?  	    do_convert_private_ssh2_from_blob(blob, blen) :  	    key_from_blob(blob, blen); -	if (k == NULL) { +	if (*k == NULL) {  		fprintf(stderr, gettext("decode blob failed.\n"));  		exit(1);  	} -	ok = private ? -	    (k->type == KEY_DSA ? -		 PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : -		 PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) : -	    key_write(k, stdout); +	fclose(fp); +} + +static void +do_convert_from_pkcs8(Key **k, int *private) +{ +	EVP_PKEY *pubkey; +	FILE *fp; + +	if ((fp = fopen(identity_file, "r")) == NULL) +		fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); +	if ((pubkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) { +		fatal("%s: %s is not a recognised public key format", __func__, +		    identity_file); +	} +	fclose(fp); +	switch (EVP_PKEY_type(pubkey->type)) { +	case EVP_PKEY_RSA: +		*k = key_new(KEY_UNSPEC); +		(*k)->type = KEY_RSA; +		(*k)->rsa = EVP_PKEY_get1_RSA(pubkey); +		break; +	case EVP_PKEY_DSA: +		*k = key_new(KEY_UNSPEC); +		(*k)->type = KEY_DSA; +		(*k)->dsa = EVP_PKEY_get1_DSA(pubkey); +		break; +	default: +		fatal("%s: unsupported pubkey type %d", __func__, +		    EVP_PKEY_type(pubkey->type)); +	} +	EVP_PKEY_free(pubkey); +	return; +} + +static void +do_convert_from_pem(Key **k, int *private) +{ +	FILE *fp; +	RSA *rsa; + +	if ((fp = fopen(identity_file, "r")) == NULL) +		fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); +	if ((rsa = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL)) != NULL) { +		*k = key_new(KEY_UNSPEC); +		(*k)->type = KEY_RSA; +		(*k)->rsa = rsa; +		fclose(fp); +		return; +	} +	fatal("%s: unrecognised raw private key format", __func__); +} + +static void +do_convert_from(struct passwd *pw) +{ +	Key *k = NULL; +	int private = 0, ok = 0; +	struct stat st; + +	if (!have_identity) +		ask_filename(pw, "Enter file in which the key is"); +	if (stat(identity_file, &st) < 0) +		fatal("%s: %s: %s", __progname, identity_file, strerror(errno)); + +	switch (convert_format) { +	case FMT_RFC4716: +		do_convert_from_ssh2(pw, &k, &private); +		break; +	case FMT_PKCS8: +		do_convert_from_pkcs8(&k, &private); +		break; +	case FMT_PEM: +		do_convert_from_pem(&k, &private); +		break; +	default: +		fatal("%s: unknown key format %d", __func__, convert_format); +	} + +	if (!private) +		ok = key_write(k, stdout); +		if (ok) +			fprintf(stdout, "\n"); +	else { +		switch (k->type) { +		case KEY_DSA: +			ok = PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, +			    NULL, 0, NULL, NULL); +			break; +		case KEY_RSA: +			ok = PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, +			    NULL, 0, NULL, NULL); +			break; +		default: +			fatal("%s: unsupported key type %s", __func__, +			    key_type(k)); +		} +	} +  	if (!ok) { -		fprintf(stderr, gettext("key write failed")); +		fprintf(stderr, "key write failed\n");  		exit(1);  	}  	key_free(k); -	if (!private) -		fprintf(stdout, "\n"); -	fclose(fp);  	exit(0);  } @@ -917,12 +1069,13 @@ usage(void)  	"  -B          Show bubblebabble digest of key file.\n"  	"  -c          Change comment in private and public key files.\n"  	"  -C comment  Provide new comment.\n" -	"  -e          Convert OpenSSH to IETF SECSH key file.\n" +	"  -e          Convert OpenSSH to foreign format key file.\n"  	"  -f filename Filename of the key file.\n"  	"  -F hostname Find hostname in known hosts file.\n"  	"  -H          Hash names in known_hosts file.\n" -	"  -i          Convert IETF SECSH to OpenSSH key file.\n" +	"  -i          Convert foreign format to OpenSSH key file.\n"  	"  -l          Show fingerprint of key file.\n" +	"  -m key_fmt  Conversion format for -e/-i (PEM|PKCS8|RFC4716).\n"  	"  -N phrase   Provide new passphrase.\n"  	"  -p          Change passphrase of private key file.\n"  	"  -P phrase   Provide old passphrase.\n" @@ -974,7 +1127,7 @@ main(int argc, char **argv)  		exit(1);  	} -#define GETOPT_ARGS "BcdeHilpqxXyb:C:f:F:N:P:R:t:" +#define GETOPT_ARGS "BcdeHilpqxXyb:C:f:F:m:N:P:R:t:"  	while ((opt = getopt(argc, argv, GETOPT_ARGS)) != -1) {  		switch (opt) { @@ -1002,6 +1155,21 @@ main(int argc, char **argv)  		case 'B':  			print_bubblebabble = 1;  			break; +		case 'm': +			if (strcasecmp(optarg, "RFC4716") == 0 || +			    strcasecmp(optarg, "ssh2") == 0) { +				convert_format = FMT_RFC4716; +				break; +			} +			if (strcasecmp(optarg, "PKCS8") == 0) { +				convert_format = FMT_PKCS8; +				break; +			} +			if (strcasecmp(optarg, "PEM") == 0) { +				convert_format = FMT_PEM; +				break; +			} +			fatal("Unsupported conversion format \"%s\"", optarg);  		case 'p':  			change_passphrase = 1;  			break; @@ -1027,12 +1195,12 @@ main(int argc, char **argv)  		case 'e':  		case 'x':  			/* export key */ -			convert_to_ssh2 = 1; +			convert_to = 1;  			break;  		case 'i':  		case 'X':  			/* import key */ -			convert_from_ssh2 = 1; +			convert_from = 1;  			break;  		case 'y':  			print_public = 1; @@ -1064,10 +1232,10 @@ main(int argc, char **argv)  		do_change_passphrase(pw);  	if (change_comment)  		do_change_comment(pw); -	if (convert_to_ssh2) -		do_convert_to_ssh2(pw); -	if (convert_from_ssh2) -		do_convert_from_ssh2(pw); +	if (convert_to) +		do_convert_to(pw); +	if (convert_from) +		do_convert_from(pw);  	if (print_public)  		do_print_public(pw); | 
