=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/ssh-keygen.c,v retrieving revision 1.7 retrieving revision 1.11 diff -u -r1.7 -r1.11 --- src/usr.bin/ssh/ssh-keygen.c 1999/11/16 22:27:54 1.7 +++ src/usr.bin/ssh/ssh-keygen.c 1999/11/21 21:58:31 1.11 @@ -14,11 +14,12 @@ */ #include "includes.h" -RCSID("$Id: ssh-keygen.c,v 1.7 1999/11/16 22:27:54 markus Exp $"); +RCSID("$Id: ssh-keygen.c,v 1.11 1999/11/21 21:58:31 markus Exp $"); #include "rsa.h" #include "ssh.h" #include "xmalloc.h" +#include "fingerprint.h" /* Generated private key. */ RSA *private_key; @@ -40,9 +41,13 @@ int quiet = 0; -/* This is set to the identity file name if given on the command line. */ -char *identity_file = NULL; +/* 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; @@ -52,54 +57,102 @@ /* 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. */ +/* argv0 */ +extern char *__progname; -char * -get_filename(struct passwd *pw, const char *prompt) +void +ask_filename(struct passwd *pw, const char *prompt) { - char buf[1024], default_file[1024]; + 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); + 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) { - return xstrdup(identity_file); - } else { - snprintf(default_file, sizeof default_file, "%s/%s", - pw->pw_dir, SSH_CLIENT_IDENTITY); - printf("%s (%s): ", prompt, default_file); - fflush(stdout); - if (fgets(buf, sizeof(buf), stdin) == NULL) +void +do_fingerprint(struct passwd *pw) +{ + char *comment; + RSA *public_key; + 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); - if (strchr(buf, '\n')) - *strchr(buf, '\n') = 0; - if (strcmp(buf, "") == 0) - return xstrdup(default_file); + } + 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; + } + if (invalid) { + printf("%s is not a valid key file.\n", identity_file); + BN_free(e); + BN_free(n); + exit(1); + } } - return xstrdup(buf); + + printf("%d %s %s\n", BN_num_bits(public_key->n), + fingerprint(public_key->e, public_key->n), + comment); + 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 *file, *comment; + char *comment; char *old_passphrase, *passphrase1, *passphrase2; struct stat st; RSA *private_key; - file = get_filename(pw, "Enter file in which the key is"); + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); /* Check if the file exists. */ - if (stat(file, &st) < 0) + if (stat(identity_file, &st) < 0) { - perror(file); + 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(file, public_key, NULL)) + if (!load_public_key(identity_file, public_key, NULL)) { - printf("%s is not a valid key file.\n", file); + 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. */ @@ -107,14 +160,14 @@ /* Try to load the file with empty passphrase. */ private_key = RSA_new(); - if (!load_private_key(file, "", private_key, &comment)) { + if (!load_private_key(identity_file, "", 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(file, old_passphrase, private_key, &comment)) + if (!load_private_key(identity_file, old_passphrase, private_key, &comment)) { memset(old_passphrase, 0, strlen(old_passphrase)); xfree(old_passphrase); @@ -155,10 +208,10 @@ } /* Save the file using the new passphrase. */ - if (!save_private_key(file, passphrase1, private_key, comment)) + if (!save_private_key(identity_file, passphrase1, private_key, comment)) { printf("Saving the key failed: %s: %s.\n", - file, strerror(errno)); + identity_file, strerror(errno)); memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); RSA_free(private_key); @@ -180,33 +233,34 @@ void do_change_comment(struct passwd *pw) { - char new_comment[1024], *file, *comment; + char new_comment[1024], *comment; RSA *private_key; char *passphrase; struct stat st; FILE *f; char *tmpbuf; - file = get_filename(pw, "Enter file in which the key is"); + if (!have_identity) + ask_filename(pw, "Enter file in which the key is"); /* Check if the file exists. */ - if (stat(file, &st) < 0) + if (stat(identity_file, &st) < 0) { - perror(file); + 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(file, public_key, NULL)) + if (!load_public_key(identity_file, public_key, NULL)) { - printf("%s is not a valid key file.\n", file); + 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(file, "", private_key, &comment)) + if (load_private_key(identity_file, "", private_key, &comment)) passphrase = xstrdup(""); else { @@ -219,7 +273,7 @@ else passphrase = read_passphrase("Enter passphrase: ", 1); /* Try to load using the passphrase. */ - if (!load_private_key(file, passphrase, private_key, &comment)) + if (!load_private_key(identity_file, passphrase, private_key, &comment)) { memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); @@ -250,10 +304,10 @@ } /* Save the file using the new passphrase. */ - if (!save_private_key(file, passphrase, private_key, new_comment)) + if (!save_private_key(identity_file, passphrase, private_key, new_comment)) { printf("Saving the key failed: %s: %s.\n", - file, strerror(errno)); + identity_file, strerror(errno)); memset(passphrase, 0, strlen(passphrase)); xfree(passphrase); RSA_free(private_key); @@ -268,11 +322,11 @@ /* Save the public key in text format in a file with the same name but .pub appended. */ - strcat(file, ".pub"); - f = fopen(file, "w"); + strlcat(identity_file, ".pub", sizeof(identity_file)); + f = fopen(identity_file, "w"); if (!f) { - printf("Could not save your public key in %s\n", file); + printf("Could not save your public key in %s\n", identity_file); exit(1); } fprintf(f, "%d ", BN_num_bits(public_key->n)); @@ -290,14 +344,22 @@ exit(0); } +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); + exit(1); +} + /* Main program for key management. */ int main(int ac, char **av) { - char buf[16384], buf2[1024], *passphrase1, *passphrase2; + char dotsshdir[16*1024], comment[1024], *passphrase1, *passphrase2; struct passwd *pw; - char *file, *tmpbuf; + char *tmpbuf; int opt; struct stat st; FILE *f; @@ -323,14 +385,8 @@ exit(1); } - /* Create ~/.ssh directory if it doesn\'t already exist. */ - snprintf(buf, sizeof 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); - /* Parse command line arguments. */ - while ((opt = getopt(ac, av, "qpcb:f:P:N:C:")) != EOF) + while ((opt = getopt(ac, av, "qpclb:f:P:N:C:")) != EOF) { switch (opt) { @@ -343,6 +399,10 @@ } break; + case 'l': + print_fingerprint = 1; + break; + case 'p': change_passphrase = 1; break; @@ -352,7 +412,8 @@ break; case 'f': - identity_file = optarg; + strlcpy(identity_file, optarg, sizeof(identity_file)); + have_identity = 1; break; case 'P': @@ -373,22 +434,23 @@ 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); + usage(); } } if (optind < ac) { printf("Too many arguments.\n"); - exit(1); + usage(); } if (change_passphrase && change_comment) { printf("Can only have one of -p and -c.\n"); - exit(1); + usage(); } + if (print_fingerprint) + do_fingerprint(pw); + /* If the user requested to change the passphrase, do it now. This function never returns. */ if (change_passphrase) @@ -409,19 +471,29 @@ public_key = RSA_new(); rsa_generate_key(private_key, public_key, bits); - ask_file_again: + if (!have_identity) + ask_filename(pw, "Enter file in which to save the key"); - file = get_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, 0755) < 0) + error("Could not create directory '%s'.", dotsshdir); + else if(!quiet) + printf("Created directory '%s'.\n", dotsshdir); + } - /* If the file aready exists, ask the user to confirm. */ - if (stat(file, &st) >= 0) + /* If the file already exists, ask the user to confirm. */ + if (stat(identity_file, &st) >= 0) { - printf("%s already exists.\n", file); + char yesno[3]; + printf("%s already exists.\n", identity_file); printf("Overwrite (y/n)? "); fflush(stdout); - if (fgets(buf2, sizeof(buf2), stdin) == NULL) + if (fgets(yesno, sizeof(yesno), stdin) == NULL) exit(1); - if (buf2[0] != 'y' && buf2[0] != 'Y') + if (yesno[0] != 'y' && yesno[0] != 'Y') exit(1); } @@ -456,7 +528,7 @@ edit this field. */ if (identity_comment) { - strlcpy(buf2, identity_comment, sizeof(buf2)); + strlcpy(comment, identity_comment, sizeof(comment)); } else { @@ -465,18 +537,17 @@ perror("gethostname"); exit(1); } - snprintf(buf2, sizeof buf2, "%s@%s", pw->pw_name, hostname); + snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); } /* Save the key with the given passphrase and comment. */ - if (!save_private_key(file, passphrase1, private_key, buf2)) + if (!save_private_key(identity_file, passphrase1, private_key, comment)) { printf("Saving the key failed: %s: %s.\n", - file, strerror(errno)); + identity_file, strerror(errno)); memset(passphrase1, 0, strlen(passphrase1)); xfree(passphrase1); - xfree(file); - goto ask_file_again; + exit(1); } /* Clear the passphrase. */ memset(passphrase1, 0, strlen(passphrase1)); @@ -487,27 +558,15 @@ arc4random_stir(); if (!quiet) - printf("Your identification has been saved in %s.\n", file); + printf("Your identification has been saved in %s.\n", identity_file); - /* Display the public key on the screen. */ - if (!quiet) { - printf("Your public key is:\n"); - printf("%d ", BN_num_bits(public_key->n)); - tmpbuf = BN_bn2dec(public_key->e); - printf("%s ", tmpbuf); - free(tmpbuf); - tmpbuf = BN_bn2dec(public_key->n); - printf("%s %s\n", tmpbuf, buf2); - free(tmpbuf); - } - /* Save the public key in text format in a file with the same name but .pub appended. */ - strcat(file, ".pub"); - f = fopen(file, "w"); + strlcat(identity_file, ".pub", sizeof(identity_file)); + f = fopen(identity_file, "w"); if (!f) { - printf("Could not save your public key in %s\n", file); + printf("Could not save your public key in %s\n", identity_file); exit(1); } fprintf(f, "%d ", BN_num_bits(public_key->n)); @@ -515,12 +574,17 @@ fprintf(f, "%s ", tmpbuf); free(tmpbuf); tmpbuf = BN_bn2dec(public_key->n); - fprintf(f, "%s %s\n", tmpbuf, buf2); + fprintf(f, "%s %s\n", tmpbuf, comment); free(tmpbuf); fclose(f); - if (!quiet) - printf("Your public key has been saved in %s\n", file); + if (!quiet) { + 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); + } exit(0); }