upstream commit

add RevokedHostKeys option for the client

Allow textfile or KRL-based revocation of hostkeys.
This commit is contained in:
djm@openbsd.org 2014-12-04 02:24:32 +00:00 committed by Damien Miller
parent 74de254bb9
commit 5e39a49930
8 changed files with 155 additions and 70 deletions

62
auth.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth.c,v 1.106 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: auth.c,v 1.107 2014/12/04 02:24:32 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -71,7 +71,8 @@
#endif
#include "authfile.h"
#include "monitor_wrap.h"
#include "krl.h"
#include "authfile.h"
#include "ssherr.h"
#include "compat.h"
/* import */
@ -673,43 +674,38 @@ getpwnamallow(const char *user)
int
auth_key_is_revoked(Key *key)
{
#ifdef WITH_OPENSSL
char *key_fp;
char *fp = NULL;
int r;
if (options.revoked_keys_file == NULL)
return 0;
switch (ssh_krl_file_contains_key(options.revoked_keys_file, key)) {
if ((fp = sshkey_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
error("%s: fingerprint key: %s", __func__, ssh_err(r));
goto out;
}
r = sshkey_check_revoked(key, options.revoked_keys_file);
switch (r) {
case 0:
return 0; /* Not revoked */
case -2:
break; /* Not a KRL */
break; /* not revoked */
case SSH_ERR_KEY_REVOKED:
error("Authentication key %s %s revoked by file %s",
sshkey_type(key), fp, options.revoked_keys_file);
goto out;
default:
goto revoked;
error("Error checking authentication key %s %s in "
"revoked keys file %s: %s", sshkey_type(key), fp,
options.revoked_keys_file, ssh_err(r));
goto out;
}
#endif
debug3("%s: treating %s as a key list", __func__,
options.revoked_keys_file);
switch (key_in_file(key, options.revoked_keys_file, 0)) {
case 0:
/* key not revoked */
return 0;
case -1:
/* Error opening revoked_keys_file: refuse all keys */
error("Revoked keys file is unreadable: refusing public key "
"authentication");
return 1;
#ifdef WITH_OPENSSL
case 1:
revoked:
/* Key revoked */
key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
error("WARNING: authentication attempt with a revoked "
"%s key %s ", key_type(key), key_fp);
free(key_fp);
return 1;
#endif
}
fatal("key_in_file returned junk");
/* Success */
r = 0;
out:
free(fp);
return r == 0 ? 0 : 1;
}
void

View File

@ -1,4 +1,4 @@
/* $OpenBSD: auth2-pubkey.c,v 1.41 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: auth2-pubkey.c,v 1.42 2014/12/04 02:24:32 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
*
@ -434,8 +434,8 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
ca_fp = key_fingerprint(key->cert->signature_key,
SSH_FP_MD5, SSH_FP_HEX);
if (key_in_file(key->cert->signature_key,
options.trusted_user_ca_keys, 1) != 1) {
if (sshkey_in_file(key->cert->signature_key,
options.trusted_user_ca_keys, 1, 0) != 0) {
debug2("%s: CA %s %s is not listed in %s", __func__,
key_type(key->cert->signature_key), ca_fp,
options.trusted_user_ca_keys);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 djm Exp $ */
/* $OpenBSD: authfile.c,v 1.108 2014/12/04 02:24:32 djm Exp $ */
/*
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
*
@ -48,6 +48,7 @@
#include "atomicio.h"
#include "sshbuf.h"
#include "ssherr.h"
#include "krl.h"
#define MAX_KEY_FILE_SIZE (1024 * 1024)
@ -494,11 +495,14 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
/*
* Returns success if the specified "key" is listed in the file "filename",
* SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
* If strict_type is set then the key type must match exactly,
* If "strict_type" is set then the key type must match exactly,
* otherwise a comparison that ignores certficiate data is performed.
* If "check_ca" is set and "key" is a certificate, then its CA key is
* also checked and sshkey_in_file() will return success if either is found.
*/
int
sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
int check_ca)
{
FILE *f;
char line[SSH_MAX_PUBKEY_BYTES];
@ -509,12 +513,8 @@ sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
strict_type ? sshkey_equal : sshkey_equal_public;
if ((f = fopen(filename, "r")) == NULL) {
if (errno == ENOENT)
return SSH_ERR_KEY_NOT_FOUND;
else
return SSH_ERR_SYSTEM_ERROR;
}
if ((f = fopen(filename, "r")) == NULL)
return SSH_ERR_SYSTEM_ERROR;
while (read_keyfile_line(f, filename, line, sizeof(line),
&linenum) != -1) {
@ -538,7 +538,9 @@ sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
}
if ((r = sshkey_read(pub, &cp)) != 0)
goto out;
if (sshkey_compare(key, pub)) {
if (sshkey_compare(key, pub) ||
(check_ca && sshkey_is_cert(key) &&
sshkey_compare(key->cert->signature_key, pub))) {
r = 0;
goto out;
}
@ -553,3 +555,39 @@ sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
return r;
}
/*
* Checks whether the specified key is revoked, returning 0 if not,
* SSH_ERR_KEY_REVOKED if it is or another error code if something
* unexpected happened.
* This will check both the key and, if it is a certificate, its CA key too.
* "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
*/
int
sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
{
int r;
#ifdef WITH_OPENSSL
r = ssh_krl_file_contains_key(revoked_keys_file, key);
/* If this was not a KRL to begin with then continue below */
if (r != SSH_ERR_KRL_BAD_MAGIC)
return r;
#endif
/*
* If the file is not a KRL or we can't handle KRLs then attempt to
* parse the file as a flat list of keys.
*/
switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
case 0:
/* Key found => revoked */
return SSH_ERR_KEY_REVOKED;
case SSH_ERR_KEY_NOT_FOUND:
/* Key not found => not revoked */
return 0;
default:
/* Some other error occurred */
return r;
}
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: authfile.h,v 1.19 2014/07/03 23:18:35 djm Exp $ */
/* $OpenBSD: authfile.h,v 1.20 2014/12/04 02:24:32 djm Exp $ */
/*
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
@ -42,6 +42,7 @@ int sshkey_load_private_type(int, const char *, const char *,
struct sshkey **, char **, int *);
int sshkey_load_private_pem(int, int, const char *, struct sshkey **, char **);
int sshkey_perm_ok(int, const char *);
int sshkey_in_file(struct sshkey *, const char *, int);
int sshkey_in_file(struct sshkey *, const char *, int, int);
int sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file);
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.c,v 1.222 2014/10/24 02:01:20 lteo Exp $ */
/* $OpenBSD: readconf.c,v 1.223 2014/12/04 02:24:32 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -154,7 +154,7 @@ typedef enum {
oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass,
oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
oStreamLocalBindMask, oStreamLocalBindUnlink,
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
@ -269,6 +269,7 @@ static struct {
{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
{ "streamlocalbindmask", oStreamLocalBindMask },
{ "streamlocalbindunlink", oStreamLocalBindUnlink },
{ "revokedhostkeys", oRevokedHostKeys },
{ "ignoreunknown", oIgnoreUnknown },
{ NULL, oBadOption }
@ -1455,6 +1456,10 @@ parse_int:
intptr = &options->fwd_opts.streamlocal_bind_unlink;
goto parse_flag;
case oRevokedHostKeys:
charptr = &options->revoked_host_keys;
goto parse_string;
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@ -1631,6 +1636,7 @@ initialize_options(Options * options)
options->canonicalize_max_dots = -1;
options->canonicalize_fallback_local = -1;
options->canonicalize_hostname = -1;
options->revoked_host_keys = NULL;
}
/*
@ -1818,6 +1824,7 @@ fill_default_options(Options * options)
CLEAR_ON_NONE(options->local_command);
CLEAR_ON_NONE(options->proxy_command);
CLEAR_ON_NONE(options->control_path);
CLEAR_ON_NONE(options->revoked_host_keys);
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */
/* options->host_key_alias should not be set by default */
@ -2251,6 +2258,7 @@ dump_client_config(Options *o, const char *host)
dump_cfg_string(oPreferredAuthentications, o->preferred_authentications);
dump_cfg_string(oProxyCommand, o->proxy_command);
dump_cfg_string(oXAuthLocation, o->xauth_location);
dump_cfg_string(oRevokedHostKeys, o->revoked_host_keys);
dump_cfg_forwards(oDynamicForward, o->num_local_forwards, o->local_forwards);
dump_cfg_forwards(oLocalForward, o->num_local_forwards, o->local_forwards);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: readconf.h,v 1.103 2014/10/08 22:20:25 djm Exp $ */
/* $OpenBSD: readconf.h,v 1.104 2014/12/04 02:24:32 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -144,6 +144,8 @@ typedef struct {
int num_permitted_cnames;
struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS];
char *revoked_host_keys;
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
} Options;

View File

@ -33,8 +33,8 @@
.\" (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.195 2014/11/10 22:25:49 djm Exp $
.Dd $Mdocdate: November 10 2014 $
.\" $OpenBSD: ssh_config.5,v 1.196 2014/12/04 02:24:32 djm Exp $
.Dd $Mdocdate: December 4 2014 $
.Dt SSH_CONFIG 5
.Os
.Sh NAME
@ -1253,6 +1253,16 @@ and
.Fl T
flags for
.Xr ssh 1 .
.It Cm RevokedHostKeys
Specifies revoked host public keys.
Keys listed in this file will be refused for host authentication.
Note that if this file does not exist or is not readable,
then host authentication will be refused for all hosts.
Keys may be specified as a text file, listing one public key per line, or as
an OpenSSH Key Revocation List (KRL) as generated by
.Xr ssh-keygen 1 .
For more information on KRLs, see the KEY REVOCATION LISTS section in
.Xr ssh-keygen 1 .
.It Cm RhostsRSAAuthentication
Specifies whether to try rhosts based authentication with RSA host
authentication.

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect.c,v 1.251 2014/07/15 15:54:14 millert Exp $ */
/* $OpenBSD: sshconnect.c,v 1.252 2014/12/04 02:24:32 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -62,6 +62,8 @@
#include "monitor_fdpass.h"
#include "ssh2.h"
#include "version.h"
#include "authfile.h"
#include "ssherr.h"
char *client_version_string = NULL;
char *server_version_string = NULL;
@ -1219,16 +1221,44 @@ int
verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
{
int r = -1, flags = 0;
char *fp;
Key *plain = NULL;
char *fp = NULL;
struct sshkey *plain = NULL;
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
debug("Server host key: %s %s", key_type(host_key), fp);
free(fp);
if ((fp = sshkey_fingerprint(host_key,
SSH_FP_MD5, SSH_FP_HEX)) == NULL) {
error("%s: fingerprint host key: %s", __func__, ssh_err(r));
r = -1;
goto out;
}
if (key_equal(previous_host_key, host_key)) {
debug("%s: server host key matches cached key", __func__);
return 0;
debug("Server host key: %s %s", sshkey_type(host_key), fp);
if (sshkey_equal(previous_host_key, host_key)) {
debug2("%s: server host key %s %s matches cached key",
__func__, sshkey_type(host_key), fp);
r = 0;
goto out;
}
/* Check in RevokedHostKeys file if specified */
if (options.revoked_host_keys != NULL) {
r = sshkey_check_revoked(host_key, options.revoked_host_keys);
switch (r) {
case 0:
break; /* not revoked */
case SSH_ERR_KEY_REVOKED:
error("Host key %s %s revoked by file %s",
sshkey_type(host_key), fp,
options.revoked_host_keys);
r = -1;
goto out;
default:
error("Error checking host key %s %s in "
"revoked keys file %s: %s", sshkey_type(host_key),
fp, options.revoked_host_keys, ssh_err(r));
r = -1;
goto out;
}
}
if (options.verify_host_key_dns) {
@ -1236,17 +1266,17 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
* XXX certs are not yet supported for DNS, so downgrade
* them and try the plain key.
*/
plain = key_from_private(host_key);
if (key_is_cert(plain))
key_drop_cert(plain);
if ((r = sshkey_from_private(host_key, &plain)) != 0)
goto out;
if (sshkey_is_cert(plain))
sshkey_drop_cert(plain);
if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) {
if (flags & DNS_VERIFY_FOUND) {
if (options.verify_host_key_dns == 1 &&
flags & DNS_VERIFY_MATCH &&
flags & DNS_VERIFY_SECURE) {
key_free(plain);
r = 0;
goto done;
goto out;
}
if (flags & DNS_VERIFY_MATCH) {
matching_host_key_dns = 1;
@ -1258,14 +1288,14 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
}
}
}
key_free(plain);
}
r = check_host_key(host, hostaddr, options.port, host_key, RDRW,
options.user_hostfiles, options.num_user_hostfiles,
options.system_hostfiles, options.num_system_hostfiles);
done:
out:
sshkey_free(plain);
free(fp);
if (r == 0 && host_key != NULL) {
key_free(previous_host_key);
previous_host_key = key_from_private(host_key);