=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-keygen.c,v retrieving revision 1.12 retrieving revision 1.54 diff -u -r1.12 -r1.54 --- src/usr.bin/ssh/ssh-keygen.c 1999/11/23 22:25:55 1.12 +++ src/usr.bin/ssh/ssh-keygen.c 2001/04/03 13:56:11 1.54 @@ -1,48 +1,53 @@ /* + * Author: Tatu Ylonen + * Copyright (c) 1994 Tatu Ylonen , Espoo, Finland + * All rights reserved + * Identity and host key generation and maintenance. + * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ -ssh-keygen.c - -Author: Tatu Ylonen - -Copyright (c) 1994 Tatu Ylonen , Espoo, Finland - All rights reserved - -Created: Mon Mar 27 02:26:40 1995 ylo - -Identity and host key generation and maintenance. - -*/ - #include "includes.h" -RCSID("$Id: ssh-keygen.c,v 1.12 1999/11/23 22:25:55 markus Exp $"); +RCSID("$OpenBSD: ssh-keygen.c,v 1.54 2001/04/03 13:56:11 stevesk Exp $"); -#include "rsa.h" -#include "ssh.h" +#include +#include + #include "xmalloc.h" -#include "fingerprint.h" +#include "key.h" +#include "rsa.h" +#include "authfile.h" +#include "uuencode.h" +#include "buffer.h" +#include "bufaux.h" +#include "pathnames.h" +#include "log.h" +#include "readpass.h" -/* Generated private key. */ -RSA *private_key; - -/* Generated public key. */ -RSA *public_key; - -/* Number of bits in the RSA key. This value can be changed on the command - line. */ +/* Number of bits in the RSA/DSA key. This value can be changed on the command line. */ int bits = 1024; -/* Flag indicating that we just want to change the passphrase. This can be - set on the command line. */ +/* + * Flag indicating that we just want to change the passphrase. This can be + * set on the command line. + */ int change_passphrase = 0; -/* Flag indicating that we just want to change the comment. This can be set - on the command line. */ +/* + * Flag indicating that we just want to change the comment. This can be set + * on the command line. + */ int change_comment = 0; int quiet = 0; /* Flag indicating that we just want to see the key fingerprint */ int print_fingerprint = 0; +int print_bubblebabble = 0; /* The identity file name, given on the command line or entered by the user. */ char identity_file[1024]; @@ -57,17 +62,43 @@ /* 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; +int print_public = 0; + +/* default to RSA for SSH-1 */ +char *key_type_name = "rsa1"; + /* argv0 */ extern char *__progname; +char hostname[MAXHOSTNAMELEN]; + void ask_filename(struct passwd *pw, const char *prompt) { char buf[1024]; - snprintf(identity_file, sizeof(identity_file), "%s/%s", - pw->pw_dir, SSH_CLIENT_IDENTITY); - printf("%s (%s): ", prompt, identity_file); - fflush(stdout); + char *name = NULL; + + switch (key_type_from_name(key_type_name)) { + case KEY_RSA1: + name = _PATH_SSH_CLIENT_IDENTITY; + break; + case KEY_DSA: + name = _PATH_SSH_CLIENT_ID_DSA; + break; + case KEY_RSA: + name = _PATH_SSH_CLIENT_ID_RSA; + break; + default: + fprintf(stderr, "bad key type"); + exit(1); + break; + } + snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); + fprintf(stderr, "%s (%s): ", prompt, identity_file); + fflush(stderr); if (fgets(buf, sizeof(buf), stdin) == NULL) exit(1); if (strchr(buf, '\n')) @@ -77,11 +108,33 @@ have_identity = 1; } +Key * +try_load_pem_key(char *filename) +{ + char *pass; + Key *prv; + + prv = key_load_private(filename, "", NULL); + if (prv == NULL) { + pass = read_passphrase("Enter passphrase: ", 1); + prv = key_load_private(filename, pass, NULL); + memset(pass, 0, strlen(pass)); + xfree(pass); + } + return prv; +} + +#define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" +#define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" +#define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" +#define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb + void -do_fingerprint(struct passwd *pw) +do_convert_to_ssh2(struct passwd *pw) { - char *comment; - RSA *public_key; + Key *prv; + int len; + u_char *blob; struct stat st; if (!have_identity) @@ -90,87 +143,343 @@ perror(identity_file); exit(1); } - public_key = RSA_new(); - if (!load_public_key(identity_file, public_key, &comment)) { - char *cp, line[1024]; - BIGNUM *e, *n; - int dummy, invalid = 0; - FILE *f = fopen(identity_file, "r"); - n = BN_new(); - e = BN_new(); - if (f && fgets(line, sizeof(line), f)) { - cp = line; - line[strlen(line) - 1] = '\0'; - if (auth_rsa_read_key(&cp, &dummy, e, n)) { - public_key->e = e; - public_key->n = n; - comment = xstrdup(cp ? cp : "no comment"); - } else { - invalid = 1; - } - } else { - invalid = 1; + prv = try_load_pem_key(identity_file); + if (prv == NULL) { + fprintf(stderr, "load failed\n"); + exit(1); + } + key_to_blob(prv, &blob, &len); + fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); + fprintf(stdout, + "Comment: \"%d-bit %s, converted from OpenSSH by %s@%s\"\n", + key_size(prv), key_type(prv), + pw->pw_name, hostname); + dump_base64(stdout, blob, len); + fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); + key_free(prv); + xfree(blob); + exit(0); +} + +void +buffer_get_bignum_bits(Buffer *b, BIGNUM *value) +{ + int bits = buffer_get_int(b); + int bytes = (bits + 7) / 8; + + if (buffer_len(b) < bytes) + fatal("buffer_get_bignum_bits: input buffer too small: " + "need %d have %d", bytes, buffer_len(b)); + BN_bin2bn((u_char *)buffer_ptr(b), bytes, value); + buffer_consume(b, bytes); +} + +Key * +do_convert_private_ssh2_from_blob(char *blob, int blen) +{ + Buffer b; + Key *key = NULL; + int ignore, magic, rlen, ktype; + char *type, *cipher; + + buffer_init(&b); + buffer_append(&b, blob, blen); + + magic = buffer_get_int(&b); + if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { + error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); + buffer_free(&b); + return NULL; + } + ignore = buffer_get_int(&b); + type = buffer_get_string(&b, NULL); + cipher = buffer_get_string(&b, NULL); + ignore = buffer_get_int(&b); + ignore = buffer_get_int(&b); + ignore = buffer_get_int(&b); + + if (strcmp(cipher, "none") != 0) { + error("unsupported cipher %s", cipher); + xfree(cipher); + buffer_free(&b); + xfree(type); + return NULL; + } + xfree(cipher); + + if (strstr(type, "dsa")) { + ktype = KEY_DSA; + } else if (strstr(type, "rsa")) { + ktype = KEY_RSA; + } else { + xfree(type); + return NULL; + } + key = key_new_private(ktype); + xfree(type); + + switch (key->type) { + case KEY_DSA: + buffer_get_bignum_bits(&b, key->dsa->p); + buffer_get_bignum_bits(&b, key->dsa->g); + buffer_get_bignum_bits(&b, key->dsa->q); + buffer_get_bignum_bits(&b, key->dsa->pub_key); + buffer_get_bignum_bits(&b, key->dsa->priv_key); + break; + case KEY_RSA: + if (!BN_set_word(key->rsa->e, (u_long) buffer_get_char(&b))) { + buffer_free(&b); + key_free(key); + return NULL; } - if (invalid) { - printf("%s is not a valid key file.\n", identity_file); - BN_free(e); - BN_free(n); + buffer_get_bignum_bits(&b, key->rsa->d); + buffer_get_bignum_bits(&b, key->rsa->n); + buffer_get_bignum_bits(&b, key->rsa->iqmp); + buffer_get_bignum_bits(&b, key->rsa->q); + buffer_get_bignum_bits(&b, key->rsa->p); + generate_additional_parameters(key->rsa); + break; + } + rlen = buffer_len(&b); + if(rlen != 0) + error("do_convert_private_ssh2_from_blob: " + "remaining bytes in key blob %d", rlen); + buffer_free(&b); +#ifdef DEBUG_PK + { + u_int slen; + u_char *sig, data[10] = "abcde12345"; + + key_sign(key, &sig, &slen, data, sizeof data); + key_verify(key, sig, slen, data, sizeof data); + xfree(sig); + } +#endif + return key; +} + +void +do_convert_from_ssh2(struct passwd *pw) +{ + Key *k; + int blen; + char line[1024], *p; + char blob[8096]; + char encoded[8096]; + struct stat st; + int escaped = 0, private = 0, ok; + FILE *fp; + + if (!have_identity) + ask_filename(pw, "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); + exit(1); + } + encoded[0] = '\0'; + while (fgets(line, sizeof(line), fp)) { + if (!(p = strchr(line, '\n'))) { + fprintf(stderr, "input line too long.\n"); exit(1); } + if (p > line && p[-1] == '\\') + escaped++; + if (strncmp(line, "----", 4) == 0 || + strstr(line, ": ") != NULL) { + if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) + private = 1; + fprintf(stderr, "ignore: %s", line); + continue; + } + if (escaped) { + escaped--; + fprintf(stderr, "escaped: %s", line); + continue; + } + *p = '\0'; + strlcat(encoded, line, sizeof(encoded)); } - printf("%d %s %s\n", BN_num_bits(public_key->n), - fingerprint(public_key->e, public_key->n), - comment); - RSA_free(public_key); + blen = uudecode(encoded, (u_char *)blob, sizeof(blob)); + if (blen < 0) { + fprintf(stderr, "uudecode failed.\n"); + exit(1); + } + k = private ? + do_convert_private_ssh2_from_blob(blob, blen) : + key_from_blob(blob, blen); + if (k == NULL) { + fprintf(stderr, "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); + if (!ok) { + fprintf(stderr, "key write failed"); + exit(1); + } + key_free(k); + fprintf(stdout, "\n"); + fclose(fp); exit(0); } -/* Perform changing a passphrase. The argument is the passwd structure - for the current user. */ +void +do_print_public(struct passwd *pw) +{ + Key *prv; + struct stat st; + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + prv = try_load_pem_key(identity_file); + if (prv == NULL) { + fprintf(stderr, "load failed\n"); + exit(1); + } + if (!key_write(prv, stdout)) + fprintf(stderr, "key_write failed"); + key_free(prv); + fprintf(stdout, "\n"); + exit(0); +} + void -do_change_passphrase(struct passwd *pw) +do_fingerprint(struct passwd *pw) { - char *comment; - char *old_passphrase, *passphrase1, *passphrase2; + FILE *f; + Key *public; + char *comment = NULL, *cp, *ep, line[16*1024], *fp; + int i, skip = 0, num = 1, invalid = 1, rep, fptype; struct stat st; - RSA *private_key; + fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; + rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; + if (!have_identity) ask_filename(pw, "Enter file in which the key is"); - /* Check if the file exists. */ if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } - /* Try to load the public key from the file the verify that it is - readable and of the proper format. */ - public_key = RSA_new(); - if (!load_public_key(identity_file, public_key, NULL)) { + public = key_load_public(identity_file, &comment); + if (public != NULL) { + fp = key_fingerprint(public, fptype, rep); + printf("%d %s %s\n", key_size(public), fp, comment); + key_free(public); + xfree(comment); + xfree(fp); + exit(0); + } + if (comment) + xfree(comment); + + f = fopen(identity_file, "r"); + if (f != NULL) { + while (fgets(line, sizeof(line), f)) { + i = strlen(line) - 1; + if (line[i] != '\n') { + error("line %d too long: %.40s...", num, line); + skip = 1; + continue; + } + num++; + if (skip) { + skip = 0; + continue; + } + line[i] = '\0'; + + /* Skip leading whitespace, empty and comment lines. */ + for (cp = line; *cp == ' ' || *cp == '\t'; cp++) + ; + if (!*cp || *cp == '\n' || *cp == '#') + continue ; + i = strtol(cp, &ep, 10); + if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { + int quoted = 0; + comment = cp; + for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { + if (*cp == '\\' && cp[1] == '"') + cp++; /* Skip both */ + else if (*cp == '"') + quoted = !quoted; + } + if (!*cp) + continue; + *cp++ = '\0'; + } + ep = cp; + public = key_new(KEY_RSA1); + if (key_read(public, &cp) != 1) { + cp = ep; + key_free(public); + public = key_new(KEY_UNSPEC); + if (key_read(public, &cp) != 1) { + key_free(public); + continue; + } + } + comment = *cp ? cp : comment; + fp = key_fingerprint(public, fptype, rep); + printf("%d %s %s\n", key_size(public), fp, + comment ? comment : "no comment"); + xfree(fp); + key_free(public); + invalid = 0; + } + fclose(f); + } + if (invalid) { printf("%s is not a valid key file.\n", identity_file); exit(1); } - /* Clear the public key since we are just about to load the whole file. */ - RSA_free(public_key); + exit(0); +} +/* + * Perform changing a passphrase. The argument is the passwd structure + * for the current user. + */ +void +do_change_passphrase(struct passwd *pw) +{ + char *comment; + char *old_passphrase, *passphrase1, *passphrase2; + struct stat st; + Key *private; + + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } /* Try to load the file with empty passphrase. */ - private_key = RSA_new(); - if (!load_private_key(identity_file, "", private_key, &comment)) { - /* Read passphrase from the user. */ + private = key_load_private(identity_file, "", &comment); + if (private == NULL) { if (identity_passphrase) old_passphrase = xstrdup(identity_passphrase); else old_passphrase = read_passphrase("Enter old passphrase: ", 1); - /* Try to load using the passphrase. */ - if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) { - memset(old_passphrase, 0, strlen(old_passphrase)); - xfree(old_passphrase); + private = key_load_private(identity_file, old_passphrase , &comment); + memset(old_passphrase, 0, strlen(old_passphrase)); + xfree(old_passphrase); + if (private == NULL) { printf("Bad passphrase.\n"); exit(1); } - /* Destroy the passphrase. */ - memset(old_passphrase, 0, strlen(old_passphrase)); - xfree(old_passphrase); } printf("Key has comment '%s'\n", comment); @@ -198,57 +507,46 @@ } /* Save the file using the new passphrase. */ - if (!save_private_key(identity_file, passphrase1, private_key, comment)) { + if (!key_save_private(private, identity_file, passphrase1, comment)) { printf("Saving the key failed: %s: %s.\n", identity_file, strerror(errno)); memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); - RSA_free(private_key); + key_free(private); xfree(comment); exit(1); } /* Destroy the passphrase and the copy of the key in memory. */ memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); - RSA_free(private_key); /* Destroys contents */ + key_free(private); /* Destroys contents */ xfree(comment); printf("Your identification has been saved with the new passphrase.\n"); exit(0); } -/* Change the comment of a private key file. */ - +/* + * Change the comment of a private key file. + */ void do_change_comment(struct passwd *pw) { - char new_comment[1024], *comment; - RSA *private_key; - char *passphrase; + char new_comment[1024], *comment, *passphrase; + Key *private; + Key *public; struct stat st; FILE *f; - char *tmpbuf; + int fd; if (!have_identity) ask_filename(pw, "Enter file in which the key is"); - /* Check if the file exists. */ if (stat(identity_file, &st) < 0) { perror(identity_file); exit(1); } - /* Try to load the public key from the file the verify that it is - readable and of the proper format. */ - public_key = RSA_new(); - if (!load_public_key(identity_file, public_key, NULL)) { - printf("%s is not a valid key file.\n", identity_file); - exit(1); - } - private_key = RSA_new(); - /* Try to load the file with empty passphrase. */ - if (load_private_key(identity_file, "", private_key, &comment)) - passphrase = xstrdup(""); - else { - /* Read passphrase from the user. */ + private = key_load_private(identity_file, "", &comment); + if (private == NULL) { if (identity_passphrase) passphrase = xstrdup(identity_passphrase); else if (identity_new_passphrase) @@ -256,13 +554,21 @@ else passphrase = read_passphrase("Enter passphrase: ", 1); /* Try to load using the passphrase. */ - if (!load_private_key(identity_file, passphrase, private_key, &comment)) { + private = key_load_private(identity_file, passphrase, &comment); + if (private == NULL) { memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); printf("Bad passphrase.\n"); exit(1); } + } else { + passphrase = xstrdup(""); } + if (private->type != KEY_RSA1) { + fprintf(stderr, "Comments are only supported for RSA1 keys.\n"); + key_free(private); + exit(1); + } printf("Key now has comment '%s'\n", comment); if (identity_comment) { @@ -272,44 +578,43 @@ fflush(stdout); if (!fgets(new_comment, sizeof(new_comment), stdin)) { memset(passphrase, 0, strlen(passphrase)); - RSA_free(private_key); + key_free(private); exit(1); } - /* Remove terminating newline from comment. */ if (strchr(new_comment, '\n')) *strchr(new_comment, '\n') = 0; } /* Save the file using the new passphrase. */ - if (!save_private_key(identity_file, passphrase, private_key, new_comment)) { + if (!key_save_private(private, identity_file, passphrase, new_comment)) { printf("Saving the key failed: %s: %s.\n", identity_file, strerror(errno)); memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); - RSA_free(private_key); + key_free(private); xfree(comment); exit(1); } - /* Destroy the passphrase and the private key in memory. */ memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); - RSA_free(private_key); + public = key_from_private(private); + key_free(private); - /* Save the public key in text format in a file with the same name - but .pub appended. */ strlcat(identity_file, ".pub", sizeof(identity_file)); - f = fopen(identity_file, "w"); - if (!f) { + fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { printf("Could not save your public key in %s\n", identity_file); exit(1); } - fprintf(f, "%d ", BN_num_bits(public_key->n)); - tmpbuf = BN_bn2dec(public_key->e); - fprintf(f, "%s ", tmpbuf); - free(tmpbuf); - tmpbuf = BN_bn2dec(public_key->n); - fprintf(f, "%s %s\n", tmpbuf, new_comment); - free(tmpbuf); + f = fdopen(fd, "w"); + if (f == NULL) { + printf("fdopen %s failed", identity_file); + exit(1); + } + if (!key_write(public, f)) + fprintf(stderr, "write key failed"); + key_free(public); + fprintf(f, " %s\n", new_comment); fclose(f); xfree(comment); @@ -321,44 +626,41 @@ void usage(void) { - printf("ssh-keygen version %s\n", SSH_VERSION); - printf("Usage: %s [-b bits] [-p] [-c] [-f file] [-P pass] [-N new-pass] [-C comment]\n", __progname); + printf("Usage: %s [-lBpqxXyc] [-t type] [-b bits] [-f file] [-C comment] " + "[-N new-pass] [-P pass]\n", __progname); exit(1); } -/* Main program for key management. */ - +/* + * Main program for key management. + */ int main(int ac, char **av) { char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2; + Key *private, *public; struct passwd *pw; - char *tmpbuf; - int opt; + int opt, type, fd; struct stat st; FILE *f; - char hostname[MAXHOSTNAMELEN]; + extern int optind; extern char *optarg; - /* check if RSA support exists */ - if (rsa_alive() == 0) { - extern char *__progname; + SSLeay_add_all_algorithms(); - fprintf(stderr, - "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", - __progname); - exit(1); - } - /* Get user\'s passwd structure. We need this for the home - directory. */ + /* we need this for the home * directory. */ pw = getpwuid(getuid()); if (!pw) { printf("You don't exist, go away!\n"); exit(1); } - /* Parse command line arguments. */ - while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) { + if (gethostname(hostname, sizeof(hostname)) < 0) { + perror("gethostname"); + exit(1); + } + + while ((opt = getopt(ac, av, "dqpclBRxXyb:f:t:P:N:C:")) != -1) { switch (opt) { case 'b': bits = atoi(optarg); @@ -372,6 +674,10 @@ print_fingerprint = 1; break; + case 'B': + print_bubblebabble = 1; + break; + case 'p': change_passphrase = 1; break; @@ -401,6 +707,31 @@ quiet = 1; break; + case 'R': + /* unused */ + exit(0); + break; + + case 'x': + convert_to_ssh2 = 1; + break; + + case 'X': + convert_from_ssh2 = 1; + break; + + case 'y': + print_public = 1; + break; + + case 'd': + key_type_name = "dsa"; + break; + + case 't': + key_type_name = optarg; + break; + case '?': default: usage(); @@ -414,37 +745,43 @@ printf("Can only have one of -p and -c.\n"); usage(); } - if (print_fingerprint) + if (print_fingerprint || print_bubblebabble) do_fingerprint(pw); - - /* If the user requested to change the passphrase, do it now. - This function never returns. */ if (change_passphrase) do_change_passphrase(pw); - - /* If the user requested to change the comment, do it now. This - function never returns. */ 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 (print_public) + do_print_public(pw); arc4random_stir(); - if (quiet) - rsa_set_verbose(0); + type = key_type_from_name(key_type_name); + if (type == KEY_UNSPEC) { + fprintf(stderr, "unknown key type %s\n", key_type_name); + exit(1); + } + if (!quiet) + printf("Generating public/private %s key pair.\n", key_type_name); + private = key_generate(type, bits); + if (private == NULL) { + fprintf(stderr, "key_generate failed"); + exit(1); + } + public = key_from_private(private); - /* Generate the rsa key pair. */ - private_key = RSA_new(); - public_key = RSA_new(); - rsa_generate_key(private_key, public_key, bits); - if (!have_identity) ask_filename(pw, "Enter file in which to save the key"); /* Create ~/.ssh directory if it doesn\'t already exist. */ - snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR); + snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); if (strstr(identity_file, dotsshdir) != NULL && stat(dotsshdir, &st) < 0) { - if (mkdir(dotsshdir, 0755) < 0) + if (mkdir(dotsshdir, 0700) < 0) error("Could not create directory '%s'.", dotsshdir); else if (!quiet) printf("Created directory '%s'.\n", dotsshdir); @@ -484,22 +821,17 @@ xfree(passphrase2); } - /* Create default commend field for the passphrase. The user can - later edit this field. */ if (identity_comment) { strlcpy(comment, identity_comment, sizeof(comment)); } else { - if (gethostname(hostname, sizeof(hostname)) < 0) { - perror("gethostname"); - exit(1); - } + /* Create default commend field for the passphrase. */ snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); } /* Save the key with the given passphrase and comment. */ - if (!save_private_key(identity_file, passphrase1, private_key, comment)) { + if (!key_save_private(private, identity_file, passphrase1, comment)) { printf("Saving the key failed: %s: %s.\n", - identity_file, strerror(errno)); + identity_file, strerror(errno)); memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); exit(1); @@ -509,35 +841,37 @@ xfree(passphrase1); /* Clear the private key and the random number generator. */ - RSA_free(private_key); + key_free(private); arc4random_stir(); if (!quiet) printf("Your identification has been saved in %s.\n", identity_file); - /* Save the public key in text format in a file with the same name - but .pub appended. */ strlcat(identity_file, ".pub", sizeof(identity_file)); - f = fopen(identity_file, "w"); - if (!f) { + fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { printf("Could not save your public key in %s\n", identity_file); exit(1); } - fprintf(f, "%d ", BN_num_bits(public_key->n)); - tmpbuf = BN_bn2dec(public_key->e); - fprintf(f, "%s ", tmpbuf); - free(tmpbuf); - tmpbuf = BN_bn2dec(public_key->n); - fprintf(f, "%s %s\n", tmpbuf, comment); - free(tmpbuf); + f = fdopen(fd, "w"); + if (f == NULL) { + printf("fdopen %s failed", identity_file); + exit(1); + } + if (!key_write(public, f)) + fprintf(stderr, "write key failed"); + fprintf(f, " %s\n", comment); fclose(f); if (!quiet) { - printf("Your public key has been saved in %s.\n", identity_file); + char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); + printf("Your public key has been saved in %s.\n", + identity_file); printf("The key fingerprint is:\n"); - printf("%d %s %s\n", BN_num_bits(public_key->n), - fingerprint(public_key->e, public_key->n), - comment); + printf("%s %s\n", fp, comment); + xfree(fp); } + + key_free(public); exit(0); }