=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-keygen.c,v retrieving revision 1.1 retrieving revision 1.25.2.2 diff -u -r1.1 -r1.25.2.2 --- src/usr.bin/ssh/ssh-keygen.c 1999/09/26 20:53:37 1.1 +++ src/usr.bin/ssh/ssh-keygen.c 2000/09/01 18:23:23 1.25.2.2 @@ -1,53 +1,51 @@ /* + * 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. + */ -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.1 1999/09/26 20:53:37 deraadt Exp $"); +RCSID("$OpenBSD: ssh-keygen.c,v 1.25.2.2 2000/09/01 18:23:23 jason Exp $"); -#ifndef HAVE_GETHOSTNAME -#include -#endif -#include "randoms.h" -#include "rsa.h" +#include +#include +#include +#include + #include "ssh.h" #include "xmalloc.h" +#include "key.h" +#include "rsa.h" +#include "dsa.h" +#include "authfile.h" +#include "uuencode.h" -/* Generated private key. */ -RSAPrivateKey private_key; - -/* Generated public key. */ -RSAPublicKey public_key; - -/* Random number generator state. */ -RandomState state; - -/* 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; -/* This is set to the identity file name if given on the command line. */ -char *identity_file = NULL; +int quiet = 0; +/* Flag indicating that we just want to see the key fingerprint */ +int print_fingerprint = 0; + +/* The identity file name, given on the command line or entered by the user. */ +char identity_file[1024]; +int have_identity = 0; + /* This is set to the passphrase if given on the command line. */ char *identity_passphrase = NULL; @@ -57,496 +55,686 @@ /* This is set to the new comment if given on the command line. */ char *identity_comment = NULL; -/* Perform changing a passphrase. The argument is the passwd structure - for the current user. */ +/* 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; +int dsa_mode = 0; -void do_change_passphrase(struct passwd *pw) +/* argv0 */ +extern char *__progname; + +char hostname[MAXHOSTNAMELEN]; + +void +ask_filename(struct passwd *pw, const char *prompt) { - char buf[1024], *comment; - RSAPrivateKey private_key; - char *old_passphrase, *passphrase1, *passphrase2; - struct stat st; + char buf[1024]; + snprintf(identity_file, sizeof(identity_file), "%s/%s", + pw->pw_dir, + dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY); + printf("%s (%s): ", prompt, identity_file); + fflush(stdout); + if (fgets(buf, sizeof(buf), stdin) == NULL) + exit(1); + if (strchr(buf, '\n')) + *strchr(buf, '\n') = 0; + if (strcmp(buf, "") != 0) + strlcpy(identity_file, buf, sizeof(identity_file)); + have_identity = 1; +} - /* Read key file name. */ - if (identity_file != NULL) - { - strncpy(buf, identity_file, sizeof(buf)); - buf[sizeof(buf) - 1] = '\0'; - } - else - { - printf("Enter file in which the key is ($HOME/%s): ", - SSH_CLIENT_IDENTITY); - fflush(stdout); - if (fgets(buf, sizeof(buf), stdin) == NULL) - exit(1); - if (strchr(buf, '\n')) - *strchr(buf, '\n') = 0; - if (strcmp(buf, "") == 0) - sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); - } +int +try_load_key(char *filename, Key *k) +{ + int success = 1; + if (!load_private_key(filename, "", k, NULL)) { + char *pass = read_passphrase("Enter passphrase: ", 1); + if (!load_private_key(filename, pass, k, NULL)) { + success = 0; + } + memset(pass, 0, strlen(pass)); + xfree(pass); + } + return success; +} - /* Check if the file exists. */ - if (stat(buf, &st) < 0) - { - perror(buf); - exit(1); - } - - /* Try to load the public key from the file the verify that it is - readable and of the proper format. */ - if (!load_public_key(buf, &public_key, NULL)) - { - printf("%s is not a valid key file.\n", buf); - exit(1); - } - /* Clear the public key since we are just about to load the whole file. */ - rsa_clear_public_key(&public_key); +#define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" +#define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----" - /* Try to load the file with empty passphrase. */ - if (!load_private_key(buf, "", &private_key, &comment)) - { - /* Read passphrase from the user. */ - 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(buf, old_passphrase, &private_key, &comment)) - { - memset(old_passphrase, 0, strlen(old_passphrase)); - xfree(old_passphrase); - printf("Bad passphrase.\n"); - exit(1); +void +do_convert_to_ssh2(struct passwd *pw) +{ + Key *k; + int len; + unsigned char *blob; + 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); } - /* Destroy the passphrase. */ - memset(old_passphrase, 0, strlen(old_passphrase)); - xfree(old_passphrase); - } - printf("Key has comment '%s'\n", comment); - - /* Ask the new passphrase (twice). */ - if (identity_new_passphrase) - { - passphrase1 = xstrdup(identity_new_passphrase); - passphrase2 = NULL; - } - else - { - passphrase1 = - read_passphrase("Enter new passphrase (empty for no passphrase): ", 1); - passphrase2 = read_passphrase("Enter same passphrase again: ", 1); + k = key_new(KEY_DSA); + if (!try_load_key(identity_file, k)) { + fprintf(stderr, "load failed\n"); + exit(1); + } + dsa_make_key_blob(k, &blob, &len); + fprintf(stdout, "%s\n", SSH_COM_MAGIC_BEGIN); + fprintf(stdout, + "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n", + BN_num_bits(k->dsa->p), + pw->pw_name, hostname); + dump_base64(stdout, blob, len); + fprintf(stdout, "%s\n", SSH_COM_MAGIC_END); + key_free(k); + xfree(blob); + exit(0); +} - /* Verify that they are the same. */ - if (strcmp(passphrase1, passphrase2) != 0) - { - memset(passphrase1, 0, strlen(passphrase1)); - memset(passphrase2, 0, strlen(passphrase2)); - xfree(passphrase1); - xfree(passphrase2); - printf("Pass phrases do not match. Try again.\n"); - exit(1); +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; + 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); } - /* Destroy the other copy. */ - memset(passphrase2, 0, strlen(passphrase2)); - xfree(passphrase2); - } + 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) { + fprintf(stderr, "ignore: %s", line); + continue; + } + if (escaped) { + escaped--; + fprintf(stderr, "escaped: %s", line); + continue; + } + *p = '\0'; + strlcat(encoded, line, sizeof(encoded)); + } + blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob)); + if (blen < 0) { + fprintf(stderr, "uudecode failed.\n"); + exit(1); + } + k = dsa_key_from_blob(blob, blen); + if (!key_write(k, stdout)) + fprintf(stderr, "key_write failed"); + key_free(k); + fprintf(stdout, "\n"); + fclose(fp); + exit(0); +} - /* Save the file using the new passphrase. */ - if (!save_private_key(buf, passphrase1, &private_key, comment, &state)) - { - printf("Saving the key failed: %s: %s.\n", - buf, strerror(errno)); - memset(passphrase1, 0, strlen(passphrase1)); - xfree(passphrase1); - rsa_clear_private_key(&private_key); - xfree(comment); - exit(1); - } - /* Destroy the passphrase and the copy of the key in memory. */ - memset(passphrase1, 0, strlen(passphrase1)); - xfree(passphrase1); - rsa_clear_private_key(&private_key); - xfree(comment); +void +do_print_public(struct passwd *pw) +{ + Key *k; + int len; + unsigned char *blob; + struct stat st; - printf("Your identification has been saved with the new passphrase.\n"); - exit(0); + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } + k = key_new(KEY_DSA); + if (!try_load_key(identity_file, k)) { + fprintf(stderr, "load failed\n"); + exit(1); + } + dsa_make_key_blob(k, &blob, &len); + if (!key_write(k, stdout)) + fprintf(stderr, "key_write failed"); + key_free(k); + xfree(blob); + fprintf(stdout, "\n"); + exit(0); } -/* Change the comment of a private key file. */ +void +do_fingerprint(struct passwd *pw) +{ + /* XXX RSA1 only */ -void do_change_comment(struct passwd *pw) + FILE *f; + Key *public; + char *comment = NULL, *cp, *ep, line[16*1024]; + int i, skip = 0, num = 1, invalid = 1; + unsigned int ignore; + 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); + } + public = key_new(KEY_RSA); + if (load_public_key(identity_file, public, &comment)) { + printf("%d %s %s\n", BN_num_bits(public->rsa->n), + key_fingerprint(public), comment); + key_free(public); + exit(0); + } + + 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; + if (auth_rsa_read_key(&cp, &ignore, public->rsa->e, public->rsa->n)) { + invalid = 0; + comment = *cp ? cp : comment; + printf("%d %s %s\n", key_size(public), + key_fingerprint(public), + comment ? comment : "no comment"); + } + } + fclose(f); + } + key_free(public); + if (invalid) { + printf("%s is not a valid key file.\n", identity_file); + exit(1); + } + exit(0); +} + +/* + * Perform changing a passphrase. The argument is the passwd structure + * for the current user. + */ +void +do_change_passphrase(struct passwd *pw) { - char buf[1024], new_comment[1024], *comment; - RSAPrivateKey private_key; - char *passphrase; - struct stat st; - FILE *f; + char *comment; + char *old_passphrase, *passphrase1, *passphrase2; + struct stat st; + Key *private; + Key *public; + int type = dsa_mode ? KEY_DSA : KEY_RSA; - /* Read key file name. */ - if (identity_file) - { - strncpy(buf, identity_file, sizeof(buf)); - buf[sizeof(buf) - 1] = '\0'; - } - else - { - printf("Enter file in which the key is ($HOME/%s): ", - SSH_CLIENT_IDENTITY); - fflush(stdout); - if (fgets(buf, sizeof(buf), stdin) == NULL) - exit(1); - if (strchr(buf, '\n')) - *strchr(buf, '\n') = 0; - if (strcmp(buf, "") == 0) - sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); - } + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); + if (stat(identity_file, &st) < 0) { + perror(identity_file); + exit(1); + } - /* Check if the file exists. */ - if (stat(buf, &st) < 0) - { - perror(buf); - exit(1); - } - - /* Try to load the public key from the file the verify that it is - readable and of the proper format. */ - if (!load_public_key(buf, &public_key, NULL)) - { - printf("%s is not a valid key file.\n", buf); - exit(1); - } + if (type == KEY_RSA) { + /* XXX this works currently only for RSA */ + public = key_new(type); + if (!load_public_key(identity_file, public, NULL)) { + 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. */ + key_free(public); + } - /* Try to load the file with empty passphrase. */ - if (load_private_key(buf, "", &private_key, &comment)) - passphrase = xstrdup(""); - else - { - /* Read passphrase from the user. */ - if (identity_passphrase) - passphrase = xstrdup(identity_passphrase); - else - if (identity_new_passphrase) - passphrase = xstrdup(identity_new_passphrase); - else - passphrase = read_passphrase("Enter passphrase: ", 1); - /* Try to load using the passphrase. */ - if (!load_private_key(buf, passphrase, &private_key, &comment)) - { - memset(passphrase, 0, strlen(passphrase)); - xfree(passphrase); - printf("Bad passphrase.\n"); - exit(1); + /* Try to load the file with empty passphrase. */ + private = key_new(type); + if (!load_private_key(identity_file, "", private, &comment)) { + if (identity_passphrase) + old_passphrase = xstrdup(identity_passphrase); + else + old_passphrase = read_passphrase("Enter old passphrase: ", 1); + if (!load_private_key(identity_file, old_passphrase, private, &comment)) { + memset(old_passphrase, 0, strlen(old_passphrase)); + xfree(old_passphrase); + printf("Bad passphrase.\n"); + exit(1); + } + memset(old_passphrase, 0, strlen(old_passphrase)); + xfree(old_passphrase); } - } - printf("Key now has comment '%s'\n", comment); + printf("Key has comment '%s'\n", comment); - if (identity_comment) - { - strncpy(new_comment, identity_comment, sizeof(new_comment)); - new_comment[sizeof(new_comment) - 1] = '\0'; - } - else - { - printf("Enter new comment: "); - fflush(stdout); - if (!fgets(new_comment, sizeof(new_comment), stdin)) - { - memset(passphrase, 0, strlen(passphrase)); - rsa_clear_private_key(&private_key); - exit(1); + /* Ask the new passphrase (twice). */ + if (identity_new_passphrase) { + passphrase1 = xstrdup(identity_new_passphrase); + passphrase2 = NULL; + } else { + passphrase1 = + read_passphrase("Enter new passphrase (empty for no passphrase): ", 1); + passphrase2 = read_passphrase("Enter same passphrase again: ", 1); + + /* Verify that they are the same. */ + if (strcmp(passphrase1, passphrase2) != 0) { + memset(passphrase1, 0, strlen(passphrase1)); + memset(passphrase2, 0, strlen(passphrase2)); + xfree(passphrase1); + xfree(passphrase2); + printf("Pass phrases do not match. Try again.\n"); + exit(1); + } + /* Destroy the other copy. */ + memset(passphrase2, 0, strlen(passphrase2)); + xfree(passphrase2); } - - /* 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(buf, passphrase, &private_key, new_comment, - &state)) - { - printf("Saving the key failed: %s: %s.\n", - buf, strerror(errno)); - memset(passphrase, 0, strlen(passphrase)); - xfree(passphrase); - rsa_clear_private_key(&private_key); - xfree(comment); - exit(1); - } - /* Destroy the passphrase and the private key in memory. */ - memset(passphrase, 0, strlen(passphrase)); - xfree(passphrase); - rsa_clear_private_key(&private_key); + /* Save the file using the new passphrase. */ + if (!save_private_key(identity_file, passphrase1, private, comment)) { + printf("Saving the key failed: %s: %s.\n", + identity_file, strerror(errno)); + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + 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); + key_free(private); /* Destroys contents */ + xfree(comment); - /* Save the public key in text format in a file with the same name but - .pub appended. */ - strcat(buf, ".pub"); - f = fopen(buf, "w"); - if (!f) - { - printf("Could not save your public key in %s\n", buf); - exit(1); - } - fprintf(f, "%d ", public_key.bits); - mpz_out_str(f, 10, &public_key.e); - fprintf(f, " "); - mpz_out_str(f, 10, &public_key.n); - fprintf(f, " %s\n", new_comment); - fclose(f); + printf("Your identification has been saved with the new passphrase.\n"); + exit(0); +} - xfree(comment); +/* + * Change the comment of a private key file. + */ +void +do_change_comment(struct passwd *pw) +{ + char new_comment[1024], *comment; + Key *private; + Key *public; + char *passphrase; + struct stat st; + FILE *f; - printf("The comment in your key file has been changed.\n"); - exit(0); + 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 public key from the file the verify that it is + * readable and of the proper format. + */ + public = key_new(KEY_RSA); + if (!load_public_key(identity_file, public, NULL)) { + printf("%s is not a valid key file.\n", identity_file); + exit(1); + } + + private = key_new(KEY_RSA); + if (load_private_key(identity_file, "", private, &comment)) + passphrase = xstrdup(""); + else { + if (identity_passphrase) + passphrase = xstrdup(identity_passphrase); + else if (identity_new_passphrase) + passphrase = xstrdup(identity_new_passphrase); + else + passphrase = read_passphrase("Enter passphrase: ", 1); + /* Try to load using the passphrase. */ + if (!load_private_key(identity_file, passphrase, private, &comment)) { + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + printf("Bad passphrase.\n"); + exit(1); + } + } + printf("Key now has comment '%s'\n", comment); + + if (identity_comment) { + strlcpy(new_comment, identity_comment, sizeof(new_comment)); + } else { + printf("Enter new comment: "); + fflush(stdout); + if (!fgets(new_comment, sizeof(new_comment), stdin)) { + memset(passphrase, 0, strlen(passphrase)); + key_free(private); + exit(1); + } + 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, new_comment)) { + printf("Saving the key failed: %s: %s.\n", + identity_file, strerror(errno)); + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + key_free(private); + xfree(comment); + exit(1); + } + memset(passphrase, 0, strlen(passphrase)); + xfree(passphrase); + key_free(private); + + strlcat(identity_file, ".pub", sizeof(identity_file)); + f = fopen(identity_file, "w"); + if (!f) { + printf("Could not save your public key in %s\n", 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); + + printf("The comment in your key file has been changed.\n"); + exit(0); } -/* Main program for key management. */ +void +usage(void) +{ + printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname); + exit(1); +} -int main(int ac, char **av) +/* + * Main program for key management. + */ +int +main(int ac, char **av) { - char buf[16384], buf2[1024], *passphrase1, *passphrase2; - struct passwd *pw; - int opt; - struct stat st; - FILE *f; -#ifdef HAVE_GETHOSTNAME - char hostname[257]; -#else - struct utsname uts; -#endif - extern int optind; - extern char *optarg; + char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2; + struct passwd *pw; + int opt; + struct stat st; + FILE *f; + Key *private; + Key *public; + extern int optind; + extern char *optarg; - /* Get user\'s passwd structure. We need this for the home directory. */ - pw = getpwuid(getuid()); - if (!pw) - { - printf("You don't exist, go away!\n"); - exit(1); - } + SSLeay_add_all_algorithms(); - /* Create ~/.ssh directory if it doesn\'t already exist. */ - sprintf(buf, "%s/%s", pw->pw_dir, SSH_USER_DIR); - if (stat(buf, &st) < 0) - if (mkdir(buf, 0755) < 0) - error("Could not create directory '%s'.", buf); + /* we need this for the home * directory. */ + pw = getpwuid(getuid()); + if (!pw) { + printf("You don't exist, go away!\n"); + exit(1); + } + if (gethostname(hostname, sizeof(hostname)) < 0) { + perror("gethostname"); + exit(1); + } - /* Parse command line arguments. */ - while ((opt = getopt(ac, av, "pcb:f:P:N:C:")) != EOF) - { - switch (opt) - { - case 'b': - bits = atoi(optarg); - if (bits < 512 || bits > 32768) - { - printf("Bits has bad value.\n"); - exit(1); - } - break; + while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) { + switch (opt) { + case 'b': + bits = atoi(optarg); + if (bits < 512 || bits > 32768) { + printf("Bits has bad value.\n"); + exit(1); + } + break; - case 'p': - change_passphrase = 1; - break; + case 'l': + print_fingerprint = 1; + break; - case 'c': - change_comment = 1; - break; + case 'p': + change_passphrase = 1; + break; - case 'f': - identity_file = optarg; - break; - - case 'P': - identity_passphrase = optarg; - break; + case 'c': + change_comment = 1; + break; - case 'N': - identity_new_passphrase = optarg; - break; + case 'f': + strlcpy(identity_file, optarg, sizeof(identity_file)); + have_identity = 1; + break; - case 'C': - identity_comment = optarg; - break; + case 'P': + identity_passphrase = optarg; + break; - case '?': - default: - 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", av[0]); - exit(1); - } - } - if (optind < ac) - { - printf("Too many arguments.\n"); - exit(1); - } - if (change_passphrase && change_comment) - { - printf("Can only have one of -p and -c.\n"); - exit(1); - } + case 'N': + identity_new_passphrase = optarg; + break; - /* If the user requested to change the passphrase, do it now. This - function never returns. */ - if (change_passphrase) - do_change_passphrase(pw); + case 'C': + identity_comment = optarg; + break; - /* If the user requested to change the comment, do it now. This function - never returns. */ - if (change_comment) - do_change_comment(pw); + case 'q': + quiet = 1; + break; - /* Initialize random number generator. This may take a while if the - user has no seed file, so display a message to the user. */ - printf("Initializing random number generator...\n"); - sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_SEEDFILE); - random_initialize(&state, buf); + case 'R': + if (rsa_alive() == 0) + exit(1); + else + exit(0); + break; - /* Save random seed so we don\'t need to do all that time-consuming - environmental noise collection the next time. */ - random_save(&state, buf); + case 'x': + convert_to_ssh2 = 1; + break; - /* Generate the rsa key pair. */ - rsa_generate_key(&private_key, &public_key, &state, bits); + case 'X': + convert_from_ssh2 = 1; + break; - /* Save the state again, just to remove any fear that the previous state - could be used to recreate the key. (That should not be possible anyway - since the pool is stirred after save and some noise is added.) */ - random_save(&state, buf); + case 'y': + print_public = 1; + break; - ask_file_again: + case 'd': + dsa_mode = 1; + break; - /* Ask for a file to save the key in. */ - if (identity_file) - { - strncpy(buf, identity_file, sizeof(buf)); - buf[sizeof(buf) - 1] = '\0'; - } - else - { - printf("Enter file in which to save the key ($HOME/%s): ", - SSH_CLIENT_IDENTITY); - fflush(stdout); - if (fgets(buf, sizeof(buf), stdin) == NULL) - exit(1); - if (strchr(buf, '\n')) - *strchr(buf, '\n') = 0; - if (strcmp(buf, "") == 0) - sprintf(buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); - } + case '?': + default: + usage(); + } + } + if (optind < ac) { + printf("Too many arguments.\n"); + usage(); + } + if (change_passphrase && change_comment) { + printf("Can only have one of -p and -c.\n"); + usage(); + } + /* check if RSA support is needed and exists */ + if (dsa_mode == 0 && rsa_alive() == 0) { + fprintf(stderr, + "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", + __progname); + exit(1); + } + if (print_fingerprint) + do_fingerprint(pw); + if (change_passphrase) + 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 (print_public) + do_print_public(pw); - /* If the file aready exists, ask the user to confirm. */ - if (stat(buf, &st) >= 0) - { - printf("%s already exists.\n", buf); - printf("Overwrite (y/n)? "); - fflush(stdout); - if (fgets(buf2, sizeof(buf2), stdin) == NULL) - exit(1); - if (buf2[0] != 'y' && buf2[0] != 'Y') - exit(1); - } - - /* Ask for a passphrase (twice). */ - if (identity_passphrase) - passphrase1 = xstrdup(identity_passphrase); - else - if (identity_new_passphrase) - passphrase1 = xstrdup(identity_new_passphrase); - else - { - passphrase_again: - passphrase1 = - read_passphrase("Enter passphrase (empty for no passphrase): ", 1); - passphrase2 = read_passphrase("Enter same passphrase again: ", 1); - if (strcmp(passphrase1, passphrase2) != 0) - { - /* The passphrases do not match. Clear them and retry. */ - memset(passphrase1, 0, strlen(passphrase1)); - memset(passphrase2, 0, strlen(passphrase2)); - xfree(passphrase1); - xfree(passphrase2); - printf("Passphrases do not match. Try again.\n"); - goto passphrase_again; - } - /* Clear the other copy of the passphrase. */ - memset(passphrase2, 0, strlen(passphrase2)); - xfree(passphrase2); - } + arc4random_stir(); - /* Create default commend field for the passphrase. The user can later - edit this field. */ - if (identity_comment) - { - strncpy(buf2, identity_comment, sizeof(buf2)); - buf2[sizeof(buf2) - 1] = '\0'; - } - else - { -#ifdef HAVE_GETHOSTNAME - if (gethostname(hostname, sizeof(hostname)) < 0) - { - perror("gethostname"); - exit(1); + if (dsa_mode != 0) { + if (!quiet) + printf("Generating DSA parameter and key.\n"); + public = private = dsa_generate_key(bits); + if (private == NULL) { + fprintf(stderr, "dsa_generate_keys failed"); + exit(1); + } + } else { + if (quiet) + rsa_set_verbose(0); + /* Generate the rsa key pair. */ + public = key_new(KEY_RSA); + private = key_new(KEY_RSA); + rsa_generate_key(private->rsa, public->rsa, bits); } - sprintf(buf2, "%s@%s", pw->pw_name, hostname); -#else - if (uname(&uts) < 0) - { - perror("uname"); - exit(1); + + 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); + if (strstr(identity_file, dotsshdir) != NULL && + stat(dotsshdir, &st) < 0) { + if (mkdir(dotsshdir, 0700) < 0) + error("Could not create directory '%s'.", dotsshdir); + else if (!quiet) + printf("Created directory '%s'.\n", dotsshdir); } - sprintf(buf2, "%s@%s", pw->pw_name, uts.nodename); -#endif - } + /* If the file already exists, ask the user to confirm. */ + if (stat(identity_file, &st) >= 0) { + char yesno[3]; + printf("%s already exists.\n", identity_file); + printf("Overwrite (y/n)? "); + fflush(stdout); + if (fgets(yesno, sizeof(yesno), stdin) == NULL) + exit(1); + if (yesno[0] != 'y' && yesno[0] != 'Y') + exit(1); + } + /* Ask for a passphrase (twice). */ + if (identity_passphrase) + passphrase1 = xstrdup(identity_passphrase); + else if (identity_new_passphrase) + passphrase1 = xstrdup(identity_new_passphrase); + else { +passphrase_again: + passphrase1 = + read_passphrase("Enter passphrase (empty for no passphrase): ", 1); + passphrase2 = read_passphrase("Enter same passphrase again: ", 1); + if (strcmp(passphrase1, passphrase2) != 0) { + /* The passphrases do not match. Clear them and retry. */ + memset(passphrase1, 0, strlen(passphrase1)); + memset(passphrase2, 0, strlen(passphrase2)); + xfree(passphrase1); + xfree(passphrase2); + printf("Passphrases do not match. Try again.\n"); + goto passphrase_again; + } + /* Clear the other copy of the passphrase. */ + memset(passphrase2, 0, strlen(passphrase2)); + xfree(passphrase2); + } - /* Save the key with the given passphrase and comment. */ - if (!save_private_key(buf, passphrase1, &private_key, buf2, &state)) - { - printf("Saving the key failed: %s: %s.\n", - buf, strerror(errno)); - memset(passphrase1, 0, strlen(passphrase1)); - xfree(passphrase1); - goto ask_file_again; - } - /* Clear the passphrase. */ - memset(passphrase1, 0, strlen(passphrase1)); - xfree(passphrase1); + if (identity_comment) { + strlcpy(comment, identity_comment, sizeof(comment)); + } else { + /* Create default commend field for the passphrase. */ + snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); + } - /* Clear the private key and the random number generator. */ - rsa_clear_private_key(&private_key); - random_clear(&state); + /* Save the key with the given passphrase and comment. */ + if (!save_private_key(identity_file, passphrase1, private, comment)) { + printf("Saving the key failed: %s: %s.\n", + identity_file, strerror(errno)); + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); + exit(1); + } + /* Clear the passphrase. */ + memset(passphrase1, 0, strlen(passphrase1)); + xfree(passphrase1); - printf("Your identification has been saved in %s.\n", buf); + /* Clear the private key and the random number generator. */ + if (private != public) { + key_free(private); + } + arc4random_stir(); - /* Display the public key on the screen. */ - printf("Your public key is:\n"); - printf("%d ", public_key.bits); - mpz_out_str(stdout, 10, &public_key.e); - printf(" "); - mpz_out_str(stdout, 10, &public_key.n); - printf(" %s\n", buf2); + 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. */ - strcat(buf, ".pub"); - f = fopen(buf, "w"); - if (!f) - { - printf("Could not save your public key in %s\n", buf); - exit(1); - } - fprintf(f, "%d ", public_key.bits); - mpz_out_str(f, 10, &public_key.e); - fprintf(f, " "); - mpz_out_str(f, 10, &public_key.n); - fprintf(f, " %s\n", buf2); - fclose(f); + strlcat(identity_file, ".pub", sizeof(identity_file)); + f = fopen(identity_file, "w"); + if (!f) { + printf("Could not save your public key in %s\n", identity_file); + exit(1); + } + if (!key_write(public, f)) + fprintf(stderr, "write key failed"); + fprintf(f, " %s\n", comment); + fclose(f); - printf("Your public key has been saved in %s\n", buf); - - exit(0); + if (!quiet) { + printf("Your public key has been saved in %s.\n", + identity_file); + printf("The key fingerprint is:\n"); + printf("%s %s\n", key_fingerprint(public), comment); + } + + key_free(public); + exit(0); }