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 #include "includes.h" 15 RCSID("$OpenBSD: ssh-keygen.c,v 1.31 2000/09/07 20:27:54 deraadt Exp $"); 16 17 #include <openssl/evp.h> 18 #include <openssl/pem.h> 19 #include <openssl/rsa.h> 20 #include <openssl/dsa.h> 21 22 #include "ssh.h" 23 #include "xmalloc.h" 24 #include "key.h" 25 #include "rsa.h" 26 #include "dsa.h" 27 #include "authfile.h" 28 #include "uuencode.h" 29 30 /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */ 31 int bits = 1024; 32 33 /* 34 * Flag indicating that we just want to change the passphrase. This can be 35 * set on the command line. 36 */ 37 int change_passphrase = 0; 38 39 /* 40 * Flag indicating that we just want to change the comment. This can be set 41 * on the command line. 42 */ 43 int change_comment = 0; 44 45 int quiet = 0; 46 47 /* Flag indicating that we just want to see the key fingerprint */ 48 int print_fingerprint = 0; 49 50 /* The identity file name, given on the command line or entered by the user. */ 51 char identity_file[1024]; 52 int have_identity = 0; 53 54 /* This is set to the passphrase if given on the command line. */ 55 char *identity_passphrase = NULL; 56 57 /* This is set to the new passphrase if given on the command line. */ 58 char *identity_new_passphrase = NULL; 59 60 /* This is set to the new comment if given on the command line. */ 61 char *identity_comment = NULL; 62 63 /* Dump public key file in format used by real and the original SSH 2 */ 64 int convert_to_ssh2 = 0; 65 int convert_from_ssh2 = 0; 66 int print_public = 0; 67 int dsa_mode = 0; 68 69 /* argv0 */ 70 extern char *__progname; 71 72 char hostname[MAXHOSTNAMELEN]; 73 74 void 75 ask_filename(struct passwd *pw, const char *prompt) 76 { 77 char buf[1024]; 78 snprintf(identity_file, sizeof(identity_file), "%s/%s", 79 pw->pw_dir, 80 dsa_mode ? SSH_CLIENT_ID_DSA: SSH_CLIENT_IDENTITY); 81 printf("%s (%s): ", prompt, identity_file); 82 fflush(stdout); 83 if (fgets(buf, sizeof(buf), stdin) == NULL) 84 exit(1); 85 if (strchr(buf, '\n')) 86 *strchr(buf, '\n') = 0; 87 if (strcmp(buf, "") != 0) 88 strlcpy(identity_file, buf, sizeof(identity_file)); 89 have_identity = 1; 90 } 91 92 int 93 try_load_key(char *filename, Key *k) 94 { 95 int success = 1; 96 if (!load_private_key(filename, "", k, NULL)) { 97 char *pass = read_passphrase("Enter passphrase: ", 1); 98 if (!load_private_key(filename, pass, k, NULL)) { 99 success = 0; 100 } 101 memset(pass, 0, strlen(pass)); 102 xfree(pass); 103 } 104 return success; 105 } 106 107 #define SSH_COM_MAGIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" 108 #define SSH_COM_MAGIC_END "---- END SSH2 PUBLIC KEY ----" 109 110 void 111 do_convert_to_ssh2(struct passwd *pw) 112 { 113 Key *k; 114 int len; 115 unsigned char *blob; 116 struct stat st; 117 118 if (!have_identity) 119 ask_filename(pw, "Enter file in which the key is"); 120 if (stat(identity_file, &st) < 0) { 121 perror(identity_file); 122 exit(1); 123 } 124 k = key_new(KEY_DSA); 125 if (!try_load_key(identity_file, k)) { 126 fprintf(stderr, "load failed\n"); 127 exit(1); 128 } 129 dsa_make_key_blob(k, &blob, &len); 130 fprintf(stdout, "%s\n", SSH_COM_MAGIC_BEGIN); 131 fprintf(stdout, 132 "Comment: \"%d-bit DSA, converted from openssh by %s@%s\"\n", 133 BN_num_bits(k->dsa->p), 134 pw->pw_name, hostname); 135 dump_base64(stdout, blob, len); 136 fprintf(stdout, "%s\n", SSH_COM_MAGIC_END); 137 key_free(k); 138 xfree(blob); 139 exit(0); 140 } 141 142 void 143 do_convert_from_ssh2(struct passwd *pw) 144 { 145 Key *k; 146 int blen; 147 char line[1024], *p; 148 char blob[8096]; 149 char encoded[8096]; 150 struct stat st; 151 int escaped = 0; 152 FILE *fp; 153 154 if (!have_identity) 155 ask_filename(pw, "Enter file in which the key is"); 156 if (stat(identity_file, &st) < 0) { 157 perror(identity_file); 158 exit(1); 159 } 160 fp = fopen(identity_file, "r"); 161 if (fp == NULL) { 162 perror(identity_file); 163 exit(1); 164 } 165 encoded[0] = '\0'; 166 while (fgets(line, sizeof(line), fp)) { 167 if (!(p = strchr(line, '\n'))) { 168 fprintf(stderr, "input line too long.\n"); 169 exit(1); 170 } 171 if (p > line && p[-1] == '\\') 172 escaped++; 173 if (strncmp(line, "----", 4) == 0 || 174 strstr(line, ": ") != NULL) { 175 fprintf(stderr, "ignore: %s", line); 176 continue; 177 } 178 if (escaped) { 179 escaped--; 180 fprintf(stderr, "escaped: %s", line); 181 continue; 182 } 183 *p = '\0'; 184 strlcat(encoded, line, sizeof(encoded)); 185 } 186 blen = uudecode(encoded, (unsigned char *)blob, sizeof(blob)); 187 if (blen < 0) { 188 fprintf(stderr, "uudecode failed.\n"); 189 exit(1); 190 } 191 k = dsa_key_from_blob(blob, blen); 192 if (!key_write(k, stdout)) 193 fprintf(stderr, "key_write failed"); 194 key_free(k); 195 fprintf(stdout, "\n"); 196 fclose(fp); 197 exit(0); 198 } 199 200 void 201 do_print_public(struct passwd *pw) 202 { 203 Key *k; 204 int len; 205 unsigned char *blob; 206 struct stat st; 207 208 if (!have_identity) 209 ask_filename(pw, "Enter file in which the key is"); 210 if (stat(identity_file, &st) < 0) { 211 perror(identity_file); 212 exit(1); 213 } 214 k = key_new(KEY_DSA); 215 if (!try_load_key(identity_file, k)) { 216 fprintf(stderr, "load failed\n"); 217 exit(1); 218 } 219 dsa_make_key_blob(k, &blob, &len); 220 if (!key_write(k, stdout)) 221 fprintf(stderr, "key_write failed"); 222 key_free(k); 223 xfree(blob); 224 fprintf(stdout, "\n"); 225 exit(0); 226 } 227 228 void 229 do_fingerprint(struct passwd *pw) 230 { 231 /* XXX RSA1 only */ 232 233 FILE *f; 234 Key *public; 235 char *comment = NULL, *cp, *ep, line[16*1024]; 236 int i, skip = 0, num = 1, invalid = 1; 237 unsigned int ignore; 238 struct stat st; 239 240 if (!have_identity) 241 ask_filename(pw, "Enter file in which the key is"); 242 if (stat(identity_file, &st) < 0) { 243 perror(identity_file); 244 exit(1); 245 } 246 public = key_new(KEY_RSA); 247 if (load_public_key(identity_file, public, &comment)) { 248 printf("%d %s %s\n", BN_num_bits(public->rsa->n), 249 key_fingerprint(public), comment); 250 key_free(public); 251 exit(0); 252 } 253 254 f = fopen(identity_file, "r"); 255 if (f != NULL) { 256 while (fgets(line, sizeof(line), f)) { 257 i = strlen(line) - 1; 258 if (line[i] != '\n') { 259 error("line %d too long: %.40s...", num, line); 260 skip = 1; 261 continue; 262 } 263 num++; 264 if (skip) { 265 skip = 0; 266 continue; 267 } 268 line[i] = '\0'; 269 270 /* Skip leading whitespace, empty and comment lines. */ 271 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 272 ; 273 if (!*cp || *cp == '\n' || *cp == '#') 274 continue ; 275 i = strtol(cp, &ep, 10); 276 if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { 277 int quoted = 0; 278 comment = cp; 279 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 280 if (*cp == '\\' && cp[1] == '"') 281 cp++; /* Skip both */ 282 else if (*cp == '"') 283 quoted = !quoted; 284 } 285 if (!*cp) 286 continue; 287 *cp++ = '\0'; 288 } 289 ep = cp; 290 if (auth_rsa_read_key(&cp, &ignore, public->rsa->e, public->rsa->n)) { 291 invalid = 0; 292 comment = *cp ? cp : comment; 293 printf("%d %s %s\n", key_size(public), 294 key_fingerprint(public), 295 comment ? comment : "no comment"); 296 } 297 } 298 fclose(f); 299 } 300 key_free(public); 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, 0700) < 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