From 58056d14b173850e2ad912bc1b7b75a1d7497c83 Mon Sep 17 00:00:00 2001 From: djm Date: Wed, 4 Aug 2010 05:42:47 +0000 Subject: [PATCH] enable certificates for hostbased authentication, from Iain Morgan; "looks ok" markus@ --- usr.bin/ssh/auth.c | 4 +-- usr.bin/ssh/auth2-hostbased.c | 31 ++++++++++++++++-- usr.bin/ssh/authfile.c | 60 ++++++++++++++++++++++++++++++++++- usr.bin/ssh/authfile.h | 4 ++- usr.bin/ssh/ssh-keysign.8 | 7 ++-- usr.bin/ssh/ssh-keysign.c | 4 +-- usr.bin/ssh/ssh.c | 24 +++++++++----- 7 files changed, 115 insertions(+), 19 deletions(-) diff --git a/usr.bin/ssh/auth.c b/usr.bin/ssh/auth.c index f3919306145..d264f2f6d53 100644 --- a/usr.bin/ssh/auth.c +++ b/usr.bin/ssh/auth.c @@ -1,4 +1,4 @@ -/* $OpenBSD: auth.c,v 1.88 2010/06/22 04:49:47 djm Exp $ */ +/* $OpenBSD: auth.c,v 1.89 2010/08/04 05:42:47 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -295,7 +295,7 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, HostStatus host_status; /* Check if we know the host and its host key. */ - found = key_new(key->type); + found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); host_status = check_host_in_hostfile(sysfile, host, key, found, NULL); if (host_status != HOST_OK && userfile != NULL) { diff --git a/usr.bin/ssh/auth2-hostbased.c b/usr.bin/ssh/auth2-hostbased.c index 882651cfcc5..c10cb321697 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.13 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: auth2-hostbased.c,v 1.14 2010/08/04 05:42:47 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * @@ -140,9 +140,10 @@ int hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, Key *key) { - const char *resolvedname, *ipaddr, *lookup; + const char *resolvedname, *ipaddr, *lookup, *reason; HostStatus host_status; int len; + char *fp; if (auth_key_is_revoked(key)) return 0; @@ -173,16 +174,40 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, } debug2("userauth_hostbased: access allowed by auth_rhosts2"); + if (key_is_cert(key) && + key_cert_check_authority(key, 1, 0, lookup, &reason)) { + error("%s", reason); + auth_debug_add("%s", reason); + return 0; + } + host_status = check_key_in_hostfiles(pw, key, lookup, _PATH_SSH_SYSTEM_HOSTFILE, options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); /* backward compat if no key has been found. */ - if (host_status == HOST_NEW) + if (host_status == HOST_NEW) { host_status = check_key_in_hostfiles(pw, key, lookup, _PATH_SSH_SYSTEM_HOSTFILE2, options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE2); + } + + if (host_status == HOST_OK) { + if (key_is_cert(key)) { + fp = key_fingerprint(key->cert->signature_key, + SSH_FP_MD5, SSH_FP_HEX); + verbose("Accepted certificate ID \"%s\" signed by " + "%s CA %s from %s@%s", key->cert->key_id, + key_type(key->cert->signature_key), fp, + cuser, lookup); + } else { + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); + verbose("Accepted %s public key %s from %s@%s", + key_type(key), fp, cuser, lookup); + } + xfree(fp); + } return (host_status == HOST_OK); } diff --git a/usr.bin/ssh/authfile.c b/usr.bin/ssh/authfile.c index 3726f51042f..ffc21005c0c 100644 --- a/usr.bin/ssh/authfile.c +++ b/usr.bin/ssh/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.80 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: authfile.c,v 1.81 2010/08/04 05:42:47 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -681,6 +681,64 @@ key_load_public(const char *filename, char **commentp) return NULL; } +/* Load the certificate associated with the named private key */ +Key * +key_load_cert(const char *filename) +{ + Key *pub; + char file[MAXPATHLEN]; + + pub = key_new(KEY_UNSPEC); + if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && + (strlcat(file, "-cert.pub", sizeof file) < sizeof(file)) && + (key_try_load_public(pub, file, NULL) == 1)) + return pub; + key_free(pub); + return NULL; +} + +/* Load private key and certificate */ +Key * +key_load_private_cert(int type, const char *filename, const char *passphrase, + int *perm_ok) +{ + Key *key, *pub; + + switch (type) { + case KEY_RSA: + case KEY_DSA: + break; + default: + error("%s: unsupported key type", __func__); + return NULL; + } + + if ((key = key_load_private_type(type, filename, + passphrase, NULL, perm_ok)) == NULL) + return NULL; + + if ((pub = key_load_cert(filename)) == NULL) { + key_free(key); + return NULL; + } + + /* Make sure the private key matches the certificate */ + if (key_equal_public(key, pub) == 0) { + error("%s: certificate does not match private key %s", + __func__, filename); + } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) { + error("%s: key_to_certified failed", __func__); + } else { + key_cert_copy(pub, key); + key_free(pub); + return key; + } + + key_free(key); + 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. diff --git a/usr.bin/ssh/authfile.h b/usr.bin/ssh/authfile.h index 6dfa478e76e..6745dc062be 100644 --- a/usr.bin/ssh/authfile.h +++ b/usr.bin/ssh/authfile.h @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.h,v 1.14 2010/03/04 10:36:03 djm Exp $ */ +/* $OpenBSD: authfile.h,v 1.15 2010/08/04 05:42:47 djm Exp $ */ /* * Author: Tatu Ylonen @@ -16,9 +16,11 @@ #define AUTHFILE_H int key_save_private(Key *, const char *, const char *, const char *); +Key *key_load_cert(const char *); Key *key_load_public(const char *, char **); Key *key_load_public_type(int, const char *, char **); Key *key_load_private(const char *, const char *, char **); +Key *key_load_private_cert(int, const char *, const char *, int *); 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 *); diff --git a/usr.bin/ssh/ssh-keysign.8 b/usr.bin/ssh/ssh-keysign.8 index 3ba54b935ff..46c0ee9cd9d 100644 --- a/usr.bin/ssh/ssh-keysign.8 +++ b/usr.bin/ssh/ssh-keysign.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: ssh-keysign.8,v 1.9 2007/05/31 19:20:16 jmc Exp $ +.\" $OpenBSD: ssh-keysign.8,v 1.10 2010/08/04 05:42:47 djm Exp $ .\" .\" Copyright (c) 2002 Markus Friedl. All rights reserved. .\" @@ -22,7 +22,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. .\" -.Dd $Mdocdate: May 31 2007 $ +.Dd $Mdocdate: August 4 2010 $ .Dt SSH-KEYSIGN 8 .Os .Sh NAME @@ -68,6 +68,9 @@ accessible to others. Since they are readable only by root, .Nm must be set-uid root if host-based authentication is used. +.It Pa /etc/ssh/ssh_host_dsa_key-cert.pub, /etc/ssh/ssh_host_rsa_key-cert.pub +If these files exist they are assumed to contain public certificate +information corresponding with the private keys above. .El .Sh SEE ALSO .Xr ssh 1 , diff --git a/usr.bin/ssh/ssh-keysign.c b/usr.bin/ssh/ssh-keysign.c index 47cbd3fb257..298a90f4590 100644 --- a/usr.bin/ssh/ssh-keysign.c +++ b/usr.bin/ssh/ssh-keysign.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh-keysign.c,v 1.30 2010/01/13 01:20:20 dtucker Exp $ */ +/* $OpenBSD: ssh-keysign.c,v 1.31 2010/08/04 05:42:47 djm Exp $ */ /* * Copyright (c) 2002 Markus Friedl. All rights reserved. * @@ -223,7 +223,7 @@ main(int argc, char **argv) found = 0; for (i = 0; i < 2; i++) { if (keys[i] != NULL && - key_equal(key, keys[i])) { + key_equal_public(key, keys[i])) { found = 1; break; } diff --git a/usr.bin/ssh/ssh.c b/usr.bin/ssh/ssh.c index 0c18fec527b..dc49752c4c5 100644 --- a/usr.bin/ssh/ssh.c +++ b/usr.bin/ssh/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.344 2010/07/19 09:15:12 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.345 2010/08/04 05:42:47 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -755,26 +755,34 @@ main(int ac, char **av) sensitive_data.external_keysign = 0; if (options.rhosts_rsa_authentication || options.hostbased_authentication) { - sensitive_data.nkeys = 3; + sensitive_data.nkeys = 5; sensitive_data.keys = xcalloc(sensitive_data.nkeys, sizeof(Key)); PRIV_START; sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, _PATH_HOST_KEY_FILE, "", NULL, NULL); - sensitive_data.keys[1] = key_load_private_type(KEY_DSA, + sensitive_data.keys[1] = key_load_private_cert(KEY_DSA, + _PATH_HOST_DSA_KEY_FILE, "", NULL); + sensitive_data.keys[2] = key_load_private_cert(KEY_RSA, + _PATH_HOST_RSA_KEY_FILE, "", NULL); + sensitive_data.keys[3] = key_load_private_type(KEY_DSA, _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); - sensitive_data.keys[2] = key_load_private_type(KEY_RSA, + sensitive_data.keys[4] = key_load_private_type(KEY_RSA, _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); PRIV_END; if (options.hostbased_authentication == 1 && sensitive_data.keys[0] == NULL && - sensitive_data.keys[1] == NULL && - sensitive_data.keys[2] == NULL) { - sensitive_data.keys[1] = key_load_public( + sensitive_data.keys[3] == NULL && + sensitive_data.keys[4] == NULL) { + sensitive_data.keys[1] = key_load_cert( + _PATH_HOST_DSA_KEY_FILE); + sensitive_data.keys[2] = key_load_cert( + _PATH_HOST_RSA_KEY_FILE); + sensitive_data.keys[3] = key_load_public( _PATH_HOST_DSA_KEY_FILE, NULL); - sensitive_data.keys[2] = key_load_public( + sensitive_data.keys[4] = key_load_public( _PATH_HOST_RSA_KEY_FILE, NULL); sensitive_data.external_keysign = 1; } -- 2.20.1