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