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