summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--ssh-keygen.143
-rw-r--r--ssh-keygen.c228
-rw-r--r--ssh_config.55
4 files changed, 268 insertions, 14 deletions
diff --git a/ChangeLog b/ChangeLog
index fd3076220..762f8dce4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -36,6 +36,10 @@
36 - djm@cvs.openbsd.org 2005/03/01 10:41:28 36 - djm@cvs.openbsd.org 2005/03/01 10:41:28
37 [ssh-keyscan.1 ssh-keyscan.c] 37 [ssh-keyscan.1 ssh-keyscan.c]
38 option to hash hostnames output by ssh-keyscan; ok markus@ deraadt@ 38 option to hash hostnames output by ssh-keyscan; ok markus@ deraadt@
39 - djm@cvs.openbsd.org 2005/03/01 10:42:49
40 [ssh-keygen.1 ssh-keygen.c ssh_config.5]
41 add tools for managing known_hosts files with hashed hostnames, including
42 hashing existing files and deleting hosts by name; ok markus@ deraadt@
39 43
4020050226 4420050226
41 - (dtucker) [openbsd-compat/bsd-openpty.c openbsd-compat/inet_ntop.c] 45 - (dtucker) [openbsd-compat/bsd-openpty.c openbsd-compat/inet_ntop.c]
@@ -2212,4 +2216,4 @@
2212 - (djm) Trim deprecated options from INSTALL. Mention UsePAM 2216 - (djm) Trim deprecated options from INSTALL. Mention UsePAM
2213 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu 2217 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
2214 2218
2215$Id: ChangeLog,v 1.3674 2005/03/01 10:48:03 djm Exp $ 2219$Id: ChangeLog,v 1.3675 2005/03/01 10:48:35 djm Exp $
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index c0f24dcd0..f4c5ebcb8 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-keygen.1,v 1.63 2004/08/13 00:01:43 jmc Exp $ 1.\" $OpenBSD: ssh-keygen.1,v 1.64 2005/03/01 10:42:49 djm Exp $
2.\" 2.\"
3.\" -*- nroff -*- 3.\" -*- nroff -*-
4.\" 4.\"
@@ -81,6 +81,15 @@
81.Nm ssh-keygen 81.Nm ssh-keygen
82.Fl D Ar reader 82.Fl D Ar reader
83.Nm ssh-keygen 83.Nm ssh-keygen
84.Fl F Ar hostname
85.Op Fl f Ar known_hosts_file
86.Nm ssh-keygen
87.Fl H
88.Op Fl f Ar known_hosts_file
89.Nm ssh-keygen
90.Fl R Ar hostname
91.Op Fl f Ar known_hosts_file
92.Nm ssh-keygen
84.Fl U Ar reader 93.Fl U Ar reader
85.Op Fl f Ar input_keyfile 94.Op Fl f Ar input_keyfile
86.Nm ssh-keygen 95.Nm ssh-keygen
@@ -243,6 +252,38 @@ Provides the new comment.
243.It Fl D Ar reader 252.It Fl D Ar reader
244Download the RSA public key stored in the smartcard in 253Download the RSA public key stored in the smartcard in
245.Ar reader . 254.Ar reader .
255.It Fl F Ar hostname
256Search for the specified
257.Ar hostname
258in a
259.Pa known_hosts
260file, listing any occurances found.
261This option is useful to find hashed host names or addresses and may also be
262used in conjunction with the
263.Fl H
264option to print found keys in a hashed format.
265.It Fl H
266Hash a
267.Pa known_hosts
268file, printing the result to standard output.
269This replaces all hostnames and addresses with hashed representations.
270These hashes may be used normally by
271.Nm ssh
272and
273.Nm sshd ,
274but they do not reveal identifying information should the file's contents
275be disclosed.
276This option will not modify existing hashed hostnames and is therefore safe
277to use on files that mix hashed and non-hashed names.
278.It Fl R Ar hostname
279Removes all keys belonging to
280.Ar hostname
281from a
282.Pa known_hosts
283file.
284This option is useful to delete hashed hosts (see the
285.Fl H
286option above).
246.It Fl G Ar output_file 287.It Fl G Ar output_file
247Generate candidate primes for DH-GEX. 288Generate candidate primes for DH-GEX.
248These primes must be screened for 289These primes must be screened for
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 7ed62a30c..00ddb90c8 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -12,7 +12,7 @@
12 */ 12 */
13 13
14#include "includes.h" 14#include "includes.h"
15RCSID("$OpenBSD: ssh-keygen.c,v 1.118 2004/12/23 17:38:07 markus Exp $"); 15RCSID("$OpenBSD: ssh-keygen.c,v 1.119 2005/03/01 10:42:49 djm Exp $");
16 16
17#include <openssl/evp.h> 17#include <openssl/evp.h>
18#include <openssl/pem.h> 18#include <openssl/pem.h>
@@ -27,6 +27,8 @@ RCSID("$OpenBSD: ssh-keygen.c,v 1.118 2004/12/23 17:38:07 markus Exp $");
27#include "pathnames.h" 27#include "pathnames.h"
28#include "log.h" 28#include "log.h"
29#include "misc.h" 29#include "misc.h"
30#include "match.h"
31#include "hostfile.h"
30 32
31#ifdef SMARTCARD 33#ifdef SMARTCARD
32#include "scard.h" 34#include "scard.h"
@@ -50,6 +52,13 @@ int change_comment = 0;
50 52
51int quiet = 0; 53int quiet = 0;
52 54
55/* Flag indicating that we want to hash a known_hosts file */
56int hash_hosts = 0;
57/* Flag indicating that we want lookup a host in known_hosts file */
58int find_host = 0;
59/* Flag indicating that we want to delete a host from a known_hosts file */
60int delete_host = 0;
61
53/* Flag indicating that we just want to see the key fingerprint */ 62/* Flag indicating that we just want to see the key fingerprint */
54int print_fingerprint = 0; 63int print_fingerprint = 0;
55int print_bubblebabble = 0; 64int print_bubblebabble = 0;
@@ -541,6 +550,194 @@ do_fingerprint(struct passwd *pw)
541 exit(0); 550 exit(0);
542} 551}
543 552
553static void
554print_host(FILE *f, char *name, Key *public, int hash)
555{
556 if (hash && (name = host_hash(name, NULL, 0)) == NULL)
557 fatal("hash_host failed");
558 fprintf(f, "%s ", name);
559 if (!key_write(public, f))
560 fatal("key_write failed");
561 fprintf(f, "\n");
562}
563
564static void
565do_known_hosts(struct passwd *pw, const char *name)
566{
567 FILE *in, *out = stdout;
568 Key *public;
569 char *cp, *cp2, *kp, *kp2;
570 char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
571 int c, i, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
572
573 if (!have_identity) {
574 cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
575 if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
576 sizeof(identity_file))
577 fatal("Specified known hosts path too long");
578 xfree(cp);
579 have_identity = 1;
580 }
581 if ((in = fopen(identity_file, "r")) == NULL)
582 fatal("fopen: %s", strerror(errno));
583
584 /*
585 * Find hosts goes to stdout, hash and deletions happen in-place
586 * A corner case is ssh-keygen -HF foo, which should go to stdout
587 */
588 if (!find_host && (hash_hosts || delete_host)) {
589 if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
590 strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
591 strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
592 strlcat(old, ".old", sizeof(old)) >= sizeof(old))
593 fatal("known_hosts path too long");
594 umask(077);
595 if ((c = mkstemp(tmp)) == -1)
596 fatal("mkstemp: %s", strerror(errno));
597 if ((out = fdopen(c, "w")) == NULL) {
598 c = errno;
599 unlink(tmp);
600 fatal("fdopen: %s", strerror(c));
601 }
602 inplace = 1;
603 }
604
605 while (fgets(line, sizeof(line), in)) {
606 num++;
607 i = strlen(line) - 1;
608 if (line[i] != '\n') {
609 error("line %d too long: %.40s...", num, line);
610 skip = 1;
611 invalid = 1;
612 continue;
613 }
614 if (skip) {
615 skip = 0;
616 continue;
617 }
618 line[i] = '\0';
619
620 /* Skip leading whitespace, empty and comment lines. */
621 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
622 ;
623 if (!*cp || *cp == '\n' || *cp == '#') {
624 if (inplace)
625 fprintf(out, "%s\n", cp);
626 continue;
627 }
628 /* Find the end of the host name portion. */
629 for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
630 ;
631 if (*kp == '\0' || *(kp + 1) == '\0') {
632 error("line %d missing key: %.40s...",
633 num, line);
634 invalid = 1;
635 continue;
636 }
637 *kp++ = '\0';
638 kp2 = kp;
639
640 public = key_new(KEY_RSA1);
641 if (key_read(public, &kp) != 1) {
642 kp = kp2;
643 key_free(public);
644 public = key_new(KEY_UNSPEC);
645 if (key_read(public, &kp) != 1) {
646 error("line %d invalid key: %.40s...",
647 num, line);
648 key_free(public);
649 invalid = 1;
650 continue;
651 }
652 }
653
654 if (*cp == HASH_DELIM) {
655 if (find_host || delete_host) {
656 cp2 = host_hash(name, cp, strlen(cp));
657 if (cp2 == NULL) {
658 error("line %d: invalid hashed "
659 "name: %.64s...", num, line);
660 invalid = 1;
661 continue;
662 }
663 c = (strcmp(cp2, cp) == 0);
664 if (find_host && c) {
665 printf("# Host %s found: "
666 "line %d type %s\n", name,
667 num, key_type(public));
668 print_host(out, cp, public, 0);
669 }
670 if (delete_host && !c)
671 print_host(out, cp, public, 0);
672 } else if (hash_hosts)
673 print_host(out, cp, public, 0);
674 } else {
675 if (find_host || delete_host) {
676 c = (match_hostname(name, cp,
677 strlen(cp)) == 1);
678 if (find_host && c) {
679 printf("# Host %s found: "
680 "line %d type %s\n", name,
681 num, key_type(public));
682 print_host(out, cp, public, hash_hosts);
683 }
684 if (delete_host && !c)
685 print_host(out, cp, public, 0);
686 } else if (hash_hosts) {
687 for(cp2 = strsep(&cp, ",");
688 cp2 != NULL && *cp2 != '\0';
689 cp2 = strsep(&cp, ","))
690 print_host(out, cp2, public, 1);
691 has_unhashed = 1;
692 }
693 }
694 key_free(public);
695 }
696 fclose(in);
697
698 if (invalid) {
699 fprintf(stderr, "%s is not a valid known_host file.\n",
700 identity_file);
701 if (inplace) {
702 fprintf(stderr, "Not replacing existing known_hosts "
703 "file beacuse of errors");
704 fclose(out);
705 unlink(tmp);
706 }
707 exit(1);
708 }
709
710 if (inplace) {
711 fclose(out);
712
713 /* Backup existing file */
714 if (unlink(old) == -1 && errno != ENOENT)
715 fatal("unlink %.100s: %s", old, strerror(errno));
716 if (link(identity_file, old) == -1)
717 fatal("link %.100s to %.100s: %s", identity_file, old,
718 strerror(errno));
719 /* Move new one into place */
720 if (rename(tmp, identity_file) == -1) {
721 error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
722 strerror(errno));
723 unlink(tmp);
724 unlink(old);
725 exit(1);
726 }
727
728 fprintf(stderr, "%s updated.\n", identity_file);
729 fprintf(stderr, "Original contents retained as %s\n", old);
730 if (has_unhashed) {
731 fprintf(stderr, "WARNING: %s contains unhashed "
732 "entries\n", old);
733 fprintf(stderr, "Delete this file to ensure privacy "
734 "of hostnames\n");
735 }
736 }
737
738 exit(0);
739}
740
544/* 741/*
545 * Perform changing a passphrase. The argument is the passwd structure 742 * Perform changing a passphrase. The argument is the passwd structure
546 * for the current user. 743 * for the current user.
@@ -767,6 +964,8 @@ usage(void)
767 fprintf(stderr, " -y Read private key file and print public key.\n"); 964 fprintf(stderr, " -y Read private key file and print public key.\n");
768 fprintf(stderr, " -t type Specify type of key to create.\n"); 965 fprintf(stderr, " -t type Specify type of key to create.\n");
769 fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); 966 fprintf(stderr, " -B Show bubblebabble digest of key file.\n");
967 fprintf(stderr, " -H Hash names in known_hosts file\n");
968 fprintf(stderr, " -F hostname Find hostname in known hosts file\n");
770 fprintf(stderr, " -C comment Provide new comment.\n"); 969 fprintf(stderr, " -C comment Provide new comment.\n");
771 fprintf(stderr, " -N phrase Provide new passphrase.\n"); 970 fprintf(stderr, " -N phrase Provide new passphrase.\n");
772 fprintf(stderr, " -P phrase Provide old passphrase.\n"); 971 fprintf(stderr, " -P phrase Provide old passphrase.\n");
@@ -790,7 +989,7 @@ main(int ac, char **av)
790{ 989{
791 char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; 990 char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
792 char out_file[MAXPATHLEN], *reader_id = NULL; 991 char out_file[MAXPATHLEN], *reader_id = NULL;
793 char *resource_record_hostname = NULL; 992 char *rr_hostname = NULL;
794 Key *private, *public; 993 Key *private, *public;
795 struct passwd *pw; 994 struct passwd *pw;
796 struct stat st; 995 struct stat st;
@@ -824,7 +1023,7 @@ main(int ac, char **av)
824 } 1023 }
825 1024
826 while ((opt = getopt(ac, av, 1025 while ((opt = getopt(ac, av,
827 "degiqpclBRvxXyb:f:t:U:D:P:N:C:r:g:T:G:M:S:a:W:")) != -1) { 1026 "degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
828 switch (opt) { 1027 switch (opt) {
829 case 'b': 1028 case 'b':
830 bits = atoi(optarg); 1029 bits = atoi(optarg);
@@ -833,6 +1032,17 @@ main(int ac, char **av)
833 exit(1); 1032 exit(1);
834 } 1033 }
835 break; 1034 break;
1035 case 'F':
1036 find_host = 1;
1037 rr_hostname = optarg;
1038 break;
1039 case 'H':
1040 hash_hosts = 1;
1041 break;
1042 case 'R':
1043 delete_host = 1;
1044 rr_hostname = optarg;
1045 break;
836 case 'l': 1046 case 'l':
837 print_fingerprint = 1; 1047 print_fingerprint = 1;
838 break; 1048 break;
@@ -864,10 +1074,6 @@ main(int ac, char **av)
864 case 'q': 1074 case 'q':
865 quiet = 1; 1075 quiet = 1;
866 break; 1076 break;
867 case 'R':
868 /* unused */
869 exit(0);
870 break;
871 case 'e': 1077 case 'e':
872 case 'x': 1078 case 'x':
873 /* export key */ 1079 /* export key */
@@ -902,7 +1108,7 @@ main(int ac, char **av)
902 } 1108 }
903 break; 1109 break;
904 case 'r': 1110 case 'r':
905 resource_record_hostname = optarg; 1111 rr_hostname = optarg;
906 break; 1112 break;
907 case 'W': 1113 case 'W':
908 generator_wanted = atoi(optarg); 1114 generator_wanted = atoi(optarg);
@@ -945,6 +1151,8 @@ main(int ac, char **av)
945 printf("Can only have one of -p and -c.\n"); 1151 printf("Can only have one of -p and -c.\n");
946 usage(); 1152 usage();
947 } 1153 }
1154 if (delete_host || hash_hosts || find_host)
1155 do_known_hosts(pw, rr_hostname);
948 if (print_fingerprint || print_bubblebabble) 1156 if (print_fingerprint || print_bubblebabble)
949 do_fingerprint(pw); 1157 do_fingerprint(pw);
950 if (change_passphrase) 1158 if (change_passphrase)
@@ -957,8 +1165,8 @@ main(int ac, char **av)
957 do_convert_from_ssh2(pw); 1165 do_convert_from_ssh2(pw);
958 if (print_public) 1166 if (print_public)
959 do_print_public(pw); 1167 do_print_public(pw);
960 if (resource_record_hostname != NULL) { 1168 if (rr_hostname != NULL) {
961 do_print_resource_record(pw, resource_record_hostname); 1169 do_print_resource_record(pw, rr_hostname);
962 } 1170 }
963 if (reader_id != NULL) { 1171 if (reader_id != NULL) {
964#ifdef SMARTCARD 1172#ifdef SMARTCARD
diff --git a/ssh_config.5 b/ssh_config.5
index 9077acbee..2a85485ec 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -34,7 +34,7 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: ssh_config.5,v 1.44 2005/03/01 10:40:27 djm Exp $ 37.\" $OpenBSD: ssh_config.5,v 1.45 2005/03/01 10:42:49 djm Exp $
38.Dd September 25, 1999 38.Dd September 25, 1999
39.Dt SSH_CONFIG 5 39.Dt SSH_CONFIG 5
40.Os 40.Os
@@ -421,7 +421,8 @@ be disclosed.
421The default is 421The default is
422.Dq no . 422.Dq no .
423Note that hashing of names and addresses will not be retrospectively applied 423Note that hashing of names and addresses will not be retrospectively applied
424to existing known hosts files. 424to existing known hosts files, but these may be manually hashed using
425.Xr ssh-keygen 1 .
425.It Cm HostbasedAuthentication 426.It Cm HostbasedAuthentication
426Specifies whether to try rhosts based authentication with public key 427Specifies whether to try rhosts based authentication with public key
427authentication. 428authentication.