1 /*
   2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
   3  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
   4  *                    All rights reserved
   5  * Identity and host key generation and maintenance.
   6  *
   7  * As far as I am concerned, the code I have written for this software
   8  * can be used freely for any purpose.  Any derived versions of this
   9  * software must be clearly marked as such, and if the derived work is
  10  * incompatible with the protocol description in the RFC file, it must be
  11  * called by a name other than "ssh" or "Secure Shell".
  12  */
  13 
  14 /* $OpenBSD: ssh-keygen.c,v 1.160 2007/01/21 01:41:54 stevesk Exp $ */
  15 
  16 #include "includes.h"
  17 #include <openssl/evp.h>
  18 #include <openssl/pem.h>
  19 
  20 #include "xmalloc.h"
  21 #include "key.h"
  22 #include "rsa.h"
  23 #include "authfile.h"
  24 #include "uuencode.h"
  25 #include "buffer.h"
  26 #include "bufaux.h"
  27 #include "pathnames.h"
  28 #include "log.h"
  29 #include "readpass.h"
  30 #include "misc.h"
  31 #include <langinfo.h>
  32 #include "match.h"
  33 #include "hostfile.h"
  34 #include "tildexpand.h"
  35 
  36 /* Number of bits in the RSA/DSA key.  This value can be set on the command line. */
  37 #define DEFAULT_BITS_RSA        2048
  38 #define DEFAULT_BITS_DSA        1024
  39 u_int32_t bits = 0;
  40 
  41 /*
  42  * Flag indicating that we just want to change the passphrase.  This can be
  43  * set on the command line.
  44  */
  45 int change_passphrase = 0;
  46 
  47 /*
  48  * Flag indicating that we just want to change the comment.  This can be set
  49  * on the command line.
  50  */
  51 int change_comment = 0;
  52 
  53 int quiet = 0;
  54 
  55 /* Flag indicating that we want to hash a known_hosts file */
  56 int hash_hosts = 0;
  57 /* Flag indicating that we want to lookup a host in known_hosts file */
  58 int find_host = 0;
  59 /* Flag indicating that we want to delete a host from a known_hosts file */
  60 int delete_host = 0;
  61 
  62 /* Flag indicating that we just want to see the key fingerprint */
  63 int print_fingerprint = 0;
  64 int print_bubblebabble = 0;
  65 
  66 /* The identity file name, given on the command line or entered by the user. */
  67 char identity_file[1024];
  68 int have_identity = 0;
  69 
  70 /* This is set to the passphrase if given on the command line. */
  71 char *identity_passphrase = NULL;
  72 
  73 /* This is set to the new passphrase if given on the command line. */
  74 char *identity_new_passphrase = NULL;
  75 
  76 /* This is set to the new comment if given on the command line. */
  77 char *identity_comment = NULL;
  78 
  79 /* Dump public key file in format used by real and the original SSH 2 */
  80 int convert_to_ssh2 = 0;
  81 int convert_from_ssh2 = 0;
  82 int print_public = 0;
  83 
  84 char *key_type_name = NULL;
  85 
  86 /* argv0 */
  87 #ifdef HAVE___PROGNAME
  88 extern char *__progname;
  89 #else
  90 char *__progname;
  91 #endif
  92 
  93 char hostname[MAXHOSTNAMELEN];
  94 
  95 static void
  96 ask_filename(struct passwd *pw, const char *prompt)
  97 {
  98         char buf[1024];
  99         char *name = NULL;
 100 
 101         if (key_type_name == NULL)
 102                 name = _PATH_SSH_CLIENT_ID_RSA;
 103         else {
 104                 switch (key_type_from_name(key_type_name)) {
 105                 case KEY_RSA1:
 106                         name = _PATH_SSH_CLIENT_IDENTITY;
 107                         break;
 108                 case KEY_DSA:
 109                         name = _PATH_SSH_CLIENT_ID_DSA;
 110                         break;
 111                 case KEY_RSA:
 112                         name = _PATH_SSH_CLIENT_ID_RSA;
 113                         break;
 114                 default:
 115                         fprintf(stderr, gettext("bad key type"));
 116                         exit(1);
 117                         break;
 118                 }
 119         }
 120         snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name);
 121         fprintf(stderr, "%s (%s): ", gettext(prompt), identity_file);
 122         if (fgets(buf, sizeof(buf), stdin) == NULL)
 123                 exit(1);
 124         if (strchr(buf, '\n'))
 125                 *strchr(buf, '\n') = 0;
 126         if (strcmp(buf, "") != 0)
 127                 strlcpy(identity_file, buf, sizeof(identity_file));
 128         have_identity = 1;
 129 }
 130 
 131 static Key *
 132 load_identity(char *filename)
 133 {
 134         char *pass;
 135         Key *prv;
 136 
 137         prv = key_load_private(filename, "", NULL);
 138         if (prv == NULL) {
 139                 if (identity_passphrase)
 140                         pass = xstrdup(identity_passphrase);
 141                 else
 142                         pass = read_passphrase(gettext("Enter passphrase: "),
 143                             RP_ALLOW_STDIN);
 144                 prv = key_load_private(filename, pass, NULL);
 145                 memset(pass, 0, strlen(pass));
 146                 xfree(pass);
 147         }
 148         return prv;
 149 }
 150 
 151 #define SSH_COM_PUBLIC_BEGIN            "---- BEGIN SSH2 PUBLIC KEY ----"
 152 #define SSH_COM_PUBLIC_END              "---- END SSH2 PUBLIC KEY ----"
 153 #define SSH_COM_PRIVATE_BEGIN           "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----"
 154 #define SSH_COM_PRIVATE_KEY_MAGIC       0x3f6ff9eb
 155 
 156 static void
 157 do_convert_to_ssh2(struct passwd *pw)
 158 {
 159         Key *k;
 160         u_int len;
 161         u_char *blob;
 162         struct stat st;
 163 
 164         if (!have_identity)
 165                 ask_filename(pw, gettext("Enter file in which the key is"));
 166         if (stat(identity_file, &st) < 0) {
 167                 perror(identity_file);
 168                 exit(1);
 169         }
 170         if ((k = key_load_public(identity_file, NULL)) == NULL) {
 171                 if ((k = load_identity(identity_file)) == NULL) {
 172                         fprintf(stderr, gettext("load failed\n"));
 173                         exit(1);
 174                 }
 175         }
 176         if (key_to_blob(k, &blob, &len) <= 0) {
 177                 fprintf(stderr, gettext("key_to_blob failed\n"));
 178                 exit(1);
 179         }
 180         fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN);
 181         fprintf(stdout, gettext(
 182             "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n"),
 183             key_size(k), key_type(k),
 184             pw->pw_name, hostname);
 185         dump_base64(stdout, blob, len);
 186         fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END);
 187         key_free(k);
 188         xfree(blob);
 189         exit(0);
 190 }
 191 
 192 static void
 193 buffer_get_bignum_bits(Buffer *b, BIGNUM *value)
 194 {
 195         u_int bignum_bits = buffer_get_int(b);
 196         u_int bytes = (bignum_bits + 7) / 8;
 197 
 198         if (buffer_len(b) < bytes)
 199                 fatal("buffer_get_bignum_bits: input buffer too small: "
 200                     "need %d have %d", bytes, buffer_len(b));
 201         if (BN_bin2bn(buffer_ptr(b), bytes, value) == NULL)
 202                 fatal("buffer_get_bignum_bits: BN_bin2bn failed");
 203         buffer_consume(b, bytes);
 204 }
 205 
 206 static Key *
 207 do_convert_private_ssh2_from_blob(u_char *blob, u_int blen)
 208 {
 209         Buffer b;
 210         Key *key = NULL;
 211         char *type, *cipher;
 212         u_char *sig, data[] = "abcde12345";
 213         int magic, rlen, ktype, i1, i2, i3, i4;
 214         u_int slen;
 215         u_long e;
 216 
 217         buffer_init(&b);
 218         buffer_append(&b, blob, blen);
 219 
 220         magic  = buffer_get_int(&b);
 221         if (magic != SSH_COM_PRIVATE_KEY_MAGIC) {
 222                 error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC);
 223                 buffer_free(&b);
 224                 return NULL;
 225         }
 226         i1 = buffer_get_int(&b);
 227         type   = buffer_get_string(&b, NULL);
 228         cipher = buffer_get_string(&b, NULL);
 229         i2 = buffer_get_int(&b);
 230         i3 = buffer_get_int(&b);
 231         i4 = buffer_get_int(&b);
 232         debug("ignore (%d %d %d %d)", i1, i2, i3, i4);
 233         if (strcmp(cipher, "none") != 0) {
 234                 error("unsupported cipher %s", cipher);
 235                 xfree(cipher);
 236                 buffer_free(&b);
 237                 xfree(type);
 238                 return NULL;
 239         }
 240         xfree(cipher);
 241 
 242         if (strstr(type, "dsa")) {
 243                 ktype = KEY_DSA;
 244         } else if (strstr(type, "rsa")) {
 245                 ktype = KEY_RSA;
 246         } else {
 247                 buffer_free(&b);
 248                 xfree(type);
 249                 return NULL;
 250         }
 251         key = key_new_private(ktype);
 252         xfree(type);
 253 
 254         switch (key->type) {
 255         case KEY_DSA:
 256                 buffer_get_bignum_bits(&b, key->dsa->p);
 257                 buffer_get_bignum_bits(&b, key->dsa->g);
 258                 buffer_get_bignum_bits(&b, key->dsa->q);
 259                 buffer_get_bignum_bits(&b, key->dsa->pub_key);
 260                 buffer_get_bignum_bits(&b, key->dsa->priv_key);
 261                 break;
 262         case KEY_RSA:
 263                 e  = buffer_get_char(&b);
 264                 debug("e %lx", e);
 265                 if (e < 30) {
 266                         e <<= 8;
 267                         e += buffer_get_char(&b);
 268                         debug("e %lx", e);
 269                         e <<= 8;
 270                         e += buffer_get_char(&b);
 271                         debug("e %lx", e);
 272                 }
 273                 if (!BN_set_word(key->rsa->e, e)) {
 274                         buffer_free(&b);
 275                         key_free(key);
 276                         return NULL;
 277                 }
 278                 buffer_get_bignum_bits(&b, key->rsa->d);
 279                 buffer_get_bignum_bits(&b, key->rsa->n);
 280                 buffer_get_bignum_bits(&b, key->rsa->iqmp);
 281                 buffer_get_bignum_bits(&b, key->rsa->q);
 282                 buffer_get_bignum_bits(&b, key->rsa->p);
 283                 rsa_generate_additional_parameters(key->rsa);
 284                 break;
 285         }
 286         rlen = buffer_len(&b);
 287         if (rlen != 0)
 288                 error("do_convert_private_ssh2_from_blob: "
 289                     "remaining bytes in key blob %d", rlen);
 290         buffer_free(&b);
 291 
 292         /* try the key */
 293         key_sign(key, &sig, &slen, data, sizeof(data));
 294         key_verify(key, sig, slen, data, sizeof(data));
 295         xfree(sig);
 296         return key;
 297 }
 298 
 299 static int
 300 get_line(FILE *fp, char *line, size_t len)
 301 {
 302         int c;
 303         size_t pos = 0;
 304 
 305         line[0] = '\0';
 306         while ((c = fgetc(fp)) != EOF) {
 307                 if (pos >= len - 1) {
 308                         fprintf(stderr, "input line too long.\n");
 309                         exit(1);
 310                 }
 311                 switch (c) {
 312                 case '\r':
 313                         c = fgetc(fp);
 314                         if (c != EOF && c != '\n' && ungetc(c, fp) == EOF) {
 315                                 fprintf(stderr, "unget: %s\n", strerror(errno));
 316                                 exit(1);
 317                         }
 318                         return pos;
 319                 case '\n':
 320                         return pos;
 321                 }
 322                 line[pos++] = c;
 323                 line[pos] = '\0';
 324         }
 325         /* We reached EOF */
 326         return -1;
 327 }
 328 
 329 static void
 330 do_convert_from_ssh2(struct passwd *pw)
 331 {
 332         Key *k;
 333         int blen;
 334         u_int len;
 335         char line[1024];
 336         u_char blob[8096];
 337         char encoded[8096];
 338         struct stat st;
 339         int escaped = 0, private = 0, ok;
 340         FILE *fp;
 341 
 342         if (!have_identity)
 343                 ask_filename(pw, gettext("Enter file in which the key is"));
 344         if (stat(identity_file, &st) < 0) {
 345                 perror(identity_file);
 346                 exit(1);
 347         }
 348         fp = fopen(identity_file, "r");
 349         if (fp == NULL) {
 350                 perror(identity_file);
 351                 exit(1);
 352         }
 353         encoded[0] = '\0';
 354         while ((blen = get_line(fp, line, sizeof(line))) != -1) {
 355                 if (line[blen - 1] == '\\')
 356                         escaped++;
 357                 if (strncmp(line, "----", 4) == 0 ||
 358                     strstr(line, ": ") != NULL) {
 359                         if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL)
 360                                 private = 1;
 361                         if (strstr(line, " END ") != NULL) {
 362                                 break;
 363                         }
 364                         /* fprintf(stderr, "ignore: %s", line); */
 365                         continue;
 366                 }
 367                 if (escaped) {
 368                         escaped--;
 369                         /* fprintf(stderr, "escaped: %s", line); */
 370                         continue;
 371                 }
 372                 strlcat(encoded, line, sizeof(encoded));
 373         }
 374         len = strlen(encoded);
 375         if (((len % 4) == 3) &&
 376             (encoded[len-1] == '=') &&
 377             (encoded[len-2] == '=') &&
 378             (encoded[len-3] == '='))
 379                 encoded[len-3] = '\0';
 380         blen = uudecode(encoded, blob, sizeof(blob));
 381         if (blen < 0) {
 382                 fprintf(stderr, gettext("uudecode failed.\n"));
 383                 exit(1);
 384         }
 385         k = private ?
 386             do_convert_private_ssh2_from_blob(blob, blen) :
 387             key_from_blob(blob, blen);
 388         if (k == NULL) {
 389                 fprintf(stderr, gettext("decode blob failed.\n"));
 390                 exit(1);
 391         }
 392         ok = private ?
 393             (k->type == KEY_DSA ?
 394                  PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) :
 395                  PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) :
 396             key_write(k, stdout);
 397         if (!ok) {
 398                 fprintf(stderr, gettext("key write failed"));
 399                 exit(1);
 400         }
 401         key_free(k);
 402         if (!private)
 403                 fprintf(stdout, "\n");
 404         fclose(fp);
 405         exit(0);
 406 }
 407 
 408 static void
 409 do_print_public(struct passwd *pw)
 410 {
 411         Key *prv;
 412         struct stat st;
 413 
 414         if (!have_identity)
 415                 ask_filename(pw, gettext("Enter file in which the key is"));
 416         if (stat(identity_file, &st) < 0) {
 417                 perror(identity_file);
 418                 exit(1);
 419         }
 420         prv = load_identity(identity_file);
 421         if (prv == NULL) {
 422                 fprintf(stderr, gettext("load failed\n"));
 423                 exit(1);
 424         }
 425         if (!key_write(prv, stdout))
 426                 fprintf(stderr, gettext("key_write failed"));
 427         key_free(prv);
 428         fprintf(stdout, "\n");
 429         exit(0);
 430 }
 431 
 432 static void
 433 do_fingerprint(struct passwd *pw)
 434 {
 435         FILE *f;
 436         Key *public;
 437         char *comment = NULL, *cp, *ep, line[16*1024], *fp;
 438         int i, skip = 0, num = 1, invalid = 1;
 439         enum fp_rep rep;
 440         enum fp_type fptype;
 441         struct stat st;
 442 
 443         fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
 444         rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
 445 
 446         if (!have_identity)
 447                 ask_filename(pw, gettext("Enter file in which the key is"));
 448         if (stat(identity_file, &st) < 0) {
 449                 perror(identity_file);
 450                 exit(1);
 451         }
 452         public = key_load_public(identity_file, &comment);
 453         if (public != NULL) {
 454                 fp = key_fingerprint(public, fptype, rep);
 455                 printf("%u %s %s\n", key_size(public), fp, comment);
 456                 key_free(public);
 457                 xfree(comment);
 458                 xfree(fp);
 459                 exit(0);
 460         }
 461         if (comment) {
 462                 xfree(comment);
 463                 comment = NULL;
 464         }
 465 
 466         f = fopen(identity_file, "r");
 467         if (f != NULL) {
 468                 while (fgets(line, sizeof(line), f)) {
 469                         i = strlen(line) - 1;
 470                         if (line[i] != '\n') {
 471                                 error("line %d too long: %.40s...", num, line);
 472                                 skip = 1;
 473                                 continue;
 474                         }
 475                         num++;
 476                         if (skip) {
 477                                 skip = 0;
 478                                 continue;
 479                         }
 480                         line[i] = '\0';
 481 
 482                         /* Skip leading whitespace, empty and comment lines. */
 483                         for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
 484                                 ;
 485                         if (!*cp || *cp == '\n' || *cp == '#')
 486                                 continue;
 487                         i = strtol(cp, &ep, 10);
 488                         if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) {
 489                                 int quoted = 0;
 490                                 comment = cp;
 491                                 for (; *cp && (quoted || (*cp != ' ' &&
 492                                     *cp != '\t')); cp++) {
 493                                         if (*cp == '\\' && cp[1] == '"')
 494                                                 cp++;   /* Skip both */
 495                                         else if (*cp == '"')
 496                                                 quoted = !quoted;
 497                                 }
 498                                 if (!*cp)
 499                                         continue;
 500                                 *cp++ = '\0';
 501                         }
 502                         ep = cp;
 503                         public = key_new(KEY_RSA1);
 504                         if (key_read(public, &cp) != 1) {
 505                                 cp = ep;
 506                                 key_free(public);
 507                                 public = key_new(KEY_UNSPEC);
 508                                 if (key_read(public, &cp) != 1) {
 509                                         key_free(public);
 510                                         continue;
 511                                 }
 512                         }
 513                         comment = *cp ? cp : comment;
 514                         fp = key_fingerprint(public, fptype, rep);
 515                         printf("%u %s %s\n", key_size(public), fp,
 516                             comment ? comment : gettext("no comment"));
 517                         xfree(fp);
 518                         key_free(public);
 519                         invalid = 0;
 520                 }
 521                 fclose(f);
 522         }
 523         if (invalid) {
 524                 printf(gettext("%s is not a public key file.\n"),
 525                        identity_file);
 526                 exit(1);
 527         }
 528         exit(0);
 529 }
 530 
 531 static void
 532 print_host(FILE *f, const char *name, Key *public, int hash)
 533 {
 534         if (hash && (name = host_hash(name, NULL, 0)) == NULL)
 535                 fatal("hash_host failed");
 536         fprintf(f, "%s ", name);
 537         if (!key_write(public, f))
 538                 fatal("key_write failed");
 539         fprintf(f, "\n");
 540 }
 541 
 542 static void
 543 do_known_hosts(struct passwd *pw, const char *name)
 544 {
 545         FILE *in, *out = stdout;
 546         Key *public;
 547         char *cp, *cp2, *kp, *kp2;
 548         char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
 549         int c, i, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
 550 
 551         if (!have_identity) {
 552                 cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
 553                 if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
 554                     sizeof(identity_file))
 555                         fatal("Specified known hosts path too long");
 556                 xfree(cp);
 557                 have_identity = 1;
 558         }
 559         if ((in = fopen(identity_file, "r")) == NULL)
 560                 fatal("fopen: %s", strerror(errno));
 561 
 562         /*
 563          * Find hosts goes to stdout, hash and deletions happen in-place
 564          * A corner case is ssh-keygen -HF foo, which should go to stdout
 565          */
 566         if (!find_host && (hash_hosts || delete_host)) {
 567                 if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
 568                     strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
 569                     strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
 570                     strlcat(old, ".old", sizeof(old)) >= sizeof(old))
 571                         fatal("known_hosts path too long");
 572                 umask(077);
 573                 if ((c = mkstemp(tmp)) == -1)
 574                         fatal("mkstemp: %s", strerror(errno));
 575                 if ((out = fdopen(c, "w")) == NULL) {
 576                         c = errno;
 577                         unlink(tmp);
 578                         fatal("fdopen: %s", strerror(c));
 579                 }
 580                 inplace = 1;
 581         }
 582 
 583         while (fgets(line, sizeof(line), in)) {
 584                 num++;
 585                 i = strlen(line) - 1;
 586                 if (line[i] != '\n') {
 587                         error("line %d too long: %.40s...", num, line);
 588                         skip = 1;
 589                         invalid = 1;
 590                         continue;
 591                 }
 592                 if (skip) {
 593                         skip = 0;
 594                         continue;
 595                 }
 596                 line[i] = '\0';
 597 
 598                 /* Skip leading whitespace, empty and comment lines. */
 599                 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
 600                         ;
 601                 if (!*cp || *cp == '\n' || *cp == '#') {
 602                         if (inplace)
 603                                 fprintf(out, "%s\n", cp);
 604                         continue;
 605                 }
 606                 /* Find the end of the host name portion. */
 607                 for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
 608                         ;
 609                 if (*kp == '\0' || *(kp + 1) == '\0') {
 610                         error("line %d missing key: %.40s...",
 611                             num, line);
 612                         invalid = 1;
 613                         continue;
 614                 }
 615                 *kp++ = '\0';
 616                 kp2 = kp;
 617 
 618                 public = key_new(KEY_RSA1);
 619                 if (key_read(public, &kp) != 1) {
 620                         kp = kp2;
 621                         key_free(public);
 622                         public = key_new(KEY_UNSPEC);
 623                         if (key_read(public, &kp) != 1) {
 624                                 error("line %d invalid key: %.40s...",
 625                                     num, line);
 626                                 key_free(public);
 627                                 invalid = 1;
 628                                 continue;
 629                         }
 630                 }
 631 
 632                 if (*cp == HASH_DELIM) {
 633                         if (find_host || delete_host) {
 634                                 cp2 = host_hash(name, cp, strlen(cp));
 635                                 if (cp2 == NULL) {
 636                                         error("line %d: invalid hashed "
 637                                             "name: %.64s...", num, line);
 638                                         invalid = 1;
 639                                         continue;
 640                                 }
 641                                 c = (strcmp(cp2, cp) == 0);
 642                                 if (find_host && c) {
 643                                         printf(gettext("# Host %s found: "
 644                                             "line %d type %s\n"), name,
 645                                             num, key_type(public));
 646                                         print_host(out, cp, public, 0);
 647                                 }
 648                                 if (delete_host && !c)
 649                                         print_host(out, cp, public, 0);
 650                         } else if (hash_hosts)
 651                                 print_host(out, cp, public, 0);
 652                 } else {
 653                         if (find_host || delete_host) {
 654                                 c = (match_hostname(name, cp,
 655                                     strlen(cp)) == 1);
 656                                 if (find_host && c) {
 657                                         printf(gettext("# Host %s found: "
 658                                             "line %d type %s\n"), name,
 659                                             num, key_type(public));
 660                                         print_host(out, name, public, hash_hosts);
 661                                 }
 662                                 if (delete_host && !c)
 663                                         print_host(out, cp, public, 0);
 664                         } else if (hash_hosts) {
 665                                 for (cp2 = strsep(&cp, ",");
 666                                     cp2 != NULL && *cp2 != '\0';
 667                                     cp2 = strsep(&cp, ",")) {
 668                                         if (strcspn(cp2, "*?!") != strlen(cp2))
 669                                                 fprintf(stderr, gettext("Warning: "
 670                                                    "ignoring host name with "
 671                                                    "metacharacters: %.64s\n"),
 672                                                     cp2);
 673                                         else
 674                                                 print_host(out, cp2, public, 1);
 675                                 }
 676                                 has_unhashed = 1;
 677                         }
 678                 }
 679                 key_free(public);
 680         }
 681         fclose(in);
 682 
 683         if (invalid) {
 684                 fprintf(stderr, gettext("%s is not a valid known_host file.\n"),
 685                     identity_file);
 686                 if (inplace) {
 687                         fprintf(stderr, gettext("Not replacing existing known_hosts "
 688                            "file because of errors\n"));
 689                         fclose(out);
 690                         unlink(tmp);
 691                 }
 692                 exit(1);
 693         }
 694 
 695         if (inplace) {
 696                 fclose(out);
 697 
 698                 /* Backup existing file */
 699                 if (unlink(old) == -1 && errno != ENOENT)
 700                         fatal("unlink %.100s: %s", old, strerror(errno));
 701                 if (link(identity_file, old) == -1)
 702                         fatal("link %.100s to %.100s: %s", identity_file, old,
 703                             strerror(errno));
 704                 /* Move new one into place */
 705                 if (rename(tmp, identity_file) == -1) {
 706                         error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
 707                             strerror(errno));
 708                         unlink(tmp);
 709                         unlink(old);
 710                         exit(1);
 711                 }
 712 
 713                 fprintf(stderr, gettext("%s updated.\n"), identity_file);
 714                 fprintf(stderr, gettext("Original contents retained as %s\n"), old);
 715                 if (has_unhashed) {
 716                         fprintf(stderr, gettext("WARNING: %s contains unhashed "
 717                             "entries\n"), old);
 718                         fprintf(stderr, gettext("Delete this file to ensure privacy "
 719                             "of hostnames\n"));
 720                 }
 721         }
 722 
 723         exit(0);
 724 }
 725 
 726 /*
 727  * Perform changing a passphrase.  The argument is the passwd structure
 728  * for the current user.
 729  */
 730 static void
 731 do_change_passphrase(struct passwd *pw)
 732 {
 733         char *comment;
 734         char *old_passphrase, *passphrase1, *passphrase2;
 735         struct stat st;
 736         Key *private;
 737 
 738         if (!have_identity)
 739                 ask_filename(pw, gettext("Enter file in which the key is"));
 740         if (stat(identity_file, &st) < 0) {
 741                 perror(identity_file);
 742                 exit(1);
 743         }
 744         /* Try to load the file with empty passphrase. */
 745         private = key_load_private(identity_file, "", &comment);
 746         if (private == NULL) {
 747                 if (identity_passphrase)
 748                         old_passphrase = xstrdup(identity_passphrase);
 749                 else
 750                         old_passphrase =
 751                             read_passphrase(gettext("Enter old passphrase: "),
 752                             RP_ALLOW_STDIN);
 753                 private = key_load_private(identity_file, old_passphrase,
 754                     &comment);
 755                 memset(old_passphrase, 0, strlen(old_passphrase));
 756                 xfree(old_passphrase);
 757                 if (private == NULL) {
 758                         printf(gettext("Bad passphrase.\n"));
 759                         exit(1);
 760                 }
 761         }
 762         printf(gettext("Key has comment '%s'\n"), comment);
 763 
 764         /* Ask the new passphrase (twice). */
 765         if (identity_new_passphrase) {
 766                 passphrase1 = xstrdup(identity_new_passphrase);
 767                 passphrase2 = NULL;
 768         } else {
 769                 passphrase1 =
 770                         read_passphrase(gettext("Enter new passphrase (empty"
 771                             " for no passphrase): "), RP_ALLOW_STDIN);
 772                 passphrase2 = read_passphrase(gettext("Enter same "
 773                             "passphrase again: "), RP_ALLOW_STDIN);
 774 
 775                 /* Verify that they are the same. */
 776                 if (strcmp(passphrase1, passphrase2) != 0) {
 777                         memset(passphrase1, 0, strlen(passphrase1));
 778                         memset(passphrase2, 0, strlen(passphrase2));
 779                         xfree(passphrase1);
 780                         xfree(passphrase2);
 781                         printf(gettext("Pass phrases do not match.  Try "
 782                             "again.\n"));
 783                         exit(1);
 784                 }
 785                 /* Destroy the other copy. */
 786                 memset(passphrase2, 0, strlen(passphrase2));
 787                 xfree(passphrase2);
 788         }
 789 
 790         /* Save the file using the new passphrase. */
 791         if (!key_save_private(private, identity_file, passphrase1, comment)) {
 792                 printf(gettext("Saving the key failed: %s.\n"), identity_file);
 793                 memset(passphrase1, 0, strlen(passphrase1));
 794                 xfree(passphrase1);
 795                 key_free(private);
 796                 xfree(comment);
 797                 exit(1);
 798         }
 799         /* Destroy the passphrase and the copy of the key in memory. */
 800         memset(passphrase1, 0, strlen(passphrase1));
 801         xfree(passphrase1);
 802         key_free(private);               /* Destroys contents */
 803         xfree(comment);
 804 
 805         printf(gettext("Your identification has been saved with the new "
 806             "passphrase.\n"));
 807         exit(0);
 808 }
 809 
 810 /*
 811  * Change the comment of a private key file.
 812  */
 813 static void
 814 do_change_comment(struct passwd *pw)
 815 {
 816         char new_comment[1024], *comment, *passphrase;
 817         Key *private;
 818         Key *public;
 819         struct stat st;
 820         FILE *f;
 821         int fd;
 822 
 823         if (!have_identity)
 824                 ask_filename(pw, gettext("Enter file in which the key is"));
 825         if (stat(identity_file, &st) < 0) {
 826                 perror(identity_file);
 827                 exit(1);
 828         }
 829         private = key_load_private(identity_file, "", &comment);
 830         if (private == NULL) {
 831                 if (identity_passphrase)
 832                         passphrase = xstrdup(identity_passphrase);
 833                 else if (identity_new_passphrase)
 834                         passphrase = xstrdup(identity_new_passphrase);
 835                 else
 836                         passphrase =
 837                             read_passphrase(gettext("Enter passphrase: "),
 838                             RP_ALLOW_STDIN);
 839                 /* Try to load using the passphrase. */
 840                 private = key_load_private(identity_file, passphrase, &comment);
 841                 if (private == NULL) {
 842                         memset(passphrase, 0, strlen(passphrase));
 843                         xfree(passphrase);
 844                         printf(gettext("Bad passphrase.\n"));
 845                         exit(1);
 846                 }
 847         } else {
 848                 passphrase = xstrdup("");
 849         }
 850         if (private->type != KEY_RSA1) {
 851                 fprintf(stderr, gettext("Comments are only supported for "
 852                     "RSA1 keys.\n"));
 853                 key_free(private);
 854                 exit(1);
 855         }
 856         printf(gettext("Key now has comment '%s'\n"), comment);
 857 
 858         if (identity_comment) {
 859                 strlcpy(new_comment, identity_comment, sizeof(new_comment));
 860         } else {
 861                 printf(gettext("Enter new comment: "));
 862                 fflush(stdout);
 863                 if (!fgets(new_comment, sizeof(new_comment), stdin)) {
 864                         memset(passphrase, 0, strlen(passphrase));
 865                         key_free(private);
 866                         exit(1);
 867                 }
 868                 if (strchr(new_comment, '\n'))
 869                         *strchr(new_comment, '\n') = 0;
 870         }
 871 
 872         /* Save the file using the new passphrase. */
 873         if (!key_save_private(private, identity_file, passphrase, new_comment)) {
 874                 printf(gettext("Saving the key failed: %s.\n"), identity_file);
 875                 memset(passphrase, 0, strlen(passphrase));
 876                 xfree(passphrase);
 877                 key_free(private);
 878                 xfree(comment);
 879                 exit(1);
 880         }
 881         memset(passphrase, 0, strlen(passphrase));
 882         xfree(passphrase);
 883         public = key_from_private(private);
 884         key_free(private);
 885 
 886         strlcat(identity_file, ".pub", sizeof(identity_file));
 887         fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
 888         if (fd == -1) {
 889                 printf(gettext("Could not save your public key in %s\n"),
 890                     identity_file);
 891                 exit(1);
 892         }
 893         f = fdopen(fd, "w");
 894         if (f == NULL) {
 895                 printf(gettext("fdopen %s failed"), identity_file);
 896                 exit(1);
 897         }
 898         if (!key_write(public, f))
 899                 fprintf(stderr, gettext("write key failed"));
 900         key_free(public);
 901         fprintf(f, " %s\n", new_comment);
 902         fclose(f);
 903 
 904         xfree(comment);
 905 
 906         printf(gettext("The comment in your key file has been changed.\n"));
 907         exit(0);
 908 }
 909 
 910 static void
 911 usage(void)
 912 {
 913         fprintf(stderr, gettext(
 914         "Usage: %s [options]\n"
 915         "Options:\n"
 916         "  -b bits     Number of bits in the key to create.\n"
 917         "  -B          Show bubblebabble digest of key file.\n"
 918         "  -c          Change comment in private and public key files.\n"
 919         "  -C comment  Provide new comment.\n"
 920         "  -e          Convert OpenSSH to IETF SECSH key file.\n"
 921         "  -f filename Filename of the key file.\n"
 922         "  -F hostname Find hostname in known hosts file.\n"
 923         "  -H          Hash names in known_hosts file.\n"
 924         "  -i          Convert IETF SECSH to OpenSSH key file.\n"
 925         "  -l          Show fingerprint of key file.\n"
 926         "  -N phrase   Provide new passphrase.\n"
 927         "  -p          Change passphrase of private key file.\n"
 928         "  -P phrase   Provide old passphrase.\n"
 929         "  -q          Quiet.\n"
 930         "  -R hostname Remove host from known_hosts file.\n"
 931         "  -t type     Specify type of key to create.\n"
 932         "  -y          Read private key file and print public key.\n"
 933         ), __progname);
 934 
 935         exit(1);
 936 }
 937 
 938 /*
 939  * Main program for key management.
 940  */
 941 int
 942 main(int argc, char **argv)
 943 {
 944         char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
 945         char *rr_hostname = NULL;
 946         Key *private, *public;
 947         struct passwd *pw;
 948         struct stat st;
 949         int opt, type, fd;
 950         FILE *f;
 951 
 952         extern int optind;
 953         extern char *optarg;
 954 
 955         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
 956         sanitise_stdfd();
 957 
 958         __progname = get_progname(argv[0]);
 959 
 960         g11n_setlocale(LC_ALL, "");
 961 
 962         SSLeay_add_all_algorithms();
 963         init_rng();
 964         seed_rng();
 965 
 966         /* we need this for the home * directory.  */
 967         pw = getpwuid(getuid());
 968         if (!pw) {
 969                 printf(gettext("You don't exist, go away!\n"));
 970                 exit(1);
 971         }
 972         if (gethostname(hostname, sizeof(hostname)) < 0) {
 973                 perror("gethostname");
 974                 exit(1);
 975         }
 976 
 977 #define GETOPT_ARGS "BcdeHilpqxXyb:C:f:F:N:P:R:t:"
 978 
 979         while ((opt = getopt(argc, argv, GETOPT_ARGS)) != -1) {
 980                 switch (opt) {
 981                 case 'b':
 982                         bits = atoi(optarg);
 983                         if (bits < 512 || bits > 32768) {
 984                                 printf(gettext("Bits has bad value.\n"));
 985                                 exit(1);
 986                         }
 987                         break;
 988                 case 'F':
 989                         find_host = 1;
 990                         rr_hostname = optarg;
 991                         break;
 992                 case 'H':
 993                         hash_hosts = 1;
 994                         break;
 995                 case 'R':
 996                         delete_host = 1;
 997                         rr_hostname = optarg;
 998                         break;
 999                 case 'l':
1000                         print_fingerprint = 1;
1001                         break;
1002                 case 'B':
1003                         print_bubblebabble = 1;
1004                         break;
1005                 case 'p':
1006                         change_passphrase = 1;
1007                         break;
1008                 case 'c':
1009                         change_comment = 1;
1010                         break;
1011                 case 'f':
1012                         strlcpy(identity_file, optarg, sizeof(identity_file));
1013                         have_identity = 1;
1014                         break;
1015                 case 'P':
1016                         identity_passphrase = optarg;
1017                         break;
1018                 case 'N':
1019                         identity_new_passphrase = optarg;
1020                         break;
1021                 case 'C':
1022                         identity_comment = optarg;
1023                         break;
1024                 case 'q':
1025                         quiet = 1;
1026                         break;
1027                 case 'e':
1028                 case 'x':
1029                         /* export key */
1030                         convert_to_ssh2 = 1;
1031                         break;
1032                 case 'i':
1033                 case 'X':
1034                         /* import key */
1035                         convert_from_ssh2 = 1;
1036                         break;
1037                 case 'y':
1038                         print_public = 1;
1039                         break;
1040                 case 'd':
1041                         key_type_name = "dsa";
1042                         break;
1043                 case 't':
1044                         key_type_name = optarg;
1045                         break;
1046                 case '?':
1047                 default:
1048                         usage();
1049                 }
1050         }
1051         if (optind < argc) {
1052                 printf(gettext("Too many arguments.\n"));
1053                 usage();
1054         }
1055         if (change_passphrase && change_comment) {
1056                 printf(gettext("Can only have one of -p and -c.\n"));
1057                 usage();
1058         }
1059         if (delete_host || hash_hosts || find_host)
1060                 do_known_hosts(pw, rr_hostname);
1061         if (print_fingerprint || print_bubblebabble)
1062                 do_fingerprint(pw);
1063         if (change_passphrase)
1064                 do_change_passphrase(pw);
1065         if (change_comment)
1066                 do_change_comment(pw);
1067         if (convert_to_ssh2)
1068                 do_convert_to_ssh2(pw);
1069         if (convert_from_ssh2)
1070                 do_convert_from_ssh2(pw);
1071         if (print_public)
1072                 do_print_public(pw);
1073 
1074         arc4random_stir();
1075 
1076         if (key_type_name == NULL) {
1077                 printf(gettext("You must specify a key type (-t).\n"));
1078                 usage();
1079         }
1080         type = key_type_from_name(key_type_name);
1081         if (type == KEY_UNSPEC) {
1082                 fprintf(stderr, gettext("unknown key type %s\n"),
1083                     key_type_name);
1084                 exit(1);
1085         }
1086         if (bits == 0)
1087                 bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS_RSA;
1088 
1089         if (!quiet)
1090                 printf(gettext("Generating public/private %s key pair.\n"),
1091                     key_type_name);
1092         private = key_generate(type, bits);
1093         if (private == NULL) {
1094                 fprintf(stderr, gettext("key_generate failed"));
1095                 exit(1);
1096         }
1097         public  = key_from_private(private);
1098 
1099         if (!have_identity)
1100                 ask_filename(pw, gettext("Enter file in which to save the key"));
1101 
1102         /* Create ~/.ssh directory if it doesn't already exist. */
1103         snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR);
1104         if (strstr(identity_file, dotsshdir) != NULL &&
1105             stat(dotsshdir, &st) < 0) {
1106                 if (mkdir(dotsshdir, 0700) < 0)
1107                         error("Could not create directory '%s'.", dotsshdir);
1108                 else if (!quiet)
1109                         printf(gettext("Created directory '%s'.\n"), dotsshdir);
1110         }
1111         /* If the file already exists, ask the user to confirm. */
1112         if (stat(identity_file, &st) >= 0) {
1113                 char yesno[128];
1114                 printf(gettext("%s already exists.\n"), identity_file);
1115                 printf(gettext("Overwrite (%s/%s)? "),
1116                     nl_langinfo(YESSTR), nl_langinfo(NOSTR));
1117                 fflush(stdout);
1118                 if (fgets(yesno, sizeof(yesno), stdin) == NULL)
1119                         exit(1);
1120                 if (strcasecmp(chop(yesno), nl_langinfo(YESSTR)) != 0)
1121                         exit(1);
1122         }
1123         /* Ask for a passphrase (twice). */
1124         if (identity_passphrase)
1125                 passphrase1 = xstrdup(identity_passphrase);
1126         else if (identity_new_passphrase)
1127                 passphrase1 = xstrdup(identity_new_passphrase);
1128         else {
1129 passphrase_again:
1130                 passphrase1 =
1131                         read_passphrase(gettext("Enter passphrase (empty "
1132                         "for no passphrase): "), RP_ALLOW_STDIN);
1133                 passphrase2 = read_passphrase(gettext("Enter same "
1134                             "passphrase again: "), RP_ALLOW_STDIN);
1135                 if (strcmp(passphrase1, passphrase2) != 0) {
1136                         /*
1137                          * The passphrases do not match.  Clear them and
1138                          * retry.
1139                          */
1140                         memset(passphrase1, 0, strlen(passphrase1));
1141                         memset(passphrase2, 0, strlen(passphrase2));
1142                         xfree(passphrase1);
1143                         xfree(passphrase2);
1144                         printf(gettext("Passphrases do not match.  Try "
1145                             "again.\n"));
1146                         goto passphrase_again;
1147                 }
1148                 /* Clear the other copy of the passphrase. */
1149                 memset(passphrase2, 0, strlen(passphrase2));
1150                 xfree(passphrase2);
1151         }
1152 
1153         if (identity_comment) {
1154                 strlcpy(comment, identity_comment, sizeof(comment));
1155         } else {
1156                 /* Create default commend field for the passphrase. */
1157                 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname);
1158         }
1159 
1160         /* Save the key with the given passphrase and comment. */
1161         if (!key_save_private(private, identity_file, passphrase1, comment)) {
1162                 printf(gettext("Saving the key failed: %s.\n"), identity_file);
1163                 memset(passphrase1, 0, strlen(passphrase1));
1164                 xfree(passphrase1);
1165                 exit(1);
1166         }
1167         /* Clear the passphrase. */
1168         memset(passphrase1, 0, strlen(passphrase1));
1169         xfree(passphrase1);
1170 
1171         /* Clear the private key and the random number generator. */
1172         key_free(private);
1173         arc4random_stir();
1174 
1175         if (!quiet)
1176                 printf(gettext("Your identification has been saved in %s.\n"),
1177                     identity_file);
1178 
1179         strlcat(identity_file, ".pub", sizeof(identity_file));
1180         fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1181         if (fd == -1) {
1182                 printf(gettext("Could not save your public key in %s\n"),
1183                     identity_file);
1184                 exit(1);
1185         }
1186         f = fdopen(fd, "w");
1187         if (f == NULL) {
1188                 printf(gettext("fdopen %s failed"), identity_file);
1189                 exit(1);
1190         }
1191         if (!key_write(public, f))
1192                 fprintf(stderr, gettext("write key failed"));
1193         fprintf(f, " %s\n", comment);
1194         fclose(f);
1195 
1196         if (!quiet) {
1197                 char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
1198                 printf(gettext("Your public key has been saved in %s.\n"),
1199                     identity_file);
1200                 printf(gettext("The key fingerprint is:\n"));
1201                 printf("%s %s\n", fp, comment);
1202                 xfree(fp);
1203         }
1204 
1205         key_free(public);
1206         return(0);
1207         /* NOTREACHED */
1208 }