- char buf[16384], buf2[1024], *passphrase1, *passphrase2;
- struct passwd *pw;
- char *file, *tmpbuf;
- int opt;
- 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;
-
- 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. */
- pw = getpwuid(getuid());
- if (!pw)
- {
- printf("You don't exist, go away!\n");
- 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, "qpclb: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 'l':
- print_fingerprint = 1;
- break;
-
- case 'p':
- change_passphrase = 1;
- break;
-
- case 'c':
- change_comment = 1;
- break;
-
- case 'f':
- identity_file = optarg;
- break;
-
- case 'P':
- identity_passphrase = optarg;
- break;
-
- case 'N':
- identity_new_passphrase = optarg;
- break;
-
- case 'C':
- identity_comment = optarg;
- break;
-
- case 'q':
- quiet = 1;
- 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);
- }
-
- if (print_fingerprint)
- 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);
-
- arc4random_stir();
-
- if (quiet)
- rsa_set_verbose(0);
-
- /* Generate the rsa key pair. */
- private_key = RSA_new();
- public_key = RSA_new();
- rsa_generate_key(private_key, public_key, bits);
-
- ask_file_again:
-
- file = get_filename(pw, "Enter file in which to save the key");
-
- /* If the file aready exists, ask the user to confirm. */
- if (stat(file, &st) >= 0)
- {
- printf("%s already exists.\n", file);
- 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);
- }
-
- /* Create default commend field for the passphrase. The user can later
- edit this field. */
- if (identity_comment)
- {
- strlcpy(buf2, identity_comment, sizeof(buf2));
- }
- else
- {
- if (gethostname(hostname, sizeof(hostname)) < 0)
- {
- perror("gethostname");
- exit(1);
- }
- snprintf(buf2, sizeof buf2, "%s@%s", pw->pw_name, hostname);
- }
-
- /* Save the key with the given passphrase and comment. */
- if (!save_private_key(file, passphrase1, private_key, buf2))
- {
- printf("Saving the key failed: %s: %s.\n",
- file, strerror(errno));
- memset(passphrase1, 0, strlen(passphrase1));
- xfree(passphrase1);
- xfree(file);
- goto ask_file_again;
- }
- /* Clear the passphrase. */
- memset(passphrase1, 0, strlen(passphrase1));
- xfree(passphrase1);
-
- /* Clear the private key and the random number generator. */
- RSA_free(private_key);
- arc4random_stir();
-
- if (!quiet)
- printf("Your identification has been saved in %s.\n", 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");
- if (!f)
- {
- printf("Could not save your public key in %s\n", 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, buf2);
- free(tmpbuf);
- fclose(f);
-
- if (!quiet)
- printf("Your public key has been saved in %s\n", file);
-
- exit(0);
+ char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
+ char out_file[MAXPATHLEN], *reader_id = NULL;
+ char *rr_hostname = NULL;
+ Key *private, *public;
+ struct passwd *pw;
+ struct stat st;
+ int opt, type, fd, download = 0;
+ u_int32_t memory = 0, generator_wanted = 0, trials = 100;
+ int do_gen_candidates = 0, do_screen_candidates = 0;
+ BIGNUM *start = NULL;
+ FILE *f;
+ const char *errstr;
+
+ extern int optind;
+ extern char *optarg;
+
+ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+ sanitise_stdfd();
+
+ __progname = ssh_get_progname(argv[0]);
+
+ SSLeay_add_all_algorithms();
+ log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
+
+ init_rng();
+ seed_rng();
+
+ /* 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);
+ }
+
+ while ((opt = getopt(argc, argv,
+ "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
+ switch (opt) {
+ case 'b':
+ bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr);
+ if (errstr)
+ fatal("Bits has bad value %s (%s)",
+ optarg, errstr);
+ break;
+ case 'F':
+ find_host = 1;
+ rr_hostname = optarg;
+ break;
+ case 'H':
+ hash_hosts = 1;
+ break;
+ case 'R':
+ delete_host = 1;
+ rr_hostname = optarg;
+ break;
+ case 'l':
+ print_fingerprint = 1;
+ break;
+ case 'B':
+ print_bubblebabble = 1;
+ break;
+ case 'p':
+ change_passphrase = 1;
+ break;
+ case 'c':
+ change_comment = 1;
+ break;
+ case 'f':
+ if (strlcpy(identity_file, optarg, sizeof(identity_file)) >=
+ sizeof(identity_file))
+ fatal("Identity filename too long");
+ have_identity = 1;
+ break;
+ case 'g':
+ print_generic = 1;
+ break;
+ case 'P':
+ identity_passphrase = optarg;
+ break;
+ case 'N':
+ identity_new_passphrase = optarg;
+ break;
+ case 'C':
+ identity_comment = optarg;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'e':
+ case 'x':
+ /* export key */
+ convert_to_ssh2 = 1;
+ break;
+ case 'i':
+ case 'X':
+ /* import key */
+ 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 'D':
+ download = 1;
+ /*FALLTHROUGH*/
+ case 'U':
+ reader_id = optarg;
+ break;
+ case 'v':
+ if (log_level == SYSLOG_LEVEL_INFO)
+ log_level = SYSLOG_LEVEL_DEBUG1;
+ else {
+ if (log_level >= SYSLOG_LEVEL_DEBUG1 &&
+ log_level < SYSLOG_LEVEL_DEBUG3)
+ log_level++;
+ }
+ break;
+ case 'r':
+ rr_hostname = optarg;
+ break;
+ case 'W':
+ generator_wanted = (u_int32_t)strtonum(optarg, 1,
+ UINT_MAX, &errstr);
+ if (errstr)
+ fatal("Desired generator has bad value: %s (%s)",
+ optarg, errstr);
+ break;
+ case 'a':
+ trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
+ if (errstr)
+ fatal("Invalid number of trials: %s (%s)",
+ optarg, errstr);
+ break;
+ case 'M':
+ memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr);
+ if (errstr) {
+ fatal("Memory limit is %s: %s", errstr, optarg);
+ }
+ break;
+ case 'G':
+ do_gen_candidates = 1;
+ if (strlcpy(out_file, optarg, sizeof(out_file)) >=
+ sizeof(out_file))
+ fatal("Output filename too long");
+ break;
+ case 'T':
+ do_screen_candidates = 1;
+ if (strlcpy(out_file, optarg, sizeof(out_file)) >=
+ sizeof(out_file))
+ fatal("Output filename too long");
+ break;
+ case 'S':
+ /* XXX - also compare length against bits */
+ if (BN_hex2bn(&start, optarg) == 0)
+ fatal("Invalid start point.");
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ /* reinit */
+ log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1);
+
+ if (optind < argc) {
+ printf("Too many arguments.\n");
+ usage();
+ }
+ if (change_passphrase && change_comment) {
+ printf("Can only have one of -p and -c.\n");
+ usage();
+ }
+ if (print_fingerprint && (delete_host || hash_hosts)) {
+ printf("Cannot use -l with -D or -R.\n");
+ usage();
+ }
+ if (delete_host || hash_hosts || find_host)
+ do_known_hosts(pw, rr_hostname);
+ if (print_fingerprint || print_bubblebabble)
+ 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 (rr_hostname != NULL) {
+ unsigned int n = 0;
+
+ if (have_identity) {
+ n = do_print_resource_record(pw,
+ identity_file, rr_hostname);
+ if (n == 0) {
+ perror(identity_file);
+ exit(1);
+ }
+ exit(0);
+ } else {
+
+ n += do_print_resource_record(pw,
+ _PATH_HOST_RSA_KEY_FILE, rr_hostname);
+ n += do_print_resource_record(pw,
+ _PATH_HOST_DSA_KEY_FILE, rr_hostname);
+
+ if (n == 0)
+ fatal("no keys found.");
+ exit(0);
+ }
+ }
+ if (reader_id != NULL) {
+#ifdef SMARTCARD
+ if (download)
+ do_download(pw, reader_id);
+ else
+ do_upload(pw, reader_id);
+#else /* SMARTCARD */
+ fatal("no support for smartcards.");
+#endif /* SMARTCARD */
+ }
+
+ if (do_gen_candidates) {
+ FILE *out = fopen(out_file, "w");
+
+ if (out == NULL) {
+ error("Couldn't open modulus candidate file \"%s\": %s",
+ out_file, strerror(errno));
+ return (1);
+ }
+ if (bits == 0)
+ bits = DEFAULT_BITS;
+ if (gen_candidates(out, memory, bits, start) != 0)
+ fatal("modulus candidate generation failed");
+
+ return (0);
+ }
+
+ if (do_screen_candidates) {
+ FILE *in;
+ FILE *out = fopen(out_file, "w");
+
+ if (have_identity && strcmp(identity_file, "-") != 0) {
+ if ((in = fopen(identity_file, "r")) == NULL) {
+ fatal("Couldn't open modulus candidate "
+ "file \"%s\": %s", identity_file,
+ strerror(errno));
+ }
+ } else
+ in = stdin;
+
+ if (out == NULL) {
+ fatal("Couldn't open moduli file \"%s\": %s",
+ out_file, strerror(errno));
+ }
+ if (prime_test(in, out, trials, generator_wanted) != 0)
+ fatal("modulus screening failed");
+ return (0);
+ }
+
+ arc4random_stir();
+
+ if (key_type_name == NULL)
+ key_type_name = "rsa";
+
+ 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 (bits == 0)
+ bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS;
+ if (type == KEY_DSA && bits != 1024)
+ fatal("DSA keys must be 1024 bits");
+ 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\n");
+ exit(1);
+ }
+ public = key_from_private(private);
+
+ 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, _PATH_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);
+ }
+ /* 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): ", RP_ALLOW_STDIN);
+ passphrase2 = read_passphrase("Enter same passphrase again: ",
+ RP_ALLOW_STDIN);
+ 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);
+ }
+
+ if (identity_comment) {
+ strlcpy(comment, identity_comment, sizeof(comment));
+ } else {
+ /* Create default comment field for the passphrase. */
+ snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
+ }
+
+ /* Save the key with the given passphrase and comment. */
+ if (!key_save_private(private, identity_file, passphrase1, comment)) {
+ printf("Saving the key failed: %s.\n", identity_file);
+ memset(passphrase1, 0, strlen(passphrase1));
+ xfree(passphrase1);
+ exit(1);
+ }
+ /* Clear the passphrase. */
+ memset(passphrase1, 0, strlen(passphrase1));
+ xfree(passphrase1);
+
+ /* Clear the private key and the random number generator. */
+ key_free(private);
+ arc4random_stir();
+
+ if (!quiet)
+ printf("Your identification has been saved in %s.\n", identity_file);
+
+ strlcat(identity_file, ".pub", sizeof(identity_file));
+ 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);
+ }
+ f = fdopen(fd, "w");
+ if (f == NULL) {
+ printf("fdopen %s failed\n", identity_file);
+ exit(1);
+ }
+ if (!key_write(public, f))
+ fprintf(stderr, "write key failed\n");
+ fprintf(f, " %s\n", comment);
+ fclose(f);
+
+ if (!quiet) {
+ char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
+ char *ra = key_fingerprint(public, SSH_FP_MD5,
+ SSH_FP_RANDOMART);
+ printf("Your public key has been saved in %s.\n",
+ identity_file);
+ printf("The key fingerprint is:\n");
+ printf("%s %s\n", fp, comment);
+ printf("The key's randomart image is:\n");
+ printf("%s\n", ra);
+ xfree(ra);
+ xfree(fp);
+ }
+
+ key_free(public);
+ exit(0);