diff options
-rw-r--r-- | usr.bin/ssh/auth-rh-rsa.c | 5 | ||||
-rw-r--r-- | usr.bin/ssh/auth-rsa.c | 5 | ||||
-rw-r--r-- | usr.bin/ssh/auth.c | 31 | ||||
-rw-r--r-- | usr.bin/ssh/auth.h | 3 | ||||
-rw-r--r-- | usr.bin/ssh/auth2-hostbased.c | 5 | ||||
-rw-r--r-- | usr.bin/ssh/auth2-pubkey.c | 53 | ||||
-rw-r--r-- | usr.bin/ssh/authfile.c | 64 | ||||
-rw-r--r-- | usr.bin/ssh/authfile.h | 3 | ||||
-rw-r--r-- | usr.bin/ssh/hostfile.c | 102 | ||||
-rw-r--r-- | usr.bin/ssh/hostfile.h | 5 | ||||
-rw-r--r-- | usr.bin/ssh/servconf.c | 19 | ||||
-rw-r--r-- | usr.bin/ssh/servconf.h | 4 | ||||
-rw-r--r-- | usr.bin/ssh/ssh-keygen.c | 4 | ||||
-rw-r--r-- | usr.bin/ssh/ssh.1 | 20 | ||||
-rw-r--r-- | usr.bin/ssh/sshconnect.c | 24 | ||||
-rw-r--r-- | usr.bin/ssh/sshd_config.5 | 25 |
16 files changed, 331 insertions, 41 deletions
diff --git a/usr.bin/ssh/auth-rh-rsa.c b/usr.bin/ssh/auth-rh-rsa.c index c5ac7b20a8f..d233e493a46 100644 --- a/usr.bin/ssh/auth-rh-rsa.c +++ b/usr.bin/ssh/auth-rh-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rh-rsa.c,v 1.42 2006/08/03 03:34:41 deraadt Exp $ */ +/* $OpenBSD: auth-rh-rsa.c,v 1.43 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -42,6 +42,9 @@ auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost, { HostStatus host_status; + if (auth_key_is_revoked(client_host_key)) + return 0; + /* Check if we would accept it using rhosts authentication. */ if (!auth_rhosts(pw, cuser)) return 0; diff --git a/usr.bin/ssh/auth-rsa.c b/usr.bin/ssh/auth-rsa.c index 338ae7d5b68..f136e65961c 100644 --- a/usr.bin/ssh/auth-rsa.c +++ b/usr.bin/ssh/auth-rsa.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth-rsa.c,v 1.73 2008/07/02 12:03:51 dtucker Exp $ */ +/* $OpenBSD: auth-rsa.c,v 1.74 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -91,6 +91,9 @@ auth_rsa_verify_response(Key *key, BIGNUM *challenge, u_char response[16]) MD5_CTX md; int len; + if (auth_key_is_revoked(key)) + return 0; + /* don't allow short keys */ if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) { error("auth_rsa_verify_response: RSA modulus too small: %d < minimum %d bits", diff --git a/usr.bin/ssh/auth.c b/usr.bin/ssh/auth.c index 9a745e19dff..19002a6def1 100644 --- a/usr.bin/ssh/auth.c +++ b/usr.bin/ssh/auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.c,v 1.84 2010/02/09 06:18:46 djm Exp $ */ +/* $OpenBSD: auth.c,v 1.85 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -55,6 +55,7 @@ #ifdef GSSAPI #include "ssh-gss.h" #endif +#include "authfile.h" #include "monitor_wrap.h" /* import */ @@ -464,6 +465,34 @@ getpwnamallow(const char *user) return (NULL); } +/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ +int +auth_key_is_revoked(Key *key) +{ + char *key_fp; + + if (options.revoked_keys_file == NULL) + return 0; + + 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; + case 1: + /* Key revoked */ + key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + error("%s key %s is revoked", key_type(key), key_fp); + xfree(key_fp); + return 1; + } + fatal("key_in_file returned junk"); +} + void auth_debug_add(const char *fmt,...) { diff --git a/usr.bin/ssh/auth.h b/usr.bin/ssh/auth.h index bcadcba159f..d7fbdfba620 100644 --- a/usr.bin/ssh/auth.h +++ b/usr.bin/ssh/auth.h @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.h,v 1.64 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: auth.h,v 1.65 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. @@ -148,6 +148,7 @@ char *authorized_keys_file(struct passwd *); char *authorized_keys_file2(struct passwd *); FILE *auth_openkeyfile(const char *, struct passwd *, int); +int auth_key_is_revoked(Key *); HostStatus check_key_in_hostfiles(struct passwd *, Key *, const char *, diff --git a/usr.bin/ssh/auth2-hostbased.c b/usr.bin/ssh/auth2-hostbased.c index 2c0c375631b..882651cfcc5 100644 --- a/usr.bin/ssh/auth2-hostbased.c +++ b/usr.bin/ssh/auth2-hostbased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth2-hostbased.c,v 1.12 2008/07/17 08:51:07 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.13 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -144,6 +144,9 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, HostStatus host_status; int len; + if (auth_key_is_revoked(key)) + return 0; + resolvedname = get_canonical_hostname(options.use_dns); ipaddr = get_remote_ipaddr(); diff --git a/usr.bin/ssh/auth2-pubkey.c b/usr.bin/ssh/auth2-pubkey.c index 9b90c39e2e0..bd7df66db03 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.20 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: auth2-pubkey.c,v 1.21 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -55,6 +55,7 @@ #endif #include "monitor_wrap.h" #include "misc.h" +#include "authfile.h" /* import */ extern ServerOptions options; @@ -275,6 +276,47 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file) return found_key; } +/* Authenticate a certificate key against TrustedUserCAKeys */ +static int +user_cert_trusted_ca(struct passwd *pw, Key *key) +{ + char *key_fp, *ca_fp; + const char *reason; + int ret = 0; + + if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) + return 0; + + key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + ca_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + + if (key_in_file(key->cert->signature_key, + options.trusted_user_ca_keys, 1) != 1) { + debug2("%s: CA %s %s is not listed in %s", __func__, + key_type(key->cert->signature_key), ca_fp, + options.trusted_user_ca_keys); + goto out; + } + if (key_cert_check_authority(key, 0, 1, pw->pw_name, &reason) != 0) { + error("%s", reason); + auth_debug_add("%s", reason); + goto out; + } + if (auth_cert_constraints(&key->cert->constraints, pw) != 0) + goto out; + + verbose("%s certificate %s allowed by trusted %s key %s", + key_type(key), key_fp, key_type(key->cert->signature_key), ca_fp); + ret = 1; + + out: + if (key_fp != NULL) + xfree(key_fp); + if (ca_fp != NULL) + xfree(ca_fp); + return ret; +} + /* check whether given key is in .ssh/authorized_keys* */ int user_key_allowed(struct passwd *pw, Key *key) @@ -282,6 +324,15 @@ user_key_allowed(struct passwd *pw, Key *key) int success; char *file; + if (auth_key_is_revoked(key)) + return 0; + if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) + return 0; + + success = user_cert_trusted_ca(pw, key); + if (success) + return success; + file = authorized_keys_file(pw); success = user_key_allowed2(pw, key, file); xfree(file); diff --git a/usr.bin/ssh/authfile.c b/usr.bin/ssh/authfile.c index 17ca4e809d8..3726f51042f 100644 --- a/usr.bin/ssh/authfile.c +++ b/usr.bin/ssh/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.79 2010/01/12 00:16:47 dtucker Exp $ */ +/* $OpenBSD: authfile.c,v 1.80 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -680,3 +680,65 @@ key_load_public(const char *filename, char **commentp) key_free(pub); return NULL; } + +/* + * Returns 1 if the specified "key" is listed in the file "filename", + * 0 if the key is not listed or -1 on error. + * If strict_type is set then the key type must match exactly, + * otherwise a comparison that ignores certficiate data is performed. + */ +int +key_in_file(Key *key, const char *filename, int strict_type) +{ + FILE *f; + char line[SSH_MAX_PUBKEY_BYTES]; + char *cp; + u_long linenum = 0; + int ret = 0; + Key *pub; + int (*key_compare)(const Key *, const Key *) = strict_type ? + key_equal : key_equal_public; + + if ((f = fopen(filename, "r")) == NULL) { + if (errno == ENOENT) { + debug("%s: keyfile \"%s\" missing", __func__, filename); + return 0; + } else { + error("%s: could not open keyfile \"%s\": %s", __func__, + filename, strerror(errno)); + return -1; + } + } + + while (read_keyfile_line(f, filename, line, sizeof(line), + &linenum) != -1) { + cp = line; + + /* Skip leading whitespace. */ + for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) + ; + + /* Skip comments and empty lines */ + switch (*cp) { + case '#': + case '\n': + case '\0': + continue; + } + + pub = key_new(KEY_UNSPEC); + if (key_read(pub, &cp) != 1) { + key_free(pub); + continue; + } + if (key_compare(key, pub)) { + ret = 1; + key_free(pub); + break; + } + key_free(pub); + } + fclose(f); + return ret; +} + diff --git a/usr.bin/ssh/authfile.h b/usr.bin/ssh/authfile.h index a6c74934d69..6dfa478e76e 100644 --- a/usr.bin/ssh/authfile.h +++ b/usr.bin/ssh/authfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.h,v 1.13 2006/04/25 08:02:27 dtucker Exp $ */ +/* $OpenBSD: authfile.h,v 1.14 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -22,5 +22,6 @@ Key *key_load_private(const char *, const char *, char **); Key *key_load_private_type(int, const char *, const char *, char **, int *); Key *key_load_private_pem(int, int, const char *, char **); int key_perm_ok(int, const char *); +int key_in_file(Key *, const char *, int); #endif diff --git a/usr.bin/ssh/hostfile.c b/usr.bin/ssh/hostfile.c index ad52439d54b..4ad5557fede 100644 --- a/usr.bin/ssh/hostfile.c +++ b/usr.bin/ssh/hostfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.c,v 1.47 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: hostfile.c,v 1.48 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -180,6 +180,41 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen return 1; } +static enum { MRK_ERROR, MRK_NONE, MRK_REVOKE, MRK_CA } +check_markers(char **cpp) +{ + char marker[32], *sp, *cp = *cpp; + int ret = MRK_NONE; + + while (*cp == '@') { + /* Only one marker is allowed */ + if (ret != MRK_NONE) + return MRK_ERROR; + /* Markers are terminated by whitespace */ + if ((sp = strchr(cp, ' ')) == NULL && + (sp = strchr(cp, '\t')) == NULL) + return MRK_ERROR; + /* Extract marker for comparison */ + if (sp <= cp + 1 || sp >= cp + sizeof(marker)) + return MRK_ERROR; + memcpy(marker, cp, sp - cp); + marker[sp - cp] = '\0'; + if (strcmp(marker, CA_MARKER) == 0) + ret = MRK_CA; + else if (strcmp(marker, REVOKE_MARKER) == 0) + ret = MRK_REVOKE; + else + return MRK_ERROR; + + /* Skip past marker and any whitespace that follows it */ + cp = sp; + for (; *cp == ' ' || *cp == '\t'; cp++) + ; + } + *cpp = cp; + return ret; +} + /* * Checks whether the given host (which must be in all lowercase) is already * in the list of our known hosts. Returns HOST_OK if the host is known and @@ -192,17 +227,21 @@ hostfile_check_key(int bits, const Key *key, const char *host, const char *filen static HostStatus check_host_in_hostfile_by_key_or_type(const char *filename, - const char *host, const Key *key, int keytype, Key *found, int *numret) + const char *host, const Key *key, int keytype, Key *found, + int want_revocation, int *numret) { FILE *f; char line[8192]; - int linenum = 0, want_cert = key_is_cert(key); + int want, have, linenum = 0, want_cert = key_is_cert(key); u_int kbits; char *cp, *cp2, *hashed_host; HostStatus end_return; debug3("check_host_in_hostfile: host %s filename %s", host, filename); + if (want_revocation && (key == NULL || keytype != 0 || found != NULL)) + fatal("%s: invalid arguments", __func__); + /* Open the file containing the list of known hosts. */ f = fopen(filename, "r"); if (!f) @@ -226,21 +265,18 @@ check_host_in_hostfile_by_key_or_type(const char *filename, if (!*cp || *cp == '#' || *cp == '\n') continue; - /* - * Ignore CA keys when looking for raw keys. - * Ignore raw keys when looking for CA keys. - */ - if (strncasecmp(cp, CA_MARKER, sizeof(CA_MARKER) - 1) == 0 && - (cp[sizeof(CA_MARKER) - 1] == ' ' || - cp[sizeof(CA_MARKER) - 1] == '\t')) { - if (want_cert) { - /* Skip the marker and following whitespace */ - cp += sizeof(CA_MARKER); - for (; *cp == ' ' || *cp == '\t'; cp++) - ; - } else - continue; - } else if (want_cert) + if (want_revocation) + want = MRK_REVOKE; + else if (want_cert) + want = MRK_CA; + else + want = MRK_NONE; + + if ((have = check_markers(&cp)) == MRK_ERROR) { + verbose("%s: invalid marker at %s:%d", + __func__, filename, linenum); + continue; + } else if (want != have) continue; /* Find the end of the host name portion. */ @@ -264,6 +300,9 @@ check_host_in_hostfile_by_key_or_type(const char *filename, /* Got a match. Skip host name. */ cp = cp2; + if (want_revocation) + found = key_new(KEY_UNSPEC); + /* * Extract the key from the line. This will skip any leading * whitespace. Ignore badly formatted lines. @@ -286,6 +325,24 @@ check_host_in_hostfile_by_key_or_type(const char *filename, if (!hostfile_check_key(kbits, found, host, filename, linenum)) continue; + if (want_revocation) { + if (key_is_cert(key) && + key_equal_public(key->cert->signature_key, found)) { + verbose("check_host_in_hostfile: revoked CA " + "line %d", linenum); + key_free(found); + return HOST_REVOKED; + } + if (key_equal_public(key, found)) { + verbose("check_host_in_hostfile: revoked key " + "line %d", linenum); + key_free(found); + return HOST_REVOKED; + } + key_free(found); + continue; + } + /* Check if the current key is the same as the given key. */ if (want_cert && key_equal(key->cert->signature_key, found)) { /* Found CA cert for key */ @@ -322,8 +379,11 @@ check_host_in_hostfile(const char *filename, const char *host, const Key *key, { if (key == NULL) fatal("no key to look up"); - return (check_host_in_hostfile_by_key_or_type(filename, host, key, 0, - found, numret)); + if (check_host_in_hostfile_by_key_or_type(filename, host, + key, 0, NULL, 1, NULL) == HOST_REVOKED) + return HOST_REVOKED; + return check_host_in_hostfile_by_key_or_type(filename, host, key, 0, + found, 0, numret); } int @@ -331,7 +391,7 @@ lookup_key_in_hostfile_by_type(const char *filename, const char *host, int keytype, Key *found, int *numret) { return (check_host_in_hostfile_by_key_or_type(filename, host, NULL, - keytype, found, numret) == HOST_FOUND); + keytype, found, 0, numret) == HOST_FOUND); } /* diff --git a/usr.bin/ssh/hostfile.h b/usr.bin/ssh/hostfile.h index ebac1e4f141..1d460c1a915 100644 --- a/usr.bin/ssh/hostfile.h +++ b/usr.bin/ssh/hostfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hostfile.h,v 1.17 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: hostfile.h,v 1.18 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -15,7 +15,7 @@ #define HOSTFILE_H typedef enum { - HOST_OK, HOST_NEW, HOST_CHANGED, HOST_FOUND + HOST_OK, HOST_NEW, HOST_CHANGED, HOST_REVOKED, HOST_FOUND } HostStatus; int hostfile_read_key(char **, u_int *, Key *); @@ -29,6 +29,7 @@ int lookup_key_in_hostfile_by_type(const char *, const char *, #define HASH_DELIM '|' #define CA_MARKER "@cert-authority" +#define REVOKE_MARKER "@revoked" char *host_hash(const char *, const char *, u_int); diff --git a/usr.bin/ssh/servconf.c b/usr.bin/ssh/servconf.c index 941990f7fcc..4b2870ae063 100644 --- a/usr.bin/ssh/servconf.c +++ b/usr.bin/ssh/servconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.c,v 1.203 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: servconf.c,v 1.204 2010/03/04 10:36:03 djm Exp $ */ /* * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * All rights reserved @@ -122,6 +122,8 @@ initialize_server_options(ServerOptions *options) options->adm_forced_command = NULL; options->chroot_directory = NULL; options->zero_knowledge_password_authentication = -1; + options->revoked_keys_file = NULL; + options->trusted_user_ca_keys = NULL; } void @@ -283,6 +285,7 @@ typedef enum { sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, sZeroKnowledgePasswordAuthentication, sHostCertificate, + sRevokedKeys, sTrustedUserCAKeys, sDeprecated, sUnsupported } ServerOpCodes; @@ -390,6 +393,8 @@ static struct { { "forcecommand", sForceCommand, SSHCFG_ALL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, + { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, + { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, { NULL, sBadOption, 0 } }; @@ -1280,6 +1285,14 @@ process_server_config_line(ServerOptions *options, char *line, *charptr = xstrdup(arg); break; + case sTrustedUserCAKeys: + charptr = &options->trusted_user_ca_keys; + goto parse_filename; + + case sRevokedKeys: + charptr = &options->revoked_keys_file; + goto parse_filename; + case sDeprecated: logit("%s line %d: Deprecated option %s", filename, linenum, arg); @@ -1394,6 +1407,8 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) return; M_CP_STROPT(adm_forced_command); M_CP_STROPT(chroot_directory); + M_CP_STROPT(trusted_user_ca_keys); + M_CP_STROPT(revoked_keys_file); } #undef M_CP_INTOPT @@ -1608,6 +1623,8 @@ dump_config(ServerOptions *o) dump_cfg_string(sAuthorizedKeysFile2, o->authorized_keys_file2); dump_cfg_string(sForceCommand, o->adm_forced_command); dump_cfg_string(sChrootDirectory, o->chroot_directory); + dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); + dump_cfg_string(sRevokedKeys, o->revoked_keys_file); /* string arguments requiring a lookup */ dump_cfg_string(sLogLevel, log_level_name(o->log_level)); diff --git a/usr.bin/ssh/servconf.h b/usr.bin/ssh/servconf.h index 137da2ac2f2..7c53dec6de2 100644 --- a/usr.bin/ssh/servconf.h +++ b/usr.bin/ssh/servconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: servconf.h,v 1.91 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: servconf.h,v 1.92 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> @@ -152,6 +152,8 @@ typedef struct { int num_permitted_opens; char *chroot_directory; + char *revoked_keys_file; + char *trusted_user_ca_keys; } ServerOptions; void initialize_server_options(ServerOptions *); diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c index a6ffd83a50d..ce63cc33373 100644 --- a/usr.bin/ssh/ssh-keygen.c +++ b/usr.bin/ssh/ssh-keygen.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keygen.c,v 1.180 2010/03/02 23:20:57 djm Exp $ */ +/* $OpenBSD: ssh-keygen.c,v 1.181 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -1292,7 +1292,7 @@ parse_cert_times(char *timespec) from = xstrdup(timespec); to = strchr(from, ':'); if (to == NULL || from == to || *(to + 1) == '\0') - fatal("Invalid certificate life specification %s", optarg); + fatal("Invalid certificate life specification %s", timespec); *to++ = '\0'; if (*from == '-' || *from == '+') diff --git a/usr.bin/ssh/ssh.1 b/usr.bin/ssh/ssh.1 index 183dc277fc5..e8a4e5953a5 100644 --- a/usr.bin/ssh/ssh.1 +++ b/usr.bin/ssh/ssh.1 @@ -34,8 +34,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.1,v 1.296 2010/02/26 22:09:28 jmc Exp $ -.Dd $Mdocdate: February 26 2010 $ +.\" $OpenBSD: ssh.1,v 1.297 2010/03/04 10:36:03 djm Exp $ +.Dd $Mdocdate: March 4 2010 $ .Dt SSH 1 .Os .Sh NAME @@ -1121,6 +1121,22 @@ See the section of .Xr ssh-keygen 1 for more details. +.Pp +Keys may be also be marked as revoked using the +.Dq @revoked +marker. +Revoked keys will always trigger a warning when encountered and the host +that presented them will be treated as untrusted. +For example: +.Pp +.Dl @revoked * ssh-rsa AAAAB5W... +.Pp +Revoking a key revokes it for direct use and as a certification authority. +Do not use both the +.Dq @cert-authority and +.Dq @revoked +markers on the same line. +.Pp .Sh SSH-BASED VIRTUAL PRIVATE NETWORKS .Nm contains support for Virtual Private Network (VPN) tunnelling diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c index df5a9bdcb5a..7bf8fbec832 100644 --- a/usr.bin/ssh/sshconnect.c +++ b/usr.bin/ssh/sshconnect.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sshconnect.c,v 1.219 2010/02/26 20:29:54 djm Exp $ */ +/* $OpenBSD: sshconnect.c,v 1.220 2010/03/04 10:36:03 djm Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -846,6 +846,25 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, logit("Warning: Permanently added '%.200s' (%s) to the " "list of known hosts.", hostp, type); break; + case HOST_REVOKED: + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("@ WARNING: REVOKED HOST KEY DETECTED! @"); + error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + error("The %s host key for %s is marked as revoked.", type, host); + error("This could mean that a stolen key is being used to"); + error("impersonate this host."); + + /* + * If strict host key checking is in use, the user will have + * to edit the key manually and we can only abort. + */ + if (options.strict_host_key_checking) { + error("%s host key for %.200s was revoked and you have " + "requested strict checking.", type, host); + goto fail; + } + goto continue_unsafe; + case HOST_CHANGED: if (want_cert) { /* @@ -895,6 +914,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, goto fail; } + continue_unsafe: /* * If strict host key checking has not been requested, allow * the connection but without MITM-able authentication or @@ -994,7 +1014,7 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, return 0; fail: - if (want_cert) { + if (want_cert && host_status != HOST_REVOKED) { /* * No matching certificate. Downgrade cert to raw key and * search normally. diff --git a/usr.bin/ssh/sshd_config.5 b/usr.bin/ssh/sshd_config.5 index 3b492a3dbc2..80ce110d3b9 100644 --- a/usr.bin/ssh/sshd_config.5 +++ b/usr.bin/ssh/sshd_config.5 @@ -34,8 +34,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: sshd_config.5,v 1.117 2010/02/26 20:29:54 djm Exp $ -.Dd $Mdocdate: February 26 2010 $ +.\" $OpenBSD: sshd_config.5,v 1.118 2010/03/04 10:36:03 djm Exp $ +.Dd $Mdocdate: March 4 2010 $ .Dt SSHD_CONFIG 5 .Os .Sh NAME @@ -815,6 +815,11 @@ Specifies whether public key authentication is allowed. The default is .Dq yes . Note that this option applies to protocol version 2 only. +.It Cm RevokedKeys +Specifies a list of revoked public keys. +Keys listed in this file will be refused for public key authentication. +Note that if this file is not readable, then public key authentication will +be refused for all users. .It Cm RhostsRSAAuthentication Specifies whether rhosts or /etc/hosts.equiv authentication together with successful RSA host authentication is allowed. @@ -890,6 +895,22 @@ This avoids infinitely hanging sessions. .Pp To disable TCP keepalive messages, the value should be set to .Dq no . +.It Cm TrustedUserCAKeys +Specifies a file containing public keys of certificate authorities that are +trusted sign user certificates for authentication. +Keys are listed one per line, empty lines and comments starting with +.Ql # +are allowed. +If a certificate is presented for authentication and has its signing CA key +listed in this file, then it may be used for authentication for any user +listed in the certificate's principals list. +Note that certificates that lack a list of principals will not be permitted +for authentication using +.Cm TrustedUserCAKeys . +For more details in certificates, please see the +.Sx CERTIFICATES +section in +.Xr ssh-keygen 1 . .It Cm UseDNS Specifies whether .Xr sshd 8 |