1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 /* 6 * Author: Tatu Ylonen <ylo@cs.hut.fi> 7 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 8 * All rights reserved 9 * Identity and host key generation and maintenance. 10 * 11 * As far as I am concerned, the code I have written for this software 12 * can be used freely for any purpose. Any derived versions of this 13 * software must be clearly marked as such, and if the derived work is 14 * incompatible with the protocol description in the RFC file, it must be 15 * called by a name other than "ssh" or "Secure Shell". 16 */ 17 18 #include "includes.h" 19 RCSID("$OpenBSD: ssh-keygen.c,v 1.101 2002/06/23 09:39:55 deraadt Exp $"); 20 21 #pragma ident "%Z%%M% %I% %E% SMI" 22 23 #include <openssl/evp.h> 24 #include <openssl/pem.h> 25 26 #include "xmalloc.h" 27 #include "key.h" 28 #include "rsa.h" 29 #include "authfile.h" 30 #include "uuencode.h" 31 #include "buffer.h" 32 #include "bufaux.h" 33 #include "pathnames.h" 34 #include "log.h" 35 #include "readpass.h" 36 #include <langinfo.h> 37 38 #ifdef SMARTCARD 39 #include "scard.h" 40 #endif 41 42 /* Number of bits in the RSA/DSA key. This value can be changed on the command line. */ 43 int bits = 1024; 44 45 /* 46 * Flag indicating that we just want to change the passphrase. This can be 47 * set on the command line. 48 */ 49 int change_passphrase = 0; 50 51 /* 52 * Flag indicating that we just want to change the comment. This can be set 53 * on the command line. 54 */ 55 int change_comment = 0; 56 57 int quiet = 0; 58 59 /* Flag indicating that we just want to see the key fingerprint */ 60 int print_fingerprint = 0; 61 int print_bubblebabble = 0; 62 63 /* The identity file name, given on the command line or entered by the user. */ 64 char identity_file[1024]; 65 int have_identity = 0; 66 67 /* This is set to the passphrase if given on the command line. */ 68 char *identity_passphrase = NULL; 69 70 /* This is set to the new passphrase if given on the command line. */ 71 char *identity_new_passphrase = NULL; 72 73 /* This is set to the new comment if given on the command line. */ 74 char *identity_comment = NULL; 75 76 /* Dump public key file in format used by real and the original SSH 2 */ 77 int convert_to_ssh2 = 0; 78 int convert_from_ssh2 = 0; 79 int print_public = 0; 80 81 char *key_type_name = NULL; 82 83 /* argv0 */ 84 #ifdef HAVE___PROGNAME 85 extern char *__progname; 86 #else 87 char *__progname; 88 #endif 89 90 char hostname[MAXHOSTNAMELEN]; 91 92 static void 93 ask_filename(struct passwd *pw, const char *prompt) 94 { 95 char buf[1024]; 96 char *name = NULL; 97 98 if (key_type_name == NULL) 99 name = _PATH_SSH_CLIENT_ID_RSA; 100 else 101 switch (key_type_from_name(key_type_name)) { 102 case KEY_RSA1: 103 name = _PATH_SSH_CLIENT_IDENTITY; 104 break; 105 case KEY_DSA: 106 name = _PATH_SSH_CLIENT_ID_DSA; 107 break; 108 case KEY_RSA: 109 name = _PATH_SSH_CLIENT_ID_RSA; 110 break; 111 default: 112 (void) fprintf(stderr, gettext("bad key type")); 113 exit(1); 114 break; 115 } 116 117 (void) snprintf(identity_file, sizeof(identity_file), "%s/%s", pw->pw_dir, name); 118 (void) fprintf(stderr, "%s (%s): ", gettext(prompt), identity_file); 119 (void) fflush(stderr); 120 if (fgets(buf, sizeof(buf), stdin) == NULL) 121 exit(1); 122 if (strchr(buf, '\n')) 123 *strchr(buf, '\n') = 0; 124 if (strcmp(buf, "") != 0) 125 (void) strlcpy(identity_file, buf, sizeof(identity_file)); 126 have_identity = 1; 127 } 128 129 static Key * 130 load_identity(char *filename) 131 { 132 char *pass; 133 Key *prv; 134 135 prv = key_load_private(filename, "", NULL); 136 if (prv == NULL) { 137 if (identity_passphrase) 138 pass = xstrdup(identity_passphrase); 139 else 140 pass = read_passphrase(gettext("Enter passphrase: "), 141 RP_ALLOW_STDIN); 142 prv = key_load_private(filename, pass, NULL); 143 (void) memset(pass, 0, strlen(pass)); 144 xfree(pass); 145 } 146 return prv; 147 } 148 149 #define SSH_COM_PUBLIC_BEGIN "---- BEGIN SSH2 PUBLIC KEY ----" 150 #define SSH_COM_PUBLIC_END "---- END SSH2 PUBLIC KEY ----" 151 #define SSH_COM_PRIVATE_BEGIN "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----" 152 #define SSH_COM_PRIVATE_KEY_MAGIC 0x3f6ff9eb 153 154 static void 155 do_convert_to_ssh2(struct passwd *pw) 156 { 157 Key *k; 158 u_int len; 159 u_char *blob; 160 struct stat st; 161 162 if (!have_identity) 163 ask_filename(pw, gettext("Enter file in which the key is")); 164 if (stat(identity_file, &st) < 0) { 165 perror(identity_file); 166 exit(1); 167 } 168 if ((k = key_load_public(identity_file, NULL)) == NULL) { 169 if ((k = load_identity(identity_file)) == NULL) { 170 (void) fprintf(stderr, gettext("load failed\n")); 171 exit(1); 172 } 173 } 174 if (key_to_blob(k, &blob, &len) <= 0) { 175 (void) fprintf(stderr, gettext("key_to_blob failed\n")); 176 exit(1); 177 } 178 (void) fprintf(stdout, "%s\n", SSH_COM_PUBLIC_BEGIN); 179 (void) fprintf(stdout, gettext( 180 "Comment: \"%u-bit %s, converted from OpenSSH by %s@%s\"\n"), 181 key_size(k), key_type(k), 182 pw->pw_name, hostname); 183 dump_base64(stdout, blob, len); 184 (void) fprintf(stdout, "%s\n", SSH_COM_PUBLIC_END); 185 key_free(k); 186 xfree(blob); 187 exit(0); 188 } 189 190 static void 191 buffer_get_bignum_bits(Buffer *b, BIGNUM *value) 192 { 193 int bits = buffer_get_int(b); 194 int bytes = (bits + 7) / 8; 195 196 if (buffer_len(b) < bytes) 197 fatal("buffer_get_bignum_bits: input buffer too small: " 198 "need %d have %d", bytes, buffer_len(b)); 199 (void) BN_bin2bn(buffer_ptr(b), bytes, value); 200 buffer_consume(b, bytes); 201 } 202 203 static Key * 204 do_convert_private_ssh2_from_blob(u_char *blob, u_int blen) 205 { 206 Buffer b; 207 Key *key = NULL; 208 char *type, *cipher; 209 u_char *sig, data[] = "abcde12345"; 210 int magic, rlen, ktype, i1, i2, i3, i4; 211 u_int slen; 212 u_long e; 213 214 buffer_init(&b); 215 buffer_append(&b, blob, blen); 216 217 magic = buffer_get_int(&b); 218 if (magic != SSH_COM_PRIVATE_KEY_MAGIC) { 219 error("bad magic 0x%x != 0x%x", magic, SSH_COM_PRIVATE_KEY_MAGIC); 220 buffer_free(&b); 221 return NULL; 222 } 223 i1 = buffer_get_int(&b); 224 type = buffer_get_string(&b, NULL); 225 cipher = buffer_get_string(&b, NULL); 226 i2 = buffer_get_int(&b); 227 i3 = buffer_get_int(&b); 228 i4 = buffer_get_int(&b); 229 debug("ignore (%d %d %d %d)", i1,i2,i3,i4); 230 if (strcmp(cipher, "none") != 0) { 231 error("unsupported cipher %s", cipher); 232 xfree(cipher); 233 buffer_free(&b); 234 xfree(type); 235 return NULL; 236 } 237 xfree(cipher); 238 239 if (strstr(type, "dsa")) { 240 ktype = KEY_DSA; 241 } else if (strstr(type, "rsa")) { 242 ktype = KEY_RSA; 243 } else { 244 xfree(type); 245 return NULL; 246 } 247 key = key_new_private(ktype); 248 xfree(type); 249 250 switch (key->type) { 251 case KEY_DSA: 252 buffer_get_bignum_bits(&b, key->dsa->p); 253 buffer_get_bignum_bits(&b, key->dsa->g); 254 buffer_get_bignum_bits(&b, key->dsa->q); 255 buffer_get_bignum_bits(&b, key->dsa->pub_key); 256 buffer_get_bignum_bits(&b, key->dsa->priv_key); 257 break; 258 case KEY_RSA: 259 e = buffer_get_char(&b); 260 debug("e %lx", e); 261 if (e < 30) { 262 e <<= 8; 263 e += buffer_get_char(&b); 264 debug("e %lx", e); 265 e <<= 8; 266 e += buffer_get_char(&b); 267 debug("e %lx", e); 268 } 269 if (!BN_set_word(key->rsa->e, e)) { 270 buffer_free(&b); 271 key_free(key); 272 return NULL; 273 } 274 buffer_get_bignum_bits(&b, key->rsa->d); 275 buffer_get_bignum_bits(&b, key->rsa->n); 276 buffer_get_bignum_bits(&b, key->rsa->iqmp); 277 buffer_get_bignum_bits(&b, key->rsa->q); 278 buffer_get_bignum_bits(&b, key->rsa->p); 279 rsa_generate_additional_parameters(key->rsa); 280 break; 281 } 282 rlen = buffer_len(&b); 283 if (rlen != 0) 284 error("do_convert_private_ssh2_from_blob: " 285 "remaining bytes in key blob %d", rlen); 286 buffer_free(&b); 287 288 /* try the key */ 289 (void) key_sign(key, &sig, &slen, data, sizeof(data)); 290 key_verify(key, sig, slen, data, sizeof(data)); 291 xfree(sig); 292 return key; 293 } 294 295 static void 296 do_convert_from_ssh2(struct passwd *pw) 297 { 298 Key *k; 299 int blen; 300 u_int len; 301 char line[1024], *p; 302 u_char blob[8096]; 303 char encoded[8096]; 304 struct stat st; 305 int escaped = 0, private = 0, ok; 306 FILE *fp; 307 308 if (!have_identity) 309 ask_filename(pw, gettext("Enter file in which the key is")); 310 if (stat(identity_file, &st) < 0) { 311 perror(identity_file); 312 exit(1); 313 } 314 fp = fopen(identity_file, "r"); 315 if (fp == NULL) { 316 perror(identity_file); 317 exit(1); 318 } 319 encoded[0] = '\0'; 320 while (fgets(line, sizeof(line), fp)) { 321 if (!(p = strchr(line, '\n'))) { 322 (void) fprintf(stderr, gettext("input line too long.\n")); 323 exit(1); 324 } 325 if (p > line && p[-1] == '\\') 326 escaped++; 327 if (strncmp(line, "----", 4) == 0 || 328 strstr(line, ": ") != NULL) { 329 if (strstr(line, SSH_COM_PRIVATE_BEGIN) != NULL) 330 private = 1; 331 if (strstr(line, " END ") != NULL) { 332 break; 333 } 334 /* fprintf(stderr, "ignore: %s", line); */ 335 continue; 336 } 337 if (escaped) { 338 escaped--; 339 /* fprintf(stderr, "escaped: %s", line); */ 340 continue; 341 } 342 *p = '\0'; 343 (void) strlcat(encoded, line, sizeof(encoded)); 344 } 345 len = strlen(encoded); 346 if (((len % 4) == 3) && 347 (encoded[len-1] == '=') && 348 (encoded[len-2] == '=') && 349 (encoded[len-3] == '=')) 350 encoded[len-3] = '\0'; 351 blen = uudecode(encoded, blob, sizeof(blob)); 352 if (blen < 0) { 353 (void) fprintf(stderr, gettext("uudecode failed.\n")); 354 exit(1); 355 } 356 k = private ? 357 do_convert_private_ssh2_from_blob(blob, blen) : 358 key_from_blob(blob, blen); 359 if (k == NULL) { 360 (void) fprintf(stderr, gettext("decode blob failed.\n")); 361 exit(1); 362 } 363 ok = private ? 364 (k->type == KEY_DSA ? 365 PEM_write_DSAPrivateKey(stdout, k->dsa, NULL, NULL, 0, NULL, NULL) : 366 PEM_write_RSAPrivateKey(stdout, k->rsa, NULL, NULL, 0, NULL, NULL)) : 367 key_write(k, stdout); 368 if (!ok) { 369 (void) fprintf(stderr, gettext("key write failed")); 370 exit(1); 371 } 372 key_free(k); 373 if (!private) 374 (void) fprintf(stdout, "\n"); 375 (void) fclose(fp); 376 exit(0); 377 } 378 379 static void 380 do_print_public(struct passwd *pw) 381 { 382 Key *prv; 383 struct stat st; 384 385 if (!have_identity) 386 ask_filename(pw, gettext("Enter file in which the key is")); 387 if (stat(identity_file, &st) < 0) { 388 perror(identity_file); 389 exit(1); 390 } 391 prv = load_identity(identity_file); 392 if (prv == NULL) { 393 (void) fprintf(stderr, gettext("load failed\n")); 394 exit(1); 395 } 396 if (!key_write(prv, stdout)) 397 (void) fprintf(stderr, gettext("key_write failed")); 398 key_free(prv); 399 (void) fprintf(stdout, "\n"); 400 exit(0); 401 } 402 403 #ifdef SMARTCARD 404 static void 405 do_upload(struct passwd *pw, const char *sc_reader_id) 406 { 407 Key *prv = NULL; 408 struct stat st; 409 int ret; 410 411 if (!have_identity) 412 ask_filename(pw, gettext("Enter file in which the key is")); 413 if (stat(identity_file, &st) < 0) { 414 perror(identity_file); 415 exit(1); 416 } 417 prv = load_identity(identity_file); 418 if (prv == NULL) { 419 error("load failed"); 420 exit(1); 421 } 422 ret = sc_put_key(prv, sc_reader_id); 423 key_free(prv); 424 if (ret < 0) 425 exit(1); 426 log("loading key done"); 427 exit(0); 428 } 429 430 static void 431 do_download(struct passwd *pw, const char *sc_reader_id) 432 { 433 Key **keys = NULL; 434 int i; 435 436 keys = sc_get_keys(sc_reader_id, NULL); 437 if (keys == NULL) 438 fatal("cannot read public key from smartcard"); 439 for (i = 0; keys[i]; i++) { 440 key_write(keys[i], stdout); 441 key_free(keys[i]); 442 (void) fprintf(stdout, "\n"); 443 } 444 xfree(keys); 445 exit(0); 446 } 447 #endif /* SMARTCARD */ 448 449 static void 450 do_fingerprint(struct passwd *pw) 451 { 452 FILE *f; 453 Key *public; 454 char *comment = NULL, *cp, *ep, line[16*1024], *fp; 455 int i, skip = 0, num = 1, invalid = 1; 456 enum fp_rep rep; 457 enum fp_type fptype; 458 struct stat st; 459 460 fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5; 461 rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX; 462 463 if (!have_identity) 464 ask_filename(pw, gettext("Enter file in which the key is")); 465 if (stat(identity_file, &st) < 0) { 466 perror(identity_file); 467 exit(1); 468 } 469 public = key_load_public(identity_file, &comment); 470 if (public != NULL) { 471 fp = key_fingerprint(public, fptype, rep); 472 (void) printf("%u %s %s\n", key_size(public), fp, comment); 473 key_free(public); 474 xfree(comment); 475 xfree(fp); 476 exit(0); 477 } 478 if (comment) 479 xfree(comment); 480 481 f = fopen(identity_file, "r"); 482 if (f != NULL) { 483 while (fgets(line, sizeof(line), f)) { 484 i = strlen(line) - 1; 485 if (line[i] != '\n') { 486 error("line %d too long: %.40s...", num, line); 487 skip = 1; 488 continue; 489 } 490 num++; 491 if (skip) { 492 skip = 0; 493 continue; 494 } 495 line[i] = '\0'; 496 497 /* Skip leading whitespace, empty and comment lines. */ 498 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 499 ; 500 if (!*cp || *cp == '\n' || *cp == '#') 501 continue ; 502 i = strtol(cp, &ep, 10); 503 if (i == 0 || ep == NULL || (*ep != ' ' && *ep != '\t')) { 504 int quoted = 0; 505 comment = cp; 506 for (; *cp && (quoted || (*cp != ' ' && 507 *cp != '\t')); cp++) { 508 if (*cp == '\\' && cp[1] == '"') 509 cp++; /* Skip both */ 510 else if (*cp == '"') 511 quoted = !quoted; 512 } 513 if (!*cp) 514 continue; 515 *cp++ = '\0'; 516 } 517 ep = cp; 518 public = key_new(KEY_RSA1); 519 if (key_read(public, &cp) != 1) { 520 cp = ep; 521 key_free(public); 522 public = key_new(KEY_UNSPEC); 523 if (key_read(public, &cp) != 1) { 524 key_free(public); 525 continue; 526 } 527 } 528 comment = *cp ? cp : comment; 529 fp = key_fingerprint(public, fptype, rep); 530 (void) printf("%u %s %s\n", key_size(public), fp, 531 comment ? comment : gettext("no comment")); 532 xfree(fp); 533 key_free(public); 534 invalid = 0; 535 } 536 (void) fclose(f); 537 } 538 if (invalid) { 539 (void) printf(gettext("%s is not a public key file.\n"), 540 identity_file); 541 exit(1); 542 } 543 exit(0); 544 } 545 546 /* 547 * Perform changing a passphrase. The argument is the passwd structure 548 * for the current user. 549 */ 550 static void 551 do_change_passphrase(struct passwd *pw) 552 { 553 char *comment; 554 char *old_passphrase, *passphrase1, *passphrase2; 555 struct stat st; 556 Key *private; 557 558 if (!have_identity) 559 ask_filename(pw, gettext("Enter file in which the key is")); 560 if (stat(identity_file, &st) < 0) { 561 perror(identity_file); 562 exit(1); 563 } 564 /* Try to load the file with empty passphrase. */ 565 private = key_load_private(identity_file, "", &comment); 566 if (private == NULL) { 567 if (identity_passphrase) 568 old_passphrase = xstrdup(identity_passphrase); 569 else 570 old_passphrase = 571 read_passphrase(gettext("Enter old passphrase: "), 572 RP_ALLOW_STDIN); 573 private = key_load_private(identity_file, old_passphrase, 574 &comment); 575 (void) memset(old_passphrase, 0, strlen(old_passphrase)); 576 xfree(old_passphrase); 577 if (private == NULL) { 578 (void) printf(gettext("Bad passphrase.\n")); 579 exit(1); 580 } 581 } 582 (void) printf(gettext("Key has comment '%s'\n"), comment); 583 584 /* Ask the new passphrase (twice). */ 585 if (identity_new_passphrase) { 586 passphrase1 = xstrdup(identity_new_passphrase); 587 passphrase2 = NULL; 588 } else { 589 passphrase1 = 590 read_passphrase(gettext("Enter new passphrase (empty" 591 " for no passphrase): "), RP_ALLOW_STDIN); 592 passphrase2 = read_passphrase(gettext("Enter same " 593 "passphrase again: "), RP_ALLOW_STDIN); 594 595 /* Verify that they are the same. */ 596 if (strcmp(passphrase1, passphrase2) != 0) { 597 (void) memset(passphrase1, 0, strlen(passphrase1)); 598 (void) memset(passphrase2, 0, strlen(passphrase2)); 599 xfree(passphrase1); 600 xfree(passphrase2); 601 (void) printf(gettext("Pass phrases do not match. Try " 602 "again.\n")); 603 exit(1); 604 } 605 /* Destroy the other copy. */ 606 (void) memset(passphrase2, 0, strlen(passphrase2)); 607 xfree(passphrase2); 608 } 609 610 /* Save the file using the new passphrase. */ 611 if (!key_save_private(private, identity_file, passphrase1, comment)) { 612 (void) printf(gettext("Saving the key failed: %s.\n"), identity_file); 613 (void) memset(passphrase1, 0, strlen(passphrase1)); 614 xfree(passphrase1); 615 key_free(private); 616 xfree(comment); 617 exit(1); 618 } 619 /* Destroy the passphrase and the copy of the key in memory. */ 620 (void) memset(passphrase1, 0, strlen(passphrase1)); 621 xfree(passphrase1); 622 key_free(private); /* Destroys contents */ 623 xfree(comment); 624 625 (void) printf(gettext("Your identification has been saved with the new " 626 "passphrase.\n")); 627 exit(0); 628 } 629 630 /* 631 * Change the comment of a private key file. 632 */ 633 static void 634 do_change_comment(struct passwd *pw) 635 { 636 char new_comment[1024], *comment, *passphrase; 637 Key *private; 638 Key *public; 639 struct stat st; 640 FILE *f; 641 int fd; 642 643 if (!have_identity) 644 ask_filename(pw, gettext("Enter file in which the key is")); 645 if (stat(identity_file, &st) < 0) { 646 perror(identity_file); 647 exit(1); 648 } 649 private = key_load_private(identity_file, "", &comment); 650 if (private == NULL) { 651 if (identity_passphrase) 652 passphrase = xstrdup(identity_passphrase); 653 else if (identity_new_passphrase) 654 passphrase = xstrdup(identity_new_passphrase); 655 else 656 passphrase = 657 read_passphrase(gettext("Enter passphrase: "), 658 RP_ALLOW_STDIN); 659 /* Try to load using the passphrase. */ 660 private = key_load_private(identity_file, passphrase, &comment); 661 if (private == NULL) { 662 (void) memset(passphrase, 0, strlen(passphrase)); 663 xfree(passphrase); 664 (void) printf(gettext("Bad passphrase.\n")); 665 exit(1); 666 } 667 } else { 668 passphrase = xstrdup(""); 669 } 670 if (private->type != KEY_RSA1) { 671 (void) fprintf(stderr, gettext("Comments are only supported for " 672 "RSA1 keys.\n")); 673 key_free(private); 674 exit(1); 675 } 676 (void) printf(gettext("Key now has comment '%s'\n"), comment); 677 678 if (identity_comment) { 679 (void) strlcpy(new_comment, identity_comment, sizeof(new_comment)); 680 } else { 681 (void) printf(gettext("Enter new comment: ")); 682 (void) fflush(stdout); 683 if (!fgets(new_comment, sizeof(new_comment), stdin)) { 684 (void) memset(passphrase, 0, strlen(passphrase)); 685 key_free(private); 686 exit(1); 687 } 688 if (strchr(new_comment, '\n')) 689 *strchr(new_comment, '\n') = 0; 690 } 691 692 /* Save the file using the new passphrase. */ 693 if (!key_save_private(private, identity_file, passphrase, new_comment)) { 694 (void) printf(gettext("Saving the key failed: %s.\n"), identity_file); 695 (void) memset(passphrase, 0, strlen(passphrase)); 696 xfree(passphrase); 697 key_free(private); 698 xfree(comment); 699 exit(1); 700 } 701 (void) memset(passphrase, 0, strlen(passphrase)); 702 xfree(passphrase); 703 public = key_from_private(private); 704 key_free(private); 705 706 (void) strlcat(identity_file, ".pub", sizeof(identity_file)); 707 fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 708 if (fd == -1) { 709 (void) printf(gettext("Could not save your public key in %s\n"), 710 identity_file); 711 exit(1); 712 } 713 f = fdopen(fd, "w"); 714 if (f == NULL) { 715 (void) printf(gettext("fdopen %s failed"), identity_file); 716 exit(1); 717 } 718 if (!key_write(public, f)) 719 (void) fprintf(stderr, gettext("write key failed")); 720 key_free(public); 721 (void) fprintf(f, " %s\n", new_comment); 722 (void) fclose(f); 723 724 xfree(comment); 725 726 (void) printf(gettext("The comment in your key file has been changed.\n")); 727 exit(0); 728 } 729 730 static void 731 usage(void) 732 { 733 (void) fprintf(stderr, gettext( 734 "Usage: %s [options]\n" 735 "Options:\n" 736 " -b bits Number of bits in the key to create.\n" 737 " -c Change comment in private and public key files.\n" 738 " -e Convert OpenSSH to IETF SECSH key file.\n" 739 " -f filename Filename of the key file.\n" 740 " -i Convert IETF SECSH to OpenSSH key file.\n" 741 " -l Show fingerprint of key file.\n" 742 " -p Change passphrase of private key file.\n" 743 " -q Quiet.\n" 744 " -y Read private key file and print public key.\n" 745 " -t type Specify type of key to create.\n" 746 " -B Show bubblebabble digest of key file.\n" 747 " -C comment Provide new comment.\n" 748 " -N phrase Provide new passphrase.\n" 749 " -P phrase Provide old passphrase.\n" 750 #ifdef SMARTCARD 751 " -D reader Download public key from smartcard.\n" 752 " -U reader Upload private key to smartcard.\n" 753 #endif /* SMARTCARD */ 754 ), __progname); 755 756 exit(1); 757 } 758 759 /* 760 * Main program for key management. 761 */ 762 int 763 main(int ac, char **av) 764 { 765 char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; 766 char *reader_id = NULL; 767 Key *private, *public; 768 struct passwd *pw; 769 struct stat st; 770 int opt, type, fd; 771 #ifdef SMARTCARD 772 int download = 0; 773 #endif /* SMARTCARD */ 774 FILE *f; 775 776 extern int optind; 777 extern char *optarg; 778 779 __progname = get_progname(av[0]); 780 781 (void) g11n_setlocale(LC_ALL, ""); 782 783 SSLeay_add_all_algorithms(); 784 init_rng(); 785 seed_rng(); 786 787 /* we need this for the home * directory. */ 788 pw = getpwuid(getuid()); 789 if (!pw) { 790 (void) printf(gettext("You don't exist, go away!\n")); 791 exit(1); 792 } 793 if (gethostname(hostname, sizeof(hostname)) < 0) { 794 perror("gethostname"); 795 exit(1); 796 } 797 798 #ifdef SMARTCARD 799 #define GETOPT_ARGS "deiqpclBRxXyb:f:t:U:D:P:N:C:" 800 #else 801 #define GETOPT_ARGS "deiqpclBRxXyb:f:t:P:N:C:" 802 #endif /* SMARTCARD */ 803 while ((opt = getopt(ac, av, GETOPT_ARGS)) != -1) { 804 switch (opt) { 805 case 'b': 806 bits = atoi(optarg); 807 if (bits < 512 || bits > 32768) { 808 (void) printf(gettext("Bits has bad value.\n")); 809 exit(1); 810 } 811 break; 812 case 'l': 813 print_fingerprint = 1; 814 break; 815 case 'B': 816 print_bubblebabble = 1; 817 break; 818 case 'p': 819 change_passphrase = 1; 820 break; 821 case 'c': 822 change_comment = 1; 823 break; 824 case 'f': 825 (void) strlcpy(identity_file, optarg, sizeof(identity_file)); 826 have_identity = 1; 827 break; 828 case 'P': 829 identity_passphrase = optarg; 830 break; 831 case 'N': 832 identity_new_passphrase = optarg; 833 break; 834 case 'C': 835 identity_comment = optarg; 836 break; 837 case 'q': 838 quiet = 1; 839 break; 840 case 'R': 841 /* unused */ 842 exit(0); 843 break; 844 case 'e': 845 case 'x': 846 /* export key */ 847 convert_to_ssh2 = 1; 848 break; 849 case 'i': 850 case 'X': 851 /* import key */ 852 convert_from_ssh2 = 1; 853 break; 854 case 'y': 855 print_public = 1; 856 break; 857 case 'd': 858 key_type_name = "dsa"; 859 break; 860 case 't': 861 key_type_name = optarg; 862 break; 863 #ifdef SMARTCARD 864 case 'D': 865 download = 1; 866 case 'U': 867 reader_id = optarg; 868 break; 869 #endif 870 case '?': 871 default: 872 usage(); 873 } 874 } 875 if (optind < ac) { 876 (void) printf(gettext("Too many arguments.\n")); 877 usage(); 878 } 879 if (change_passphrase && change_comment) { 880 (void) printf(gettext("Can only have one of -p and -c.\n")); 881 usage(); 882 } 883 if (print_fingerprint || print_bubblebabble) 884 do_fingerprint(pw); 885 if (change_passphrase) 886 do_change_passphrase(pw); 887 if (change_comment) 888 do_change_comment(pw); 889 if (convert_to_ssh2) 890 do_convert_to_ssh2(pw); 891 if (convert_from_ssh2) 892 do_convert_from_ssh2(pw); 893 if (print_public) 894 do_print_public(pw); 895 if (reader_id != NULL) { 896 #ifdef SMARTCARD 897 if (download) 898 do_download(pw, reader_id); 899 else 900 do_upload(pw, reader_id); 901 #else /* SMARTCARD */ 902 fatal("no support for smartcards."); 903 #endif /* SMARTCARD */ 904 } 905 906 arc4random_stir(); 907 908 if (key_type_name == NULL) { 909 (void) printf(gettext("You must specify a key type (-t).\n")); 910 usage(); 911 } 912 type = key_type_from_name(key_type_name); 913 if (type == KEY_UNSPEC) { 914 (void) fprintf(stderr, gettext("unknown key type %s\n"), 915 key_type_name); 916 exit(1); 917 } 918 if (!quiet) 919 (void) printf(gettext("Generating public/private %s key pair.\n"), 920 key_type_name); 921 private = key_generate(type, bits); 922 if (private == NULL) { 923 (void) fprintf(stderr, gettext("key_generate failed")); 924 exit(1); 925 } 926 public = key_from_private(private); 927 928 if (!have_identity) 929 ask_filename(pw, gettext("Enter file in which to save the key")); 930 931 /* Create ~/.ssh directory if it doesn\'t already exist. */ 932 (void) snprintf(dotsshdir, sizeof dotsshdir, "%s/%s", pw->pw_dir, _PATH_SSH_USER_DIR); 933 if (strstr(identity_file, dotsshdir) != NULL && 934 stat(dotsshdir, &st) < 0) { 935 if (mkdir(dotsshdir, 0700) < 0) 936 error("Could not create directory '%s'.", dotsshdir); 937 else if (!quiet) 938 (void) printf(gettext("Created directory '%s'.\n"), dotsshdir); 939 } 940 /* If the file already exists, ask the user to confirm. */ 941 if (stat(identity_file, &st) >= 0) { 942 char yesno[128]; 943 (void) printf(gettext("%s already exists.\n"), identity_file); 944 (void) printf(gettext("Overwrite (%s/%s)? "), 945 nl_langinfo(YESSTR), nl_langinfo(NOSTR)); 946 (void) fflush(stdout); 947 if (fgets(yesno, sizeof(yesno), stdin) == NULL) 948 exit(1); 949 if (strcasecmp(yesno, nl_langinfo(YESSTR)) != 0) 950 exit(1); 951 } 952 /* Ask for a passphrase (twice). */ 953 if (identity_passphrase) 954 passphrase1 = xstrdup(identity_passphrase); 955 else if (identity_new_passphrase) 956 passphrase1 = xstrdup(identity_new_passphrase); 957 else { 958 passphrase_again: 959 passphrase1 = 960 read_passphrase(gettext("Enter passphrase (empty " 961 "for no passphrase): "), RP_ALLOW_STDIN); 962 passphrase2 = read_passphrase(gettext("Enter same " 963 "passphrase again: "), RP_ALLOW_STDIN); 964 if (strcmp(passphrase1, passphrase2) != 0) { 965 /* 966 * The passphrases do not match. Clear them and 967 * retry. 968 */ 969 (void) memset(passphrase1, 0, strlen(passphrase1)); 970 (void) memset(passphrase2, 0, strlen(passphrase2)); 971 xfree(passphrase1); 972 xfree(passphrase2); 973 (void) printf(gettext("Passphrases do not match. Try " 974 "again.\n")); 975 goto passphrase_again; 976 } 977 /* Clear the other copy of the passphrase. */ 978 (void) memset(passphrase2, 0, strlen(passphrase2)); 979 xfree(passphrase2); 980 } 981 982 if (identity_comment) { 983 (void) strlcpy(comment, identity_comment, sizeof(comment)); 984 } else { 985 /* Create default commend field for the passphrase. */ 986 (void) snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, hostname); 987 } 988 989 /* Save the key with the given passphrase and comment. */ 990 if (!key_save_private(private, identity_file, passphrase1, comment)) { 991 (void) printf(gettext("Saving the key failed: %s.\n"), identity_file); 992 (void) memset(passphrase1, 0, strlen(passphrase1)); 993 xfree(passphrase1); 994 exit(1); 995 } 996 /* Clear the passphrase. */ 997 (void) memset(passphrase1, 0, strlen(passphrase1)); 998 xfree(passphrase1); 999 1000 /* Clear the private key and the random number generator. */ 1001 key_free(private); 1002 arc4random_stir(); 1003 1004 if (!quiet) 1005 (void) printf(gettext("Your identification has been saved in %s.\n"), 1006 identity_file); 1007 1008 (void) strlcat(identity_file, ".pub", sizeof(identity_file)); 1009 fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644); 1010 if (fd == -1) { 1011 (void) printf(gettext("Could not save your public key in %s\n"), 1012 identity_file); 1013 exit(1); 1014 } 1015 f = fdopen(fd, "w"); 1016 if (f == NULL) { 1017 (void) printf(gettext("fdopen %s failed"), identity_file); 1018 exit(1); 1019 } 1020 if (!key_write(public, f)) 1021 (void) fprintf(stderr, gettext("write key failed")); 1022 (void) fprintf(f, " %s\n", comment); 1023 (void) fclose(f); 1024 1025 if (!quiet) { 1026 char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX); 1027 (void) printf(gettext("Your public key has been saved in %s.\n"), 1028 identity_file); 1029 (void) printf(gettext("The key fingerprint is:\n")); 1030 (void) printf("%s %s\n", fp, comment); 1031 xfree(fp); 1032 } 1033 1034 key_free(public); 1035 return(0); 1036 /* NOTREACHED */ 1037 } 1038