- djm@cvs.openbsd.org 2005/03/01 10:42:49
[ssh-keygen.1 ssh-keygen.c ssh_config.5] add tools for managing known_hosts files with hashed hostnames, including hashing existing files and deleting hosts by name; ok markus@ deraadt@
This commit is contained in:
parent
db7b8171ee
commit
4b42d7f195
|
@ -36,6 +36,10 @@
|
|||
- djm@cvs.openbsd.org 2005/03/01 10:41:28
|
||||
[ssh-keyscan.1 ssh-keyscan.c]
|
||||
option to hash hostnames output by ssh-keyscan; ok markus@ deraadt@
|
||||
- djm@cvs.openbsd.org 2005/03/01 10:42:49
|
||||
[ssh-keygen.1 ssh-keygen.c ssh_config.5]
|
||||
add tools for managing known_hosts files with hashed hostnames, including
|
||||
hashing existing files and deleting hosts by name; ok markus@ deraadt@
|
||||
|
||||
20050226
|
||||
- (dtucker) [openbsd-compat/bsd-openpty.c openbsd-compat/inet_ntop.c]
|
||||
|
@ -2212,4 +2216,4 @@
|
|||
- (djm) Trim deprecated options from INSTALL. Mention UsePAM
|
||||
- (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
|
||||
|
||||
$Id: ChangeLog,v 1.3674 2005/03/01 10:48:03 djm Exp $
|
||||
$Id: ChangeLog,v 1.3675 2005/03/01 10:48:35 djm Exp $
|
||||
|
|
43
ssh-keygen.1
43
ssh-keygen.1
|
@ -1,4 +1,4 @@
|
|||
.\" $OpenBSD: ssh-keygen.1,v 1.63 2004/08/13 00:01:43 jmc Exp $
|
||||
.\" $OpenBSD: ssh-keygen.1,v 1.64 2005/03/01 10:42:49 djm Exp $
|
||||
.\"
|
||||
.\" -*- nroff -*-
|
||||
.\"
|
||||
|
@ -81,6 +81,15 @@
|
|||
.Nm ssh-keygen
|
||||
.Fl D Ar reader
|
||||
.Nm ssh-keygen
|
||||
.Fl F Ar hostname
|
||||
.Op Fl f Ar known_hosts_file
|
||||
.Nm ssh-keygen
|
||||
.Fl H
|
||||
.Op Fl f Ar known_hosts_file
|
||||
.Nm ssh-keygen
|
||||
.Fl R Ar hostname
|
||||
.Op Fl f Ar known_hosts_file
|
||||
.Nm ssh-keygen
|
||||
.Fl U Ar reader
|
||||
.Op Fl f Ar input_keyfile
|
||||
.Nm ssh-keygen
|
||||
|
@ -243,6 +252,38 @@ Provides the new comment.
|
|||
.It Fl D Ar reader
|
||||
Download the RSA public key stored in the smartcard in
|
||||
.Ar reader .
|
||||
.It Fl F Ar hostname
|
||||
Search for the specified
|
||||
.Ar hostname
|
||||
in a
|
||||
.Pa known_hosts
|
||||
file, listing any occurances found.
|
||||
This option is useful to find hashed host names or addresses and may also be
|
||||
used in conjunction with the
|
||||
.Fl H
|
||||
option to print found keys in a hashed format.
|
||||
.It Fl H
|
||||
Hash a
|
||||
.Pa known_hosts
|
||||
file, printing the result to standard output.
|
||||
This replaces all hostnames and addresses with hashed representations.
|
||||
These hashes may be used normally by
|
||||
.Nm ssh
|
||||
and
|
||||
.Nm sshd ,
|
||||
but they do not reveal identifying information should the file's contents
|
||||
be disclosed.
|
||||
This option will not modify existing hashed hostnames and is therefore safe
|
||||
to use on files that mix hashed and non-hashed names.
|
||||
.It Fl R Ar hostname
|
||||
Removes all keys belonging to
|
||||
.Ar hostname
|
||||
from a
|
||||
.Pa known_hosts
|
||||
file.
|
||||
This option is useful to delete hashed hosts (see the
|
||||
.Fl H
|
||||
option above).
|
||||
.It Fl G Ar output_file
|
||||
Generate candidate primes for DH-GEX.
|
||||
These primes must be screened for
|
||||
|
|
228
ssh-keygen.c
228
ssh-keygen.c
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
#include "includes.h"
|
||||
RCSID("$OpenBSD: ssh-keygen.c,v 1.118 2004/12/23 17:38:07 markus Exp $");
|
||||
RCSID("$OpenBSD: ssh-keygen.c,v 1.119 2005/03/01 10:42:49 djm Exp $");
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
|
@ -27,6 +27,8 @@ RCSID("$OpenBSD: ssh-keygen.c,v 1.118 2004/12/23 17:38:07 markus Exp $");
|
|||
#include "pathnames.h"
|
||||
#include "log.h"
|
||||
#include "misc.h"
|
||||
#include "match.h"
|
||||
#include "hostfile.h"
|
||||
|
||||
#ifdef SMARTCARD
|
||||
#include "scard.h"
|
||||
|
@ -50,6 +52,13 @@ int change_comment = 0;
|
|||
|
||||
int quiet = 0;
|
||||
|
||||
/* Flag indicating that we want to hash a known_hosts file */
|
||||
int hash_hosts = 0;
|
||||
/* Flag indicating that we want lookup a host in known_hosts file */
|
||||
int find_host = 0;
|
||||
/* Flag indicating that we want to delete a host from a known_hosts file */
|
||||
int delete_host = 0;
|
||||
|
||||
/* Flag indicating that we just want to see the key fingerprint */
|
||||
int print_fingerprint = 0;
|
||||
int print_bubblebabble = 0;
|
||||
|
@ -541,6 +550,194 @@ do_fingerprint(struct passwd *pw)
|
|||
exit(0);
|
||||
}
|
||||
|
||||
static void
|
||||
print_host(FILE *f, char *name, Key *public, int hash)
|
||||
{
|
||||
if (hash && (name = host_hash(name, NULL, 0)) == NULL)
|
||||
fatal("hash_host failed");
|
||||
fprintf(f, "%s ", name);
|
||||
if (!key_write(public, f))
|
||||
fatal("key_write failed");
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
static void
|
||||
do_known_hosts(struct passwd *pw, const char *name)
|
||||
{
|
||||
FILE *in, *out = stdout;
|
||||
Key *public;
|
||||
char *cp, *cp2, *kp, *kp2;
|
||||
char line[16*1024], tmp[MAXPATHLEN], old[MAXPATHLEN];
|
||||
int c, i, skip = 0, inplace = 0, num = 0, invalid = 0, has_unhashed = 0;
|
||||
|
||||
if (!have_identity) {
|
||||
cp = tilde_expand_filename(_PATH_SSH_USER_HOSTFILE, pw->pw_uid);
|
||||
if (strlcpy(identity_file, cp, sizeof(identity_file)) >=
|
||||
sizeof(identity_file))
|
||||
fatal("Specified known hosts path too long");
|
||||
xfree(cp);
|
||||
have_identity = 1;
|
||||
}
|
||||
if ((in = fopen(identity_file, "r")) == NULL)
|
||||
fatal("fopen: %s", strerror(errno));
|
||||
|
||||
/*
|
||||
* Find hosts goes to stdout, hash and deletions happen in-place
|
||||
* A corner case is ssh-keygen -HF foo, which should go to stdout
|
||||
*/
|
||||
if (!find_host && (hash_hosts || delete_host)) {
|
||||
if (strlcpy(tmp, identity_file, sizeof(tmp)) >= sizeof(tmp) ||
|
||||
strlcat(tmp, ".XXXXXXXXXX", sizeof(tmp)) >= sizeof(tmp) ||
|
||||
strlcpy(old, identity_file, sizeof(old)) >= sizeof(old) ||
|
||||
strlcat(old, ".old", sizeof(old)) >= sizeof(old))
|
||||
fatal("known_hosts path too long");
|
||||
umask(077);
|
||||
if ((c = mkstemp(tmp)) == -1)
|
||||
fatal("mkstemp: %s", strerror(errno));
|
||||
if ((out = fdopen(c, "w")) == NULL) {
|
||||
c = errno;
|
||||
unlink(tmp);
|
||||
fatal("fdopen: %s", strerror(c));
|
||||
}
|
||||
inplace = 1;
|
||||
}
|
||||
|
||||
while (fgets(line, sizeof(line), in)) {
|
||||
num++;
|
||||
i = strlen(line) - 1;
|
||||
if (line[i] != '\n') {
|
||||
error("line %d too long: %.40s...", num, line);
|
||||
skip = 1;
|
||||
invalid = 1;
|
||||
continue;
|
||||
}
|
||||
if (skip) {
|
||||
skip = 0;
|
||||
continue;
|
||||
}
|
||||
line[i] = '\0';
|
||||
|
||||
/* Skip leading whitespace, empty and comment lines. */
|
||||
for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
|
||||
;
|
||||
if (!*cp || *cp == '\n' || *cp == '#') {
|
||||
if (inplace)
|
||||
fprintf(out, "%s\n", cp);
|
||||
continue;
|
||||
}
|
||||
/* Find the end of the host name portion. */
|
||||
for (kp = cp; *kp && *kp != ' ' && *kp != '\t'; kp++)
|
||||
;
|
||||
if (*kp == '\0' || *(kp + 1) == '\0') {
|
||||
error("line %d missing key: %.40s...",
|
||||
num, line);
|
||||
invalid = 1;
|
||||
continue;
|
||||
}
|
||||
*kp++ = '\0';
|
||||
kp2 = kp;
|
||||
|
||||
public = key_new(KEY_RSA1);
|
||||
if (key_read(public, &kp) != 1) {
|
||||
kp = kp2;
|
||||
key_free(public);
|
||||
public = key_new(KEY_UNSPEC);
|
||||
if (key_read(public, &kp) != 1) {
|
||||
error("line %d invalid key: %.40s...",
|
||||
num, line);
|
||||
key_free(public);
|
||||
invalid = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (*cp == HASH_DELIM) {
|
||||
if (find_host || delete_host) {
|
||||
cp2 = host_hash(name, cp, strlen(cp));
|
||||
if (cp2 == NULL) {
|
||||
error("line %d: invalid hashed "
|
||||
"name: %.64s...", num, line);
|
||||
invalid = 1;
|
||||
continue;
|
||||
}
|
||||
c = (strcmp(cp2, cp) == 0);
|
||||
if (find_host && c) {
|
||||
printf("# Host %s found: "
|
||||
"line %d type %s\n", name,
|
||||
num, key_type(public));
|
||||
print_host(out, cp, public, 0);
|
||||
}
|
||||
if (delete_host && !c)
|
||||
print_host(out, cp, public, 0);
|
||||
} else if (hash_hosts)
|
||||
print_host(out, cp, public, 0);
|
||||
} else {
|
||||
if (find_host || delete_host) {
|
||||
c = (match_hostname(name, cp,
|
||||
strlen(cp)) == 1);
|
||||
if (find_host && c) {
|
||||
printf("# Host %s found: "
|
||||
"line %d type %s\n", name,
|
||||
num, key_type(public));
|
||||
print_host(out, cp, public, hash_hosts);
|
||||
}
|
||||
if (delete_host && !c)
|
||||
print_host(out, cp, public, 0);
|
||||
} else if (hash_hosts) {
|
||||
for(cp2 = strsep(&cp, ",");
|
||||
cp2 != NULL && *cp2 != '\0';
|
||||
cp2 = strsep(&cp, ","))
|
||||
print_host(out, cp2, public, 1);
|
||||
has_unhashed = 1;
|
||||
}
|
||||
}
|
||||
key_free(public);
|
||||
}
|
||||
fclose(in);
|
||||
|
||||
if (invalid) {
|
||||
fprintf(stderr, "%s is not a valid known_host file.\n",
|
||||
identity_file);
|
||||
if (inplace) {
|
||||
fprintf(stderr, "Not replacing existing known_hosts "
|
||||
"file beacuse of errors");
|
||||
fclose(out);
|
||||
unlink(tmp);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (inplace) {
|
||||
fclose(out);
|
||||
|
||||
/* Backup existing file */
|
||||
if (unlink(old) == -1 && errno != ENOENT)
|
||||
fatal("unlink %.100s: %s", old, strerror(errno));
|
||||
if (link(identity_file, old) == -1)
|
||||
fatal("link %.100s to %.100s: %s", identity_file, old,
|
||||
strerror(errno));
|
||||
/* Move new one into place */
|
||||
if (rename(tmp, identity_file) == -1) {
|
||||
error("rename\"%s\" to \"%s\": %s", tmp, identity_file,
|
||||
strerror(errno));
|
||||
unlink(tmp);
|
||||
unlink(old);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "%s updated.\n", identity_file);
|
||||
fprintf(stderr, "Original contents retained as %s\n", old);
|
||||
if (has_unhashed) {
|
||||
fprintf(stderr, "WARNING: %s contains unhashed "
|
||||
"entries\n", old);
|
||||
fprintf(stderr, "Delete this file to ensure privacy "
|
||||
"of hostnames\n");
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform changing a passphrase. The argument is the passwd structure
|
||||
* for the current user.
|
||||
|
@ -767,6 +964,8 @@ usage(void)
|
|||
fprintf(stderr, " -y Read private key file and print public key.\n");
|
||||
fprintf(stderr, " -t type Specify type of key to create.\n");
|
||||
fprintf(stderr, " -B Show bubblebabble digest of key file.\n");
|
||||
fprintf(stderr, " -H Hash names in known_hosts file\n");
|
||||
fprintf(stderr, " -F hostname Find hostname in known hosts file\n");
|
||||
fprintf(stderr, " -C comment Provide new comment.\n");
|
||||
fprintf(stderr, " -N phrase Provide new passphrase.\n");
|
||||
fprintf(stderr, " -P phrase Provide old passphrase.\n");
|
||||
|
@ -790,7 +989,7 @@ main(int ac, char **av)
|
|||
{
|
||||
char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
|
||||
char out_file[MAXPATHLEN], *reader_id = NULL;
|
||||
char *resource_record_hostname = NULL;
|
||||
char *rr_hostname = NULL;
|
||||
Key *private, *public;
|
||||
struct passwd *pw;
|
||||
struct stat st;
|
||||
|
@ -824,7 +1023,7 @@ main(int ac, char **av)
|
|||
}
|
||||
|
||||
while ((opt = getopt(ac, av,
|
||||
"degiqpclBRvxXyb:f:t:U:D:P:N:C:r:g:T:G:M:S:a:W:")) != -1) {
|
||||
"degiqpclBHvxXyF:b:f:t:U:D:P:N:C:r:g:R:T:G:M:S:a:W:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'b':
|
||||
bits = atoi(optarg);
|
||||
|
@ -833,6 +1032,17 @@ main(int ac, char **av)
|
|||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
find_host = 1;
|
||||
rr_hostname = optarg;
|
||||
break;
|
||||
case 'H':
|
||||
hash_hosts = 1;
|
||||
break;
|
||||
case 'R':
|
||||
delete_host = 1;
|
||||
rr_hostname = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
print_fingerprint = 1;
|
||||
break;
|
||||
|
@ -864,10 +1074,6 @@ main(int ac, char **av)
|
|||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case 'R':
|
||||
/* unused */
|
||||
exit(0);
|
||||
break;
|
||||
case 'e':
|
||||
case 'x':
|
||||
/* export key */
|
||||
|
@ -902,7 +1108,7 @@ main(int ac, char **av)
|
|||
}
|
||||
break;
|
||||
case 'r':
|
||||
resource_record_hostname = optarg;
|
||||
rr_hostname = optarg;
|
||||
break;
|
||||
case 'W':
|
||||
generator_wanted = atoi(optarg);
|
||||
|
@ -945,6 +1151,8 @@ main(int ac, char **av)
|
|||
printf("Can only have one of -p and -c.\n");
|
||||
usage();
|
||||
}
|
||||
if (delete_host || hash_hosts || find_host)
|
||||
do_known_hosts(pw, rr_hostname);
|
||||
if (print_fingerprint || print_bubblebabble)
|
||||
do_fingerprint(pw);
|
||||
if (change_passphrase)
|
||||
|
@ -957,8 +1165,8 @@ main(int ac, char **av)
|
|||
do_convert_from_ssh2(pw);
|
||||
if (print_public)
|
||||
do_print_public(pw);
|
||||
if (resource_record_hostname != NULL) {
|
||||
do_print_resource_record(pw, resource_record_hostname);
|
||||
if (rr_hostname != NULL) {
|
||||
do_print_resource_record(pw, rr_hostname);
|
||||
}
|
||||
if (reader_id != NULL) {
|
||||
#ifdef SMARTCARD
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $OpenBSD: ssh_config.5,v 1.44 2005/03/01 10:40:27 djm Exp $
|
||||
.\" $OpenBSD: ssh_config.5,v 1.45 2005/03/01 10:42:49 djm Exp $
|
||||
.Dd September 25, 1999
|
||||
.Dt SSH_CONFIG 5
|
||||
.Os
|
||||
|
@ -421,7 +421,8 @@ be disclosed.
|
|||
The default is
|
||||
.Dq no .
|
||||
Note that hashing of names and addresses will not be retrospectively applied
|
||||
to existing known hosts files.
|
||||
to existing known hosts files, but these may be manually hashed using
|
||||
.Xr ssh-keygen 1 .
|
||||
.It Cm HostbasedAuthentication
|
||||
Specifies whether to try rhosts based authentication with public key
|
||||
authentication.
|
||||
|
|
Loading…
Reference in New Issue