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 * Created: Mon Mar 27 02:26:40 1995 ylo 6 * Identity and host key generation and maintenance. 7 */ 8 9 #include "includes.h" 10 RCSID("$Id: ssh-keygen.c,v 1.26 2000/05/30 17:32:06 markus Exp $"); 11 12 #include <openssl/evp.h> 13 #include <openssl/pem.h> 14 #include <openssl/rsa.h> 15 #include <openssl/dsa.h> 16 17 #include "ssh.h" 18 #include "xmalloc.h" 19 #include "fingerprint.h" 20 #include "key.h" 21 #include "rsa.h" 22 #include "dsa.h" 23 #include "authfile.h" 24 #include "uuencode.h" 25 26 /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */ 27 int bits = 1024; 28 29 /* 30 * Flag indicating that we just want to change the passphrase. This can be 31 * set on the command line. 32 */ 33 int change_passphrase = 0; 34 35 /* 36 * Flag indicating that we just want to change the comment. This can be set 37 * on the command line. 38 */ 39 int change_comment = 0; 40 41 int quiet = 0; 42 43 /* Flag indicating that we just want to see the key fingerprint */ 44 int print_fingerprint = 0; 45 46 /* The identity file name, given on the command line or entered by the user. */ 47 char identity_file[1024]; 48 int have_identity = 0; 49 50 /* This is set to the passphrase if given on the command line. */ 51 char *identity_passphrase = NULL; 52 53 /* This is set to the new passphrase if given on the command line. */ 54 char *identity_new_passphrase = NULL; 55 56 /* This is set to the new comment if given on the command line. */ 57 char *identity_comment = NULL; 58 59 /* Dump public key file in format used by real and the original SSH 2 */ 60 int convert_to_ssh2 = 0; 61 int convert_from_ssh2 = 0; 62 int print_public = 0; 63 int dsa_mode = 0; 64 65 /* argv0 */ 66 extern char *__progname; 67 68 char hostname[MAXHOSTNAMELEN]; 69 70 void 71 ask_filename(struct passwd *pw, const char *prompt) 72 { 73 char buf[1024]; 74 snprintf(identity_file, sizeof(identity_file), "%s/%s", 75 pw->pw_dir, 76 dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY); 77 printf("%s (%s): ", prompt, identity_file); 78 fflush(stdout); 79 if (fgets(buf, sizeof(buf), stdin) == NULL) 80 exit(1); 81 if (strchr(buf, '\n')) 82 *strchr(buf, '\n') = 0; 83 if (strcmp(buf, "") != 0) 84 strlcpy(identity_file, buf, sizeof(identity_file)); 85 have_identity = 1; 86 } 87 88 int 89 try_load_key(char *filename, Key *k) 90 { 91 int success = 1; 92 if (!load_private_key(filename, "", k, NULL)) { 93 char *pass = read_passphrase("Enter passphrase: ", 1); 94 if (!load_private_key(filename, pass, k, NULL)) { 95 success = 0; 96 } 97 memset(pass, 0, strlen(pass)); 98 xfree(pass); 99 } 100 return success; 101 } 102 103 #define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" 104 #define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----" 105 106 void 107 do_convert_to_ssh2(struct passwd *pw) 108 { 109 Key *k; 110 int len; 111 unsigned char *blob; 112 struct stat st; 113 114 if (!have_identity) 115 ask_filename(pw, "Enter file in which the key is"); 116 if (stat(identity_file, &st) < 0) { 117 perror(identity_file); 118 exit(1); 119 } 120 k = key_new(KEY_DSA); 121 if (!try_load_key(identity_file, k)) { 122 fprintf(stderr, "load failed\n"); 123 exit(1); 124 } 125 dsa_make_key_blob(k, &blob, &len); 126 fprintf(stdout, SSH_COM_MAGIC_BEGIN "\n"); 127 fprintf(stdout, 128 "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n", 129 BN_num_bits(k->dsa->p), 130 pw->pw_name, hostname); 131 dump_base64(stdout, blob, len); 132 fprintf(stdout, SSH_COM_MAGIC_END "\n"); 133 key_free(k); 134 xfree(blob); 135 exit(0); 136 } 137 138 void 139 do_convert_from_ssh2(struct passwd *pw) 140 { 141 Key *k; 142 int blen; 143 char line[1024], *p; 144 char blob[8096]; 145 char encoded[8096]; 146 struct stat st; 147 int escaped = 0; 148 FILE *fp; 149 150 if (!have_identity) 151 ask_filename(pw, "Enter file in which the key is"); 152 if (stat(identity_file, &st) < 0) { 153 perror(identity_file); 154 exit(1); 155 } 156 fp = fopen(identity_file, "r"); 157 if (fp == NULL) { 158 perror(identity_file); 159 exit(1); 160 } 161 encoded[0] = '\0'; 162 while (fgets(line, sizeof(line), fp)) { 163 if (!(p = strchr(line, '\n'))) { 164 fprintf(stderr, "input line too long.\n"); 165 exit(1); 166 } 167 if (p > line && p[-1] == '\\') 168 escaped++; 169 if (strncmp(line, "----", 4) == 0 || 170 strstr(line, ": ") != NULL) { 171 fprintf(stderr, "ignore: %s", line); 172 continue; 173 } 174 if (escaped) { 175 escaped--; 176 fprintf(stderr, "escaped: %s", line); 177 continue; 178 } 179 *p = '\0'; 180 strlcat(encoded, line, sizeof(encoded)); 181 } 182 blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob)); 183 if (blen < 0) { 184 fprintf(stderr, "uudecode failed.\n"); 185 exit(1); 186 } 187 k = dsa_key_from_blob(blob, blen); 188 if (!key_write(k, stdout)) 189 fprintf(stderr, "key_write failed"); 190 key_free(k); 191 fprintf(stdout, "\n"); 192 fclose(fp); 193 exit(0); 194 } 195 196 void 197 do_print_public(struct passwd *pw) 198 { 199 Key *k; 200 int len; 201 unsigned char *blob; 202 struct stat st; 203 204 if (!have_identity) 205 ask_filename(pw, "Enter file in which the key is"); 206 if (stat(identity_file, &st) < 0) { 207 perror(identity_file); 208 exit(1); 209 } 210 k = key_new(KEY_DSA); 211 if (!try_load_key(identity_file, k)) { 212 fprintf(stderr, "load failed\n"); 213 exit(1); 214 } 215 dsa_make_key_blob(k, &blob, &len); 216 if (!key_write(k, stdout)) 217 fprintf(stderr, "key_write failed"); 218 key_free(k); 219 xfree(blob); 220 fprintf(stdout, "\n"); 221 exit(0); 222 } 223 224 void 225 do_fingerprint(struct passwd *pw) 226 { 227 FILE *f; 228 BIGNUM *e, *n; 229 Key *public; 230 char *comment = NULL, *cp, *ep, line[16*1024]; 231 int i, skip = 0, num = 1, invalid = 1; 232 unsigned int ignore; 233 struct stat st; 234 235 if (!have_identity) 236 ask_filename(pw, "Enter file in which the key is"); 237 if (stat(identity_file, &st) < 0) { 238 perror(identity_file); 239 exit(1); 240 } 241 public = key_new(KEY_RSA); 242 if (load_public_key(identity_file, public, &comment)) { 243 printf("%d %s %s\n", BN_num_bits(public->rsa->n), 244 key_fingerprint(public), comment); 245 key_free(public); 246 exit(0); 247 } 248 key_free(public); 249 250 /* XXX */ 251 f = fopen(identity_file, "r"); 252 if (f != NULL) { 253 n = BN_new(); 254 e = BN_new(); 255 while (fgets(line, sizeof(line), f)) { 256 i = strlen(line) - 1; 257 if (line[i] != '\n') { 258 error("line %d too long: %.40s...", num, line); 259 skip = 1; 260 continue; 261 } 262 num++; 263 if (skip) { 264 skip = 0; 265 continue; 266 } 267 line[i] = '\0'; 268 269 /* Skip leading whitespace, empty and comment lines. */ 270 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 271 ; 272 if (!*cp || *cp == '\n' || *cp == '#') 273 continue ; 274 i = strtol(cp, &ep, 10); 275 if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { 276 int quoted = 0; 277 comment = cp; 278 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 279 if (*cp == '\\' && cp[1] == '"') 280 cp++; /* Skip both */ 281 else if (*cp == '"') 282 quoted = !quoted; 283 } 284 if (!*cp) 285 continue; 286 *cp++ = '\0'; 287 } 288 ep = cp; 289 if (auth_rsa_read_key(&cp, &ignore, e, n)) { 290 invalid = 0; 291 comment = *cp ? cp : comment; 292 printf("%d %s %s\n", BN_num_bits(n), 293 fingerprint(e, n), 294 comment ? comment : "no comment"); 295 } 296 } 297 BN_free(e); 298 BN_free(n); 299 fclose(f); 300 } 301 if (invalid) { 302 printf("%s is not a valid key file.\n", identity_file); 303 exit(1); 304 } 305 exit(0); 306 } 307 308 /* 309 * Perform changing a passphrase. The argument is the passwd structure 310 * for the current user. 311 */ 312 void 313 do_change_passphrase(struct passwd *pw) 314 { 315 char *comment; 316 char *old_passphrase, *passphrase1, *passphrase2; 317 struct stat st; 318 Key *private; 319 Key *public; 320 int type = dsa_mode ? KEY_DSA : KEY_RSA; 321 322 if (!have_identity) 323 ask_filename(pw, "Enter file in which the key is"); 324 if (stat(identity_file, &st) < 0) { 325 perror(identity_file); 326 exit(1); 327 } 328 329 if (type == KEY_RSA) { 330 /* XXX this works currently only for RSA */ 331 public = key_new(type); 332 if (!load_public_key(identity_file, public, NULL)) { 333 printf("%s is not a valid key file.\n", identity_file); 334 exit(1); 335 } 336 /* Clear the public key since we are just about to load the whole file. */ 337 key_free(public); 338 } 339 340 /* Try to load the file with empty passphrase. */ 341 private = key_new(type); 342 if (!load_private_key(identity_file, "", private, &comment)) { 343 if (identity_passphrase) 344 old_passphrase = xstrdup(identity_passphrase); 345 else 346 old_passphrase = read_passphrase("Enter old passphrase: ", 1); 347 if (!load_private_key(identity_file, old_passphrase, private, &comment)) { 348 memset(old_passphrase, 0, strlen(old_passphrase)); 349 xfree(old_passphrase); 350 printf("Bad passphrase.\n"); 351 exit(1); 352 } 353 memset(old_passphrase, 0, strlen(old_passphrase)); 354 xfree(old_passphrase); 355 } 356 printf("Key has comment '%s'\n", comment); 357 358 /* Ask the new passphrase (twice). */ 359 if (identity_new_passphrase) { 360 passphrase1 = xstrdup(identity_new_passphrase); 361 passphrase2 = NULL; 362 } else { 363 passphrase1 = 364 read_passphrase("Enter new passphrase (empty for no passphrase): ", 1); 365 passphrase2 = read_passphrase("Enter same passphrase again: ", 1); 366 367 /* Verify that they are the same. */ 368 if (strcmp(passphrase1, passphrase2) != 0) { 369 memset(passphrase1, 0, strlen(passphrase1)); 370 memset(passphrase2, 0, strlen(passphrase2)); 371 xfree(passphrase1); 372 xfree(passphrase2); 373 printf("Pass phrases do not match. Try again.\n"); 374 exit(1); 375 } 376 /* Destroy the other copy. */ 377 memset(passphrase2, 0, strlen(passphrase2)); 378 xfree(passphrase2); 379 } 380 381 /* Save the file using the new passphrase. */ 382 if (!save_private_key(identity_file, passphrase1, private, comment)) { 383 printf("Saving the key failed: %s: %s.\n", 384 identity_file, strerror(errno)); 385 memset(passphrase1, 0, strlen(passphrase1)); 386 xfree(passphrase1); 387 key_free(private); 388 xfree(comment); 389 exit(1); 390 } 391 /* Destroy the passphrase and the copy of the key in memory. */ 392 memset(passphrase1, 0, strlen(passphrase1)); 393 xfree(passphrase1); 394 key_free(private); /* Destroys contents */ 395 xfree(comment); 396 397 printf("Your identification has been saved with the new passphrase.\n"); 398 exit(0); 399 } 400 401 /* 402 * Change the comment of a private key file. 403 */ 404 void 405 do_change_comment(struct passwd *pw) 406 { 407 char new_comment[1024], *comment; 408 Key *private; 409 Key *public; 410 char *passphrase; 411 struct stat st; 412 FILE *f; 413 414 if (!have_identity) 415 ask_filename(pw, "Enter file in which the key is"); 416 if (stat(identity_file, &st) < 0) { 417 perror(identity_file); 418 exit(1); 419 } 420 /* 421 * Try to load the public key from the file the verify that it is 422 * readable and of the proper format. 423 */ 424 public = key_new(KEY_RSA); 425 if (!load_public_key(identity_file, public, NULL)) { 426 printf("%s is not a valid key file.\n", identity_file); 427 exit(1); 428 } 429 430 private = key_new(KEY_RSA); 431 if (load_private_key(identity_file, "", private, &comment)) 432 passphrase = xstrdup(""); 433 else { 434 if (identity_passphrase) 435 passphrase = xstrdup(identity_passphrase); 436 else if (identity_new_passphrase) 437 passphrase = xstrdup(identity_new_passphrase); 438 else 439 passphrase = read_passphrase("Enter passphrase: ", 1); 440 /* Try to load using the passphrase. */ 441 if (!load_private_key(identity_file, passphrase, private, &comment)) { 442 memset(passphrase, 0, strlen(passphrase)); 443 xfree(passphrase); 444 printf("Bad passphrase.\n"); 445 exit(1); 446 } 447 } 448 printf("Key now has comment '%s'\n", comment); 449 450 if (identity_comment) { 451 strlcpy(new_comment, identity_comment, sizeof(new_comment)); 452 } else { 453 printf("Enter new comment: "); 454 fflush(stdout); 455 if (!fgets(new_comment, sizeof(new_comment), stdin)) { 456 memset(passphrase, 0, strlen(passphrase)); 457 key_free(private); 458 exit(1); 459 } 460 if (strchr(new_comment, '\n')) 461 *strchr(new_comment, '\n') = 0; 462 } 463 464 /* Save the file using the new passphrase. */ 465 if (!save_private_key(identity_file, passphrase, private, new_comment)) { 466 printf("Saving the key failed: %s: %s.\n", 467 identity_file, strerror(errno)); 468 memset(passphrase, 0, strlen(passphrase)); 469 xfree(passphrase); 470 key_free(private); 471 xfree(comment); 472 exit(1); 473 } 474 memset(passphrase, 0, strlen(passphrase)); 475 xfree(passphrase); 476 key_free(private); 477 478 strlcat(identity_file, ".pub", sizeof(identity_file)); 479 f = fopen(identity_file, "w"); 480 if (!f) { 481 printf("Could not save your public key in %s\n", identity_file); 482 exit(1); 483 } 484 if (!key_write(public, f)) 485 fprintf(stderr, "write key failed"); 486 key_free(public); 487 fprintf(f, " %s\n", new_comment); 488 fclose(f); 489 490 xfree(comment); 491 492 printf("The comment in your key file has been changed.\n"); 493 exit(0); 494 } 495 496 void 497 usage(void) 498 { 499 printf("Usage: %s [-lpqxXydc] [-b bits] [-f file] [-C comment] [-N new-pass] [-P pass]\n", __progname); 500 exit(1); 501 } 502 503 /* 504 * Main program for key management. 505 */ 506 int 507 main(int ac, char **av) 508 { 509 char dotsshdir[16 * 1024], comment[1024], *passphrase1, *passphrase2; 510 struct passwd *pw; 511 int opt; 512 struct stat st; 513 FILE *f; 514 Key *private; 515 Key *public; 516 extern int optind; 517 extern char *optarg; 518 519 SSLeay_add_all_algorithms(); 520 521 /* we need this for the home * directory. */ 522 pw = getpwuid(getuid()); 523 if (!pw) { 524 printf("You don't exist, go away!\n"); 525 exit(1); 526 } 527 if (gethostname(hostname, sizeof(hostname)) < 0) { 528 perror("gethostname"); 529 exit(1); 530 } 531 532 while ((opt = getopt(ac, av, "dqpclRxXyb:f:P:N:C:")) != EOF) { 533 switch (opt) { 534 case 'b': 535 bits = atoi(optarg); 536 if (bits < 512 || bits > 32768) { 537 printf("Bits has bad value.\n"); 538 exit(1); 539 } 540 break; 541 542 case 'l': 543 print_fingerprint = 1; 544 break; 545 546 case 'p': 547 change_passphrase = 1; 548 break; 549 550 case 'c': 551 change_comment = 1; 552 break; 553 554 case 'f': 555 strlcpy(identity_file, optarg, sizeof(identity_file)); 556 have_identity = 1; 557 break; 558 559 case 'P': 560 identity_passphrase = optarg; 561 break; 562 563 case 'N': 564 identity_new_passphrase = optarg; 565 break; 566 567 case 'C': 568 identity_comment = optarg; 569 break; 570 571 case 'q': 572 quiet = 1; 573 break; 574 575 case 'R': 576 if (rsa_alive() == 0) 577 exit(1); 578 else 579 exit(0); 580 break; 581 582 case 'x': 583 convert_to_ssh2 = 1; 584 break; 585 586 case 'X': 587 convert_from_ssh2 = 1; 588 break; 589 590 case 'y': 591 print_public = 1; 592 break; 593 594 case 'd': 595 dsa_mode = 1; 596 break; 597 598 case '?': 599 default: 600 usage(); 601 } 602 } 603 if (optind < ac) { 604 printf("Too many arguments.\n"); 605 usage(); 606 } 607 if (change_passphrase && change_comment) { 608 printf("Can only have one of -p and -c.\n"); 609 usage(); 610 } 611 /* check if RSA support is needed and exists */ 612 if (dsa_mode == 0 && rsa_alive() == 0) { 613 fprintf(stderr, 614 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", 615 __progname); 616 exit(1); 617 } 618 if (print_fingerprint) 619 do_fingerprint(pw); 620 if (change_passphrase) 621 do_change_passphrase(pw); 622 if (change_comment) 623 do_change_comment(pw); 624 if (convert_to_ssh2) 625 do_convert_to_ssh2(pw); 626 if (convert_from_ssh2) 627 do_convert_from_ssh2(pw); 628 if (print_public) 629 do_print_public(pw); 630 631 arc4random_stir(); 632 633 if (dsa_mode != 0) { 634 if (!quiet) 635 printf("Generating DSA parameter and key.\n"); 636 public = private = dsa_generate_key(bits); 637 if (private == NULL) { 638 fprintf(stderr, "dsa_generate_keys failed"); 639 exit(1); 640 } 641 } else { 642 if (quiet) 643 rsa_set_verbose(0); 644 /* Generate the rsa key pair. */ 645 public = key_new(KEY_RSA); 646 private = key_new(KEY_RSA); 647 rsa_generate_key(private->rsa, public->rsa, bits); 648 } 649 650 if (!have_identity) 651 ask_filename(pw, "Enter file in which to save the key"); 652 653 /* Create ~/.ssh directory if it doesn\'t already exist. */ 654 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, SSH_USER_DIR); 655 if (strstr(identity_file, dotsshdir) != NULL && 656 stat(dotsshdir, &st) < 0) { 657 if (mkdir(dotsshdir, 0755) < 0) 658 error("Could not create directory '%s'.", dotsshdir); 659 else if (!quiet) 660 printf("Created directory '%s'.\n", dotsshdir); 661 } 662 /* If the file already exists, ask the user to confirm. */ 663 if (stat(identity_file, &st) >= 0) { 664 char yesno[3]; 665 printf("%s already exists.\n", identity_file); 666 printf("Overwrite (y/n)? "); 667 fflush(stdout); 668 if (fgets(yesno, sizeof(yesno), stdin) == NULL) 669 exit(1); 670 if (yesno[0] != 'y' && yesno[0] != 'Y') 671 exit(1); 672 } 673 /* Ask for a passphrase (twice). */ 674 if (identity_passphrase) 675 passphrase1 = xstrdup(identity_passphrase); 676 else if (identity_new_passphrase) 677 passphrase1 = xstrdup(identity_new_passphrase); 678 else { 679 passphrase_again: 680 passphrase1 = 681 read_passphrase("Enter passphrase (empty for no passphrase): ", 1); 682 passphrase2 = read_passphrase("Enter same passphrase again: ", 1); 683 if (strcmp(passphrase1, passphrase2) != 0) { 684 /* The passphrases do not match. Clear them and retry. */ 685 memset(passphrase1, 0, strlen(passphrase1)); 686 memset(passphrase2, 0, strlen(passphrase2)); 687 xfree(passphrase1); 688 xfree(passphrase2); 689 printf("Passphrases do not match. Try again.\n"); 690 goto passphrase_again; 691 } 692 /* Clear the other copy of the passphrase. */ 693 memset(passphrase2, 0, strlen(passphrase2)); 694 xfree(passphrase2); 695 } 696 697 if (identity_comment) { 698 strlcpy(comment, identity_comment, sizeof(comment)); 699 } else { 700 /* Create default commend field for the passphrase. */ 701 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); 702 } 703 704 /* Save the key with the given passphrase and comment. */ 705 if (!save_private_key(identity_file, passphrase1, private, comment)) { 706 printf("Saving the key failed: %s: %s.\n", 707 identity_file, strerror(errno)); 708 memset(passphrase1, 0, strlen(passphrase1)); 709 xfree(passphrase1); 710 exit(1); 711 } 712 /* Clear the passphrase. */ 713 memset(passphrase1, 0, strlen(passphrase1)); 714 xfree(passphrase1); 715 716 /* Clear the private key and the random number generator. */ 717 if (private != public) { 718 key_free(private); 719 } 720 arc4random_stir(); 721 722 if (!quiet) 723 printf("Your identification has been saved in %s.\n", identity_file); 724 725 strlcat(identity_file, ".pub", sizeof(identity_file)); 726 f = fopen(identity_file, "w"); 727 if (!f) { 728 printf("Could not save your public key in %s\n", identity_file); 729 exit(1); 730 } 731 if (!key_write(public, f)) 732 fprintf(stderr, "write key failed"); 733 fprintf(f, " %s\n", comment); 734 fclose(f); 735 736 if (!quiet) { 737 printf("Your public key has been saved in %s.\n", 738 identity_file); 739 printf("The key fingerprint is:\n"); 740 printf("%s %s\n", key_fingerprint(public), comment); 741 } 742 743 key_free(public); 744 exit(0); 745 } 746