1 /* $OpenBSD: ssh-keygen.c,v 1.170 2008/06/12 21:14:46 grunk 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"); 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"); 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%s\n", key_size(public), fp, name, 616 key_type(public), ra); 617 xfree(ra); 618 xfree(fp); 619 } else { 620 if (hash && (name = host_hash(name, NULL, 0)) == NULL) 621 fatal("hash_host failed"); 622 fprintf(f, "%s ", name); 623 if (!key_write(public, f)) 624 fatal("key_write failed"); 625 fprintf(f, "\n"); 626 } 627 } 628 629 static void 630 do_known_hosts(struct passwd *pw, const char *name) 631 { 632 FILE *in, *out = stdout; 633 Key *public; 634 char *cp, *cp2, *kp, *kp2; 635 char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN]; 636 int c, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0; 637 638 if (!have_identity) { 639 cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid); 640 if (strlcpy(identity_file, cp, sizeof(identity_file)) >= 641 sizeof(identity_file)) 642 fatal("Specified known hosts path too long"); 643 xfree(cp); 644 have_identity = 1; 645 } 646 if ((in = fopen(identity_file, "r")) == NULL) 647 fatal("fopen: %s", strerror(errno)); 648 649 /* 650 * Find hosts goes to stdout, hash and deletions happen in-place 651 * A corner case is ssh-keygen -HF foo, which should go to stdout 652 */ 653 if (!find_host && (hash_hosts || delete_host)) { 654 if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) || 655 strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) || 656 strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) || 657 strlcat(old, ".old", sizeof(old)) >= sizeof(old)) 658 fatal("known_hosts path too long"); 659 umask(077); 660 if ((c = mkstemp(tmp)) == -1) 661 fatal("mkstemp: %s", strerror(errno)); 662 if ((out = fdopen(c, "w")) == NULL) { 663 c = errno; 664 unlink(tmp); 665 fatal("fdopen: %s", strerror(c)); 666 } 667 inplace = 1; 668 } 669 670 while (fgets(line, sizeof(line), in)) { 671 if ((cp = strchr(line, '\n')) == NULL) { 672 error("line %d too long: %.40s...", num + 1, line); 673 skip = 1; 674 invalid = 1; 675 continue; 676 } 677 num++; 678 if (skip) { 679 skip = 0; 680 continue; 681 } 682 *cp = '\0'; 683 684 /* Skip leading whitespace, empty and comment lines. */ 685 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 686 ; 687 if (!*cp || *cp == '\n' || *cp == '#') { 688 if (inplace) 689 fprintf(out, "%s\n", cp); 690 continue; 691 } 692 /* Find the end of the host name portion. */ 693 for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++) 694 ; 695 if (*kp == '\0' || *(kp + 1) == '\0') { 696 error("line %d missing key: %.40s...", 697 num, line); 698 invalid = 1; 699 continue; 700 } 701 *kp++ = '\0'; 702 kp2 = kp; 703 704 public = key_new(KEY_RSA1); 705 if (key_read(public, &kp) != 1) { 706 kp = kp2; 707 key_free(public); 708 public = key_new(KEY_UNSPEC); 709 if (key_read(public, &kp) != 1) { 710 error("line %d invalid key: %.40s...", 711 num, line); 712 key_free(public); 713 invalid = 1; 714 continue; 715 } 716 } 717 718 if (*cp == HASH_DELIM) { 719 if (find_host || delete_host) { 720 cp2 = host_hash(name, cp, strlen(cp)); 721 if (cp2 == NULL) { 722 error("line %d: invalid hashed " 723 "name: %.64s...", num, line); 724 invalid = 1; 725 continue; 726 } 727 c = (strcmp(cp2, cp) == 0); 728 if (find_host && c) { 729 printf("# Host %s found: " 730 "line %d type %s\n", name, 731 num, key_type(public)); 732 print_host(out, cp, public, 0); 733 } 734 if (delete_host && !c) 735 print_host(out, cp, public, 0); 736 } else if (hash_hosts) 737 print_host(out, cp, public, 0); 738 } else { 739 if (find_host || delete_host) { 740 c = (match_hostname(name, cp, 741 strlen(cp)) == 1); 742 if (find_host && c) { 743 printf("# Host %s found: " 744 "line %d type %s\n", name, 745 num, key_type(public)); 746 print_host(out, name, public, 747 hash_hosts); 748 } 749 if (delete_host && !c) 750 print_host(out, cp, public, 0); 751 } else if (hash_hosts) { 752 for (cp2 = strsep(&cp, ","); 753 cp2 != NULL && *cp2 != '\0'; 754 cp2 = strsep(&cp, ",")) { 755 if (strcspn(cp2, "*?!") != strlen(cp2)) 756 fprintf(stderr, "Warning: " 757 "ignoring host name with " 758 "metacharacters: %.64s\n", 759 cp2); 760 else 761 print_host(out, cp2, public, 1); 762 } 763 has_unhashed = 1; 764 } 765 } 766 key_free(public); 767 } 768 fclose(in); 769 770 if (invalid) { 771 fprintf(stderr, "%s is not a valid known_hosts file.\n", 772 identity_file); 773 if (inplace) { 774 fprintf(stderr, "Not replacing existing known_hosts " 775 "file because of errors\n"); 776 fclose(out); 777 unlink(tmp); 778 } 779 exit(1); 780 } 781 782 if (inplace) { 783 fclose(out); 784 785 /* Backup existing file */ 786 if (unlink(old) == -1 && errno != ENOENT) 787 fatal("unlink %.100s: %s", old, strerror(errno)); 788 if (link(identity_file, old) == -1) 789 fatal("link %.100s to %.100s: %s", identity_file, old, 790 strerror(errno)); 791 /* Move new one into place */ 792 if (rename(tmp, identity_file) == -1) { 793 error("rename\"%s\" to \"%s\": %s", tmp, identity_file, 794 strerror(errno)); 795 unlink(tmp); 796 unlink(old); 797 exit(1); 798 } 799 800 fprintf(stderr, "%s updated.\n", identity_file); 801 fprintf(stderr, "Original contents retained as %s\n", old); 802 if (has_unhashed) { 803 fprintf(stderr, "WARNING: %s contains unhashed " 804 "entries\n", old); 805 fprintf(stderr, "Delete this file to ensure privacy " 806 "of hostnames\n"); 807 } 808 } 809 810 exit(0); 811 } 812 813 /* 814 * Perform changing a passphrase. The argument is the passwd structure 815 * for the current user. 816 */ 817 static void 818 do_change_passphrase(struct passwd *pw) 819 { 820 char *comment; 821 char *old_passphrase, *passphrase1, *passphrase2; 822 struct stat st; 823 Key *private; 824 825 if (!have_identity) 826 ask_filename(pw, "Enter file in which the key is"); 827 if (stat(identity_file, &st) < 0) { 828 perror(identity_file); 829 exit(1); 830 } 831 /* Try to load the file with empty passphrase. */ 832 private = key_load_private(identity_file, "", &comment); 833 if (private == NULL) { 834 if (identity_passphrase) 835 old_passphrase = xstrdup(identity_passphrase); 836 else 837 old_passphrase = 838 read_passphrase("Enter old passphrase: ", 839 RP_ALLOW_STDIN); 840 private = key_load_private(identity_file, old_passphrase, 841 &comment); 842 memset(old_passphrase, 0, strlen(old_passphrase)); 843 xfree(old_passphrase); 844 if (private == NULL) { 845 printf("Bad passphrase.\n"); 846 exit(1); 847 } 848 } 849 printf("Key has comment '%s'\n", comment); 850 851 /* Ask the new passphrase (twice). */ 852 if (identity_new_passphrase) { 853 passphrase1 = xstrdup(identity_new_passphrase); 854 passphrase2 = NULL; 855 } else { 856 passphrase1 = 857 read_passphrase("Enter new passphrase (empty for no " 858 "passphrase): ", RP_ALLOW_STDIN); 859 passphrase2 = read_passphrase("Enter same passphrase again: ", 860 RP_ALLOW_STDIN); 861 862 /* Verify that they are the same. */ 863 if (strcmp(passphrase1, passphrase2) != 0) { 864 memset(passphrase1, 0, strlen(passphrase1)); 865 memset(passphrase2, 0, strlen(passphrase2)); 866 xfree(passphrase1); 867 xfree(passphrase2); 868 printf("Pass phrases do not match. Try again.\n"); 869 exit(1); 870 } 871 /* Destroy the other copy. */ 872 memset(passphrase2, 0, strlen(passphrase2)); 873 xfree(passphrase2); 874 } 875 876 /* Save the file using the new passphrase. */ 877 if (!key_save_private(private, identity_file, passphrase1, comment)) { 878 printf("Saving the key failed: %s.\n", identity_file); 879 memset(passphrase1, 0, strlen(passphrase1)); 880 xfree(passphrase1); 881 key_free(private); 882 xfree(comment); 883 exit(1); 884 } 885 /* Destroy the passphrase and the copy of the key in memory. */ 886 memset(passphrase1, 0, strlen(passphrase1)); 887 xfree(passphrase1); 888 key_free(private); /* Destroys contents */ 889 xfree(comment); 890 891 printf("Your identification has been saved with the new passphrase.\n"); 892 exit(0); 893 } 894 895 /* 896 * Print the SSHFP RR. 897 */ 898 static int 899 do_print_resource_record(struct passwd *pw, char *fname, char *hname) 900 { 901 Key *public; 902 char *comment = NULL; 903 struct stat st; 904 905 if (fname == NULL) 906 ask_filename(pw, "Enter file in which the key is"); 907 if (stat(fname, &st) < 0) { 908 if (errno == ENOENT) 909 return 0; 910 perror(fname); 911 exit(1); 912 } 913 public = key_load_public(fname, &comment); 914 if (public != NULL) { 915 export_dns_rr(hname, public, stdout, print_generic); 916 key_free(public); 917 xfree(comment); 918 return 1; 919 } 920 if (comment) 921 xfree(comment); 922 923 printf("failed to read v2 public key from %s.\n", fname); 924 exit(1); 925 } 926 927 /* 928 * Change the comment of a private key file. 929 */ 930 static void 931 do_change_comment(struct passwd *pw) 932 { 933 char new_comment[1024], *comment, *passphrase; 934 Key *private; 935 Key *public; 936 struct stat st; 937 FILE *f; 938 int fd; 939 940 if (!have_identity) 941 ask_filename(pw, "Enter file in which the key is"); 942 if (stat(identity_file, &st) < 0) { 943 perror(identity_file); 944 exit(1); 945 } 946 private = key_load_private(identity_file, "", &comment); 947 if (private == NULL) { 948 if (identity_passphrase) 949 passphrase = xstrdup(identity_passphrase); 950 else if (identity_new_passphrase) 951 passphrase = xstrdup(identity_new_passphrase); 952 else 953 passphrase = read_passphrase("Enter passphrase: ", 954 RP_ALLOW_STDIN); 955 /* Try to load using the passphrase. */ 956 private = key_load_private(identity_file, passphrase, &comment); 957 if (private == NULL) { 958 memset(passphrase, 0, strlen(passphrase)); 959 xfree(passphrase); 960 printf("Bad passphrase.\n"); 961 exit(1); 962 } 963 } else { 964 passphrase = xstrdup(""); 965 } 966 if (private->type != KEY_RSA1) { 967 fprintf(stderr, "Comments are only supported for RSA1 keys.\n"); 968 key_free(private); 969 exit(1); 970 } 971 printf("Key now has comment '%s'\n", comment); 972 973 if (identity_comment) { 974 strlcpy(new_comment, identity_comment, sizeof(new_comment)); 975 } else { 976 printf("Enter new comment: "); 977 fflush(stdout); 978 if (!fgets(new_comment, sizeof(new_comment), stdin)) { 979 memset(passphrase, 0, strlen(passphrase)); 980 key_free(private); 981 exit(1); 982 } 983 new_comment[strcspn(new_comment, "\n")] = '\0'; 984 } 985 986 /* Save the file using the new passphrase. */ 987 if (!key_save_private(private, identity_file, passphrase, new_comment)) { 988 printf("Saving the key failed: %s.\n", identity_file); 989 memset(passphrase, 0, strlen(passphrase)); 990 xfree(passphrase); 991 key_free(private); 992 xfree(comment); 993 exit(1); 994 } 995 memset(passphrase, 0, strlen(passphrase)); 996 xfree(passphrase); 997 public = key_from_private(private); 998 key_free(private); 999 1000 strlcat(identity_file, ".pub", sizeof(identity_file)); 1001 fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 1002 if (fd == -1) { 1003 printf("Could not save your public key in %s\n", identity_file); 1004 exit(1); 1005 } 1006 f = fdopen(fd, "w"); 1007 if (f == NULL) { 1008 printf("fdopen %s failed", identity_file); 1009 exit(1); 1010 } 1011 if (!key_write(public, f)) 1012 fprintf(stderr, "write key failed"); 1013 key_free(public); 1014 fprintf(f, " %s\n", new_comment); 1015 fclose(f); 1016 1017 xfree(comment); 1018 1019 printf("The comment in your key file has been changed.\n"); 1020 exit(0); 1021 } 1022 1023 static void 1024 usage(void) 1025 { 1026 fprintf(stderr, "usage: %s [options]\n", __progname); 1027 fprintf(stderr, "Options:\n"); 1028 fprintf(stderr, " -a trials Number of trials for screening DH-GEX moduli.\n"); 1029 fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); 1030 fprintf(stderr, " -b bits Number of bits in the key to create.\n"); 1031 fprintf(stderr, " -C comment Provide new comment.\n"); 1032 fprintf(stderr, " -c Change comment in private and public key files.\n"); 1033 #ifdef SMARTCARD 1034 fprintf(stderr, " -D reader Download public key from smartcard.\n"); 1035 #endif /* SMARTCARD */ 1036 fprintf(stderr, " -e Convert OpenSSH to RFC 4716 key file.\n"); 1037 fprintf(stderr, " -F hostname Find hostname in known hosts file.\n"); 1038 fprintf(stderr, " -f filename Filename of the key file.\n"); 1039 fprintf(stderr, " -G file Generate candidates for DH-GEX moduli.\n"); 1040 fprintf(stderr, " -g Use generic DNS resource record format.\n"); 1041 fprintf(stderr, " -H Hash names in known_hosts file.\n"); 1042 fprintf(stderr, " -i Convert RFC 4716 to OpenSSH key file.\n"); 1043 fprintf(stderr, " -l Show fingerprint of key file.\n"); 1044 fprintf(stderr, " -M memory Amount of memory (MB) to use for generating DH-GEX moduli.\n"); 1045 fprintf(stderr, " -N phrase Provide new passphrase.\n"); 1046 fprintf(stderr, " -P phrase Provide old passphrase.\n"); 1047 fprintf(stderr, " -p Change passphrase of private key file.\n"); 1048 fprintf(stderr, " -q Quiet.\n"); 1049 fprintf(stderr, " -R hostname Remove host from known_hosts file.\n"); 1050 fprintf(stderr, " -r hostname Print DNS resource record.\n"); 1051 fprintf(stderr, " -S start Start point (hex) for generating DH-GEX moduli.\n"); 1052 fprintf(stderr, " -T file Screen candidates for DH-GEX moduli.\n"); 1053 fprintf(stderr, " -t type Specify type of key to create.\n"); 1054 #ifdef SMARTCARD 1055 fprintf(stderr, " -U reader Upload private key to smartcard.\n"); 1056 #endif /* SMARTCARD */ 1057 fprintf(stderr, " -v Verbose.\n"); 1058 fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); 1059 fprintf(stderr, " -y Read private key file and print public key.\n"); 1060 1061 exit(1); 1062 } 1063 1064 /* 1065 * Main program for key management. 1066 */ 1067 int 1068 main(int argc, char **argv) 1069 { 1070 char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; 1071 char out_file[MAXPATHLEN], *reader_id = NULL; 1072 char *rr_hostname = NULL; 1073 Key *private, *public; 1074 struct passwd *pw; 1075 struct stat st; 1076 int opt, type, fd, download = 0; 1077 u_int32_t memory = 0, generator_wanted = 0, trials = 100; 1078 int do_gen_candidates = 0, do_screen_candidates = 0; 1079 BIGNUM *start = NULL; 1080 FILE *f; 1081 const char *errstr; 1082 1083 extern int optind; 1084 extern char *optarg; 1085 1086 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 1087 sanitise_stdfd(); 1088 1089 SSLeay_add_all_algorithms(); 1090 log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1); 1091 1092 /* we need this for the home * directory. */ 1093 pw = getpwuid(getuid()); 1094 if (!pw) { 1095 printf("You don't exist, go away!\n"); 1096 exit(1); 1097 } 1098 if (gethostname(hostname, sizeof(hostname)) < 0) { 1099 perror("gethostname"); 1100 exit(1); 1101 } 1102 1103 while ((opt = getopt(argc, argv, 1104 "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) { 1105 switch (opt) { 1106 case 'b': 1107 bits = (u_int32_t)strtonum(optarg, 768, 32768, &errstr); 1108 if (errstr) 1109 fatal("Bits has bad value %s (%s)", 1110 optarg, errstr); 1111 break; 1112 case 'F': 1113 find_host = 1; 1114 rr_hostname = optarg; 1115 break; 1116 case 'H': 1117 hash_hosts = 1; 1118 break; 1119 case 'R': 1120 delete_host = 1; 1121 rr_hostname = optarg; 1122 break; 1123 case 'l': 1124 print_fingerprint = 1; 1125 break; 1126 case 'B': 1127 print_bubblebabble = 1; 1128 break; 1129 case 'p': 1130 change_passphrase = 1; 1131 break; 1132 case 'c': 1133 change_comment = 1; 1134 break; 1135 case 'f': 1136 if (strlcpy(identity_file, optarg, sizeof(identity_file)) >= 1137 sizeof(identity_file)) 1138 fatal("Identity filename too long"); 1139 have_identity = 1; 1140 break; 1141 case 'g': 1142 print_generic = 1; 1143 break; 1144 case 'P': 1145 identity_passphrase = optarg; 1146 break; 1147 case 'N': 1148 identity_new_passphrase = optarg; 1149 break; 1150 case 'C': 1151 identity_comment = optarg; 1152 break; 1153 case 'q': 1154 quiet = 1; 1155 break; 1156 case 'e': 1157 case 'x': 1158 /* export key */ 1159 convert_to_ssh2 = 1; 1160 break; 1161 case 'i': 1162 case 'X': 1163 /* import key */ 1164 convert_from_ssh2 = 1; 1165 break; 1166 case 'y': 1167 print_public = 1; 1168 break; 1169 case 'd': 1170 key_type_name = "dsa"; 1171 break; 1172 case 't': 1173 key_type_name = optarg; 1174 break; 1175 case 'D': 1176 download = 1; 1177 /*FALLTHROUGH*/ 1178 case 'U': 1179 reader_id = optarg; 1180 break; 1181 case 'v': 1182 if (log_level == SYSLOG_LEVEL_INFO) 1183 log_level = SYSLOG_LEVEL_DEBUG1; 1184 else { 1185 if (log_level >= SYSLOG_LEVEL_DEBUG1 && 1186 log_level < SYSLOG_LEVEL_DEBUG3) 1187 log_level++; 1188 } 1189 break; 1190 case 'r': 1191 rr_hostname = optarg; 1192 break; 1193 case 'W': 1194 generator_wanted = (u_int32_t)strtonum(optarg, 1, 1195 UINT_MAX, &errstr); 1196 if (errstr) 1197 fatal("Desired generator has bad value: %s (%s)", 1198 optarg, errstr); 1199 break; 1200 case 'a': 1201 trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); 1202 if (errstr) 1203 fatal("Invalid number of trials: %s (%s)", 1204 optarg, errstr); 1205 break; 1206 case 'M': 1207 memory = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); 1208 if (errstr) { 1209 fatal("Memory limit is %s: %s", errstr, optarg); 1210 } 1211 break; 1212 case 'G': 1213 do_gen_candidates = 1; 1214 if (strlcpy(out_file, optarg, sizeof(out_file)) >= 1215 sizeof(out_file)) 1216 fatal("Output filename too long"); 1217 break; 1218 case 'T': 1219 do_screen_candidates = 1; 1220 if (strlcpy(out_file, optarg, sizeof(out_file)) >= 1221 sizeof(out_file)) 1222 fatal("Output filename too long"); 1223 break; 1224 case 'S': 1225 /* XXX - also compare length against bits */ 1226 if (BN_hex2bn(&start, optarg) == 0) 1227 fatal("Invalid start point."); 1228 break; 1229 case '?': 1230 default: 1231 usage(); 1232 } 1233 } 1234 1235 /* reinit */ 1236 log_init(argv[0], log_level, SYSLOG_FACILITY_USER, 1); 1237 1238 if (optind < argc) { 1239 printf("Too many arguments.\n"); 1240 usage(); 1241 } 1242 if (change_passphrase && change_comment) { 1243 printf("Can only have one of -p and -c.\n"); 1244 usage(); 1245 } 1246 if (print_fingerprint && (delete_host || hash_hosts)) { 1247 printf("Cannot use -l with -D or -R.\n"); 1248 usage(); 1249 } 1250 if (delete_host || hash_hosts || find_host) 1251 do_known_hosts(pw, rr_hostname); 1252 if (print_fingerprint || print_bubblebabble) 1253 do_fingerprint(pw); 1254 if (change_passphrase) 1255 do_change_passphrase(pw); 1256 if (change_comment) 1257 do_change_comment(pw); 1258 if (convert_to_ssh2) 1259 do_convert_to_ssh2(pw); 1260 if (convert_from_ssh2) 1261 do_convert_from_ssh2(pw); 1262 if (print_public) 1263 do_print_public(pw); 1264 if (rr_hostname != NULL) { 1265 unsigned int n = 0; 1266 1267 if (have_identity) { 1268 n = do_print_resource_record(pw, 1269 identity_file, rr_hostname); 1270 if (n == 0) { 1271 perror(identity_file); 1272 exit(1); 1273 } 1274 exit(0); 1275 } else { 1276 1277 n += do_print_resource_record(pw, 1278 _PATH_HOST_RSA_KEY_FILE, rr_hostname); 1279 n += do_print_resource_record(pw, 1280 _PATH_HOST_DSA_KEY_FILE, rr_hostname); 1281 1282 if (n == 0) 1283 fatal("no keys found."); 1284 exit(0); 1285 } 1286 } 1287 if (reader_id != NULL) { 1288 #ifdef SMARTCARD 1289 if (download) 1290 do_download(pw, reader_id); 1291 else 1292 do_upload(pw, reader_id); 1293 #else /* SMARTCARD */ 1294 fatal("no support for smartcards."); 1295 #endif /* SMARTCARD */ 1296 } 1297 1298 if (do_gen_candidates) { 1299 FILE *out = fopen(out_file, "w"); 1300 1301 if (out == NULL) { 1302 error("Couldn't open modulus candidate file \"%s\": %s", 1303 out_file, strerror(errno)); 1304 return (1); 1305 } 1306 if (bits == 0) 1307 bits = DEFAULT_BITS; 1308 if (gen_candidates(out, memory, bits, start) != 0) 1309 fatal("modulus candidate generation failed"); 1310 1311 return (0); 1312 } 1313 1314 if (do_screen_candidates) { 1315 FILE *in; 1316 FILE *out = fopen(out_file, "w"); 1317 1318 if (have_identity && strcmp(identity_file, "-") != 0) { 1319 if ((in = fopen(identity_file, "r")) == NULL) { 1320 fatal("Couldn't open modulus candidate " 1321 "file \"%s\": %s", identity_file, 1322 strerror(errno)); 1323 } 1324 } else 1325 in = stdin; 1326 1327 if (out == NULL) { 1328 fatal("Couldn't open moduli file \"%s\": %s", 1329 out_file, strerror(errno)); 1330 } 1331 if (prime_test(in, out, trials, generator_wanted) != 0) 1332 fatal("modulus screening failed"); 1333 return (0); 1334 } 1335 1336 arc4random_stir(); 1337 1338 if (key_type_name == NULL) 1339 key_type_name = "rsa"; 1340 1341 type = key_type_from_name(key_type_name); 1342 if (type == KEY_UNSPEC) { 1343 fprintf(stderr, "unknown key type %s\n", key_type_name); 1344 exit(1); 1345 } 1346 if (bits == 0) 1347 bits = (type == KEY_DSA) ? DEFAULT_BITS_DSA : DEFAULT_BITS; 1348 if (type == KEY_DSA && bits != 1024) 1349 fatal("DSA keys must be 1024 bits"); 1350 if (!quiet) 1351 printf("Generating public/private %s key pair.\n", key_type_name); 1352 private = key_generate(type, bits); 1353 if (private == NULL) { 1354 fprintf(stderr, "key_generate failed"); 1355 exit(1); 1356 } 1357 public = key_from_private(private); 1358 1359 if (!have_identity) 1360 ask_filename(pw, "Enter file in which to save the key"); 1361 1362 /* Create ~/.ssh directory if it doesn't already exist. */ 1363 snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); 1364 if (strstr(identity_file, dotsshdir) != NULL && 1365 stat(dotsshdir, &st) < 0) { 1366 if (mkdir(dotsshdir, 0700) < 0) 1367 error("Could not create directory '%s'.", dotsshdir); 1368 else if (!quiet) 1369 printf("Created directory '%s'.\n", dotsshdir); 1370 } 1371 /* If the file already exists, ask the user to confirm. */ 1372 if (stat(identity_file, &st) >= 0) { 1373 char yesno[3]; 1374 printf("%s already exists.\n", identity_file); 1375 printf("Overwrite (y/n)? "); 1376 fflush(stdout); 1377 if (fgets(yesno, sizeof(yesno), stdin) == NULL) 1378 exit(1); 1379 if (yesno[0] != 'y' && yesno[0] != 'Y') 1380 exit(1); 1381 } 1382 /* Ask for a passphrase (twice). */ 1383 if (identity_passphrase) 1384 passphrase1 = xstrdup(identity_passphrase); 1385 else if (identity_new_passphrase) 1386 passphrase1 = xstrdup(identity_new_passphrase); 1387 else { 1388 passphrase_again: 1389 passphrase1 = 1390 read_passphrase("Enter passphrase (empty for no " 1391 "passphrase): ", RP_ALLOW_STDIN); 1392 passphrase2 = read_passphrase("Enter same passphrase again: ", 1393 RP_ALLOW_STDIN); 1394 if (strcmp(passphrase1, passphrase2) != 0) { 1395 /* 1396 * The passphrases do not match. Clear them and 1397 * retry. 1398 */ 1399 memset(passphrase1, 0, strlen(passphrase1)); 1400 memset(passphrase2, 0, strlen(passphrase2)); 1401 xfree(passphrase1); 1402 xfree(passphrase2); 1403 printf("Passphrases do not match. Try again.\n"); 1404 goto passphrase_again; 1405 } 1406 /* Clear the other copy of the passphrase. */ 1407 memset(passphrase2, 0, strlen(passphrase2)); 1408 xfree(passphrase2); 1409 } 1410 1411 if (identity_comment) { 1412 strlcpy(comment, identity_comment, sizeof(comment)); 1413 } else { 1414 /* Create default commend field for the passphrase. */ 1415 snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); 1416 } 1417 1418 /* Save the key with the given passphrase and comment. */ 1419 if (!key_save_private(private, identity_file, passphrase1, comment)) { 1420 printf("Saving the key failed: %s.\n", identity_file); 1421 memset(passphrase1, 0, strlen(passphrase1)); 1422 xfree(passphrase1); 1423 exit(1); 1424 } 1425 /* Clear the passphrase. */ 1426 memset(passphrase1, 0, strlen(passphrase1)); 1427 xfree(passphrase1); 1428 1429 /* Clear the private key and the random number generator. */ 1430 key_free(private); 1431 arc4random_stir(); 1432 1433 if (!quiet) 1434 printf("Your identification has been saved in %s.\n", identity_file); 1435 1436 strlcat(identity_file, ".pub", sizeof(identity_file)); 1437 fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 1438 if (fd == -1) { 1439 printf("Could not save your public key in %s\n", identity_file); 1440 exit(1); 1441 } 1442 f = fdopen(fd, "w"); 1443 if (f == NULL) { 1444 printf("fdopen %s failed", identity_file); 1445 exit(1); 1446 } 1447 if (!key_write(public, f)) 1448 fprintf(stderr, "write key failed"); 1449 fprintf(f, " %s\n", comment); 1450 fclose(f); 1451 1452 if (!quiet) { 1453 char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); 1454 char *ra = key_fingerprint(public, SSH_FP_MD5, 1455 SSH_FP_RANDOMART); 1456 printf("Your public key has been saved in %s.\n", 1457 identity_file); 1458 printf("The key fingerprint is:\n"); 1459 printf("%s %s\n", fp, comment); 1460 printf("The key's randomart image is:\n"); 1461 printf("%s\n", ra); 1462 xfree(ra); 1463 xfree(fp); 1464 } 1465 1466 key_free(public); 1467 exit(0); 1468 } 1469