diff options
author | Damien Miller <djm@cvs.openbsd.org> | 2014-12-04 02:24:33 +0000 |
---|---|---|
committer | Damien Miller <djm@cvs.openbsd.org> | 2014-12-04 02:24:33 +0000 |
commit | 39c0875a311e18e682ebe236771ff2e97ae52527 (patch) | |
tree | e0c3d3b765d28b9cb4d9f2d8abc322278039d274 /usr.bin/ssh | |
parent | 3609cf92194384b8a354c3f8004ddf8fa9a33511 (diff) |
add RevokedHostKeys option for the client
Allow textfile or KRL-based revocation of hostkeys.
Diffstat (limited to 'usr.bin/ssh')
-rw-r--r-- | usr.bin/ssh/auth.c | 62 | ||||
-rw-r--r-- | usr.bin/ssh/auth2-pubkey.c | 6 | ||||
-rw-r--r-- | usr.bin/ssh/authfile.c | 58 | ||||
-rw-r--r-- | usr.bin/ssh/authfile.h | 5 | ||||
-rw-r--r-- | usr.bin/ssh/readconf.c | 12 | ||||
-rw-r--r-- | usr.bin/ssh/readconf.h | 4 | ||||
-rw-r--r-- | usr.bin/ssh/ssh_config.5 | 14 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect.c | 64 |
8 files changed, 155 insertions, 70 deletions
diff --git a/usr.bin/ssh/auth.c b/usr.bin/ssh/auth.c index 161b80b3cd1..4f823defbd3 100644 --- a/usr.bin/ssh/auth.c +++ b/usr.bin/ssh/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. * @@ -57,7 +57,8 @@ #endif #include "authfile.h" #include "monitor_wrap.h" -#include "krl.h" +#include "authfile.h" +#include "ssherr.h" #include "compat.h" /* import */ @@ -546,43 +547,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/usr.bin/ssh/auth2-pubkey.c b/usr.bin/ssh/auth2-pubkey.c index c4b05edf853..69a319f7663 100644 --- a/usr.bin/ssh/auth2-pubkey.c +++ b/usr.bin/ssh/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. * @@ -431,8 +431,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/usr.bin/ssh/authfile.c b/usr.bin/ssh/authfile.c index 1775c758c59..0a446a4f64d 100644 --- a/usr.bin/ssh/authfile.c +++ b/usr.bin/ssh/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. * @@ -46,6 +46,7 @@ #include "atomicio.h" #include "sshbuf.h" #include "ssherr.h" +#include "krl.h" #define MAX_KEY_FILE_SIZE (1024 * 1024) @@ -489,11 +490,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]; @@ -504,12 +508,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) { @@ -533,7 +533,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; } @@ -548,3 +550,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/usr.bin/ssh/authfile.h b/usr.bin/ssh/authfile.h index 03bc3958c74..645404e61f9 100644 --- a/usr.bin/ssh/authfile.h +++ b/usr.bin/ssh/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/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c index 7fc9a6534c7..16e83f23179 100644 --- a/usr.bin/ssh/readconf.c +++ b/usr.bin/ssh/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 @@ -143,7 +143,7 @@ typedef enum { oKexAlgorithms, oIPQoS, oRequestTTY, oIgnoreUnknown, oProxyUseFdpass, oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots, oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs, - oStreamLocalBindMask, oStreamLocalBindUnlink, + oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, oIgnoredUnknownOption, oDeprecated, oUnsupported } OpCodes; @@ -258,6 +258,7 @@ static struct { { "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs }, { "streamlocalbindmask", oStreamLocalBindMask }, { "streamlocalbindunlink", oStreamLocalBindUnlink }, + { "revokedhostkeys", oRevokedHostKeys }, { "ignoreunknown", oIgnoreUnknown }, { NULL, oBadOption } @@ -1443,6 +1444,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); @@ -1619,6 +1624,7 @@ initialize_options(Options * options) options->canonicalize_max_dots = -1; options->canonicalize_fallback_local = -1; options->canonicalize_hostname = -1; + options->revoked_host_keys = NULL; } /* @@ -1804,6 +1810,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 */ @@ -2237,6 +2244,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/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h index 7b58d01f39d..49858bff365 100644 --- a/usr.bin/ssh/readconf.h +++ b/usr.bin/ssh/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/usr.bin/ssh/ssh_config.5 b/usr.bin/ssh/ssh_config.5 index d8f980b687b..f0a4b293af3 100644 --- a/usr.bin/ssh/ssh_config.5 +++ b/usr.bin/ssh/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/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c index 69ae94c5f0a..7284ec35410 100644 --- a/usr.bin/ssh/sshconnect.c +++ b/usr.bin/ssh/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 @@ -52,6 +52,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; @@ -1193,16 +1195,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) { @@ -1210,17 +1240,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; @@ -1232,14 +1262,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); |