summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2014-12-04 02:24:32 +0000
committerDamien Miller <djm@mindrot.org>2014-12-05 09:29:47 +1100
commit5e39a49930d885aac9c76af3129332b6e772cd75 (patch)
tree0d3613d35ba5478ff9f7889cc1912a70ee3b2e32
parent74de254bb92c684cf53461da97f52d5ba34ded80 (diff)
downloadopenssh-git-5e39a49930d885aac9c76af3129332b6e772cd75.tar.gz
upstream commit
add RevokedHostKeys option for the client Allow textfile or KRL-based revocation of hostkeys.
-rw-r--r--auth.c62
-rw-r--r--auth2-pubkey.c6
-rw-r--r--authfile.c58
-rw-r--r--authfile.h5
-rw-r--r--readconf.c12
-rw-r--r--readconf.h4
-rw-r--r--ssh_config.514
-rw-r--r--sshconnect.c64
8 files changed, 155 insertions, 70 deletions
diff --git a/auth.c b/auth.c
index 5e60682c..348ddc39 100644
--- a/auth.c
+++ b/auth.c
@@ -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)) {
- case 0:
- return 0; /* Not revoked */
- case -2:
- break; /* Not a KRL */
- default:
- goto revoked;
+ 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;
}
-#endif
- debug3("%s: treating %s as a key list", __func__,
- options.revoked_keys_file);
- switch (key_in_file(key, options.revoked_keys_file, 0)) {
+
+ r = sshkey_check_revoked(key, options.revoked_keys_file);
+ switch (r) {
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
+ 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:
+ 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;
}
- fatal("key_in_file returned junk");
+
+ /* Success */
+ r = 0;
+
+ out:
+ free(fp);
+ return r == 0 ? 0 : 1;
}
void
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index f3ca9659..0a3c1dee 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -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);
diff --git a/authfile.c b/authfile.c
index e93d8673..95877e15 100644
--- a/authfile.c
+++ b/authfile.c
@@ -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;
+ }
+}
+
diff --git a/authfile.h b/authfile.h
index 03bc3958..645404e6 100644
--- a/authfile.h
+++ b/authfile.h
@@ -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
diff --git a/readconf.c b/readconf.c
index 922c5745..e0386935 100644
--- a/readconf.c
+++ b/readconf.c
@@ -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);
diff --git a/readconf.h b/readconf.h
index 7b58d01f..49858bff 100644
--- a/readconf.h
+++ b/readconf.h
@@ -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;
diff --git a/ssh_config.5 b/ssh_config.5
index d8f980b6..f0a4b293 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -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.
diff --git a/sshconnect.c b/sshconnect.c
index ac09eae6..f9a59372 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -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;
+
+ 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;
+ }
- fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
- debug("Server host key: %s %s", key_type(host_key), fp);
- free(fp);
+ debug("Server host key: %s %s", sshkey_type(host_key), fp);
- if (key_equal(previous_host_key, host_key)) {
- debug("%s: server host key matches cached key", __func__);
- return 0;
+ 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);