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