Add blacklist feature for weak Debian-generated ssh keys.
authorSimon Schubert <corecode@dragonflybsd.org>
Fri, 16 May 2008 10:48:44 +0000 (10:48 +0000)
committerSimon Schubert <corecode@dragonflybsd.org>
Fri, 16 May 2008 10:48:44 +0000 (10:48 +0000)
Default is to disallow weak keys.

Obtained-from:  Ubuntu Linux

crypto/openssh-5/auth-rh-rsa.c
crypto/openssh-5/auth-rsa.c
crypto/openssh-5/auth2-hostbased.c
crypto/openssh-5/auth2-pubkey.c
crypto/openssh-5/authfile.c
crypto/openssh-5/authfile.h
crypto/openssh-5/pathnames.h
crypto/openssh-5/servconf.c
crypto/openssh-5/servconf.h
crypto/openssh-5/sshd.c
crypto/openssh-5/sshd_config

index eca7502..093461e 100644 (file)
@@ -20,6 +20,7 @@
 #include <pwd.h>
 #include <stdarg.h>
 
+#include "xmalloc.h"
 #include "packet.h"
 #include "uidswap.h"
 #include "log.h"
@@ -27,6 +28,7 @@
 #include "servconf.h"
 #include "key.h"
 #include "hostfile.h"
+#include "authfile.h"
 #include "pathnames.h"
 #include "auth.h"
 #include "canohost.h"
@@ -42,8 +44,22 @@ int
 auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost,
     Key *client_host_key)
 {
+       char *fp;
        HostStatus host_status;
 
+       if (blacklisted_key(client_host_key)) {
+               fp = key_fingerprint(client_host_key, SSH_FP_MD5, SSH_FP_HEX);
+               if (options.permit_blacklisted_keys)
+                       logit("Public key %s blacklisted (see "
+                           "ssh-vulnkey(1)); continuing anyway", fp);
+               else
+                       logit("Public key %s blacklisted (see "
+                           "ssh-vulnkey(1))", fp);
+               xfree(fp);
+               if (!options.permit_blacklisted_keys)
+                       return 0;
+       }
+
        /* Check if we would accept it using rhosts authentication. */
        if (!auth_rhosts(pw, cuser))
                return 0;
index 69f9a58..1d277f9 100644 (file)
@@ -40,6 +40,7 @@
 #include "servconf.h"
 #include "key.h"
 #include "hostfile.h"
+#include "authfile.h"
 #include "auth.h"
 #ifdef GSSAPI
 #include "ssh-gss.h"
@@ -221,6 +222,7 @@ auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
                char *cp;
                char *key_options;
                int keybits;
+               char *fp;
 
                /* Skip leading whitespace, empty and comment lines. */
                for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
@@ -265,6 +267,19 @@ auth_rsa_key_allowed(struct passwd *pw, BIGNUM *client_n, Key **rkey)
                            "actual %d vs. announced %d.",
                            file, linenum, BN_num_bits(key->rsa->n), bits);
 
+               if (blacklisted_key(key)) {
+                       fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+                       if (options.permit_blacklisted_keys)
+                               logit("Public key %s blacklisted (see "
+                                   "ssh-vulnkey(1)); continuing anyway", fp);
+                       else
+                               logit("Public key %s blacklisted (see "
+                                   "ssh-vulnkey(1))", fp);
+                       xfree(fp);
+                       if (!options.permit_blacklisted_keys)
+                               continue;
+               }
+
                /* We have found the desired key. */
                /*
                 * If our options do not allow this key to be used,
index 663dec5..a0ee306 100644 (file)
@@ -40,6 +40,7 @@
 #include "compat.h"
 #include "key.h"
 #include "hostfile.h"
+#include "authfile.h"
 #include "auth.h"
 #include "canohost.h"
 #ifdef GSSAPI
@@ -141,10 +142,24 @@ int
 hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
     Key *key)
 {
+       char *fp;
        const char *resolvedname, *ipaddr, *lookup;
        HostStatus host_status;
        int len;
 
+       if (blacklisted_key(key)) {
+               fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+               if (options.permit_blacklisted_keys)
+                       logit("Public key %s blacklisted (see "
+                           "ssh-vulnkey(1)); continuing anyway", fp);
+               else
+                       logit("Public key %s blacklisted (see "
+                           "ssh-vulnkey(1))", fp);
+               xfree(fp);
+               if (!options.permit_blacklisted_keys)
+                       return 0;
+       }
+
        resolvedname = get_canonical_hostname(options.use_dns);
        ipaddr = get_remote_ipaddr();
 
index 9863cd9..cf91196 100644 (file)
@@ -42,6 +42,7 @@
 #include "compat.h"
 #include "key.h"
 #include "hostfile.h"
+#include "authfile.h"
 #include "auth.h"
 #include "pathnames.h"
 #include "uidswap.h"
@@ -269,9 +270,23 @@ user_key_allowed2(struct passwd *pw, Key *key, char *file)
 int
 user_key_allowed(struct passwd *pw, Key *key)
 {
+       char *fp;
        int success;
        char *file;
 
+       if (blacklisted_key(key)) {
+               fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+               if (options.permit_blacklisted_keys)
+                       logit("Public key %s blacklisted (see "
+                           "ssh-vulnkey(1)); continuing anyway", fp);
+               else
+                       logit("Public key %s blacklisted (see "
+                           "ssh-vulnkey(1))", fp);
+               xfree(fp);
+               if (!options.permit_blacklisted_keys)
+                       return 0;
+       }
+
        file = authorized_keys_file(pw);
        success = user_key_allowed2(pw, key, file);
        xfree(file);
index 735c647..5348a01 100644 (file)
@@ -65,6 +65,7 @@
 #include "rsa.h"
 #include "misc.h"
 #include "atomicio.h"
+#include "pathnames.h"
 
 /* Version identification string for SSH v1 identity files. */
 static const char authfile_id_string[] =
@@ -677,3 +678,113 @@ key_load_public(const char *filename, char **commentp)
        key_free(pub);
        return NULL;
 }
+
+char *
+blacklist_filename(const Key *key)
+{
+       char *name;
+
+       xasprintf(&name, "%s.%s-%u",
+           _PATH_BLACKLIST, key_type(key), key_size(key));
+       return name;
+}
+
+/* Scan a blacklist of known-vulnerable keys. */
+int
+blacklisted_key(const Key *key)
+{
+       char *blacklist_file;
+       int fd = -1;
+       char *dgst_hex = NULL;
+       char *dgst_packed = NULL, *p;
+       int i;
+       size_t line_len;
+       struct stat st;
+       char buf[256];
+       off_t start, lower, upper;
+       int ret = 0;
+
+       blacklist_file = blacklist_filename(key);
+       debug("Checking blacklist file %s", blacklist_file);
+       fd = open(blacklist_file, O_RDONLY);
+       if (fd < 0)
+               goto out;
+
+       dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+       /* Remove all colons */
+       dgst_packed = xcalloc(1, strlen(dgst_hex) + 1);
+       for (i = 0, p = dgst_packed; dgst_hex[i]; i++)
+               if (dgst_hex[i] != ':')
+                       *p++ = dgst_hex[i];
+       /* Only compare least-significant 80 bits (to keep the blacklist
+        * size down)
+        */
+       line_len = strlen(dgst_packed + 12);
+       if (line_len > 32)
+               goto out;
+
+       /* Skip leading comments */
+       start = 0;
+       for (;;) {
+               ssize_t r;
+               char *newline;
+
+               r = atomicio(read, fd, buf, 256);
+               if (r <= 0)
+                       goto out;
+               if (buf[0] != '#')
+                       break;
+
+               newline = memchr(buf, '\n', 256);
+               if (!newline)
+                       goto out;
+               start += newline + 1 - buf;
+               if (lseek(fd, start, SEEK_SET) < 0)
+                       goto out;
+       }
+
+       /* Initialise binary search record numbers */
+       if (fstat(fd, &st) < 0)
+               goto out;
+       lower = 0;
+       upper = (st.st_size - start) / (line_len + 1);
+
+       while (lower != upper) {
+               off_t cur;
+               char buf[32];
+               int cmp;
+
+               cur = lower + (upper - lower) / 2;
+
+               /* Read this line and compare to digest; this is
+                * overflow-safe since cur < max(off_t) / (line_len + 1) */
+               if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0)
+                       break;
+               if (atomicio(read, fd, buf, line_len) != line_len)
+                       break;
+               cmp = memcmp(buf, dgst_packed + 12, line_len);
+               if (cmp < 0) {
+                       if (cur == lower)
+                               break;
+                       lower = cur;
+               } else if (cmp > 0) {
+                       if (cur == upper)
+                               break;
+                       upper = cur;
+               } else {
+                       debug("Found %s in blacklist", dgst_hex);
+                       ret = 1;
+                       break;
+               }
+       }
+
+out:
+       if (dgst_packed)
+               xfree(dgst_packed);
+       if (dgst_hex)
+               xfree(dgst_hex);
+       if (fd >= 0)
+               close(fd);
+       xfree(blacklist_file);
+       return ret;
+}
index a6c7493..e477104 100644 (file)
@@ -23,4 +23,7 @@ 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 *);
 
+char   *blacklist_filename(const Key *key);
+int     blacklisted_key(const Key *key);
+
 #endif
index f2571e2..8886e8e 100644 (file)
@@ -43,6 +43,8 @@
 /* Backwards compatibility */
 #define _PATH_DH_PRIMES                        SSHDIR "/primes"
 
+#define _PATH_BLACKLIST                        SSHDIR "/blacklist"
+
 #ifndef _PATH_SSH_PROGRAM
 #define _PATH_SSH_PROGRAM              "/usr/bin/ssh"
 #endif
index e3e1925..b7211c9 100644 (file)
@@ -94,6 +94,7 @@ initialize_server_options(ServerOptions *options)
        options->password_authentication = -1;
        options->kbd_interactive_authentication = -1;
        options->challenge_response_authentication = -1;
+       options->permit_blacklisted_keys = -1;
        options->permit_empty_passwd = -1;
        options->permit_user_env = -1;
        options->use_login = -1;
@@ -211,6 +212,8 @@ fill_default_server_options(ServerOptions *options)
                options->kbd_interactive_authentication = 0;
        if (options->challenge_response_authentication == -1)
                options->challenge_response_authentication = 1;
+       if (options->permit_blacklisted_keys == -1)
+               options->permit_blacklisted_keys = 0;
        if (options->permit_empty_passwd == -1)
                options->permit_empty_passwd = 0;
        if (options->permit_user_env == -1)
@@ -280,7 +283,7 @@ typedef enum {
        sListenAddress, sAddressFamily,
        sPrintMotd, sPrintLastLog, sIgnoreRhosts,
        sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
-       sStrictModes, sEmptyPasswd, sTCPKeepAlive,
+       sStrictModes, sPermitBlacklistedKeys, sEmptyPasswd, sTCPKeepAlive,
        sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
        sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
        sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
@@ -371,6 +374,7 @@ static struct {
        { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
        { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
        { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
+       { "permitblacklistedkeys", sPermitBlacklistedKeys, SSHCFG_GLOBAL },
        { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
        { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
        { "uselogin", sUseLogin, SSHCFG_GLOBAL },
@@ -923,6 +927,10 @@ parse_flag:
                intptr = &options->tcp_keep_alive;
                goto parse_flag;
 
+       case sPermitBlacklistedKeys:
+               intptr = &options->permit_blacklisted_keys;
+               goto parse_flag;
+
        case sEmptyPasswd:
                intptr = &options->permit_empty_passwd;
                goto parse_flag;
index 5b88067..b7e5392 100644 (file)
@@ -95,6 +95,7 @@ typedef struct {
                                                 * authentication. */
        int     kbd_interactive_authentication; /* If true, permit */
        int     challenge_response_authentication;
+       int     permit_blacklisted_keys;        /* If true, permit */
        int     permit_empty_passwd;    /* If false, do not permit empty
                                         * passwords. */
        int     permit_user_env;        /* If true, read ~/.ssh/environment */
index 6071372..b6d5767 100644 (file)
@@ -1478,6 +1478,21 @@ main(int ac, char **av)
 
        for (i = 0; i < options.num_host_key_files; i++) {
                key = key_load_private(options.host_key_files[i], "", NULL);
+               if (key && blacklisted_key(key)) {
+                       char *fp;
+                       fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+                       if (options.permit_blacklisted_keys)
+                               error("Host key %s blacklisted (see "
+                                   "ssh-vulnkey(1)); continuing anyway", fp);
+                       else
+                               error("Host key %s blacklisted (see "
+                                   "ssh-vulnkey(1))", fp);
+                       xfree(fp);
+                       if (!options.permit_blacklisted_keys) {
+                               sensitive_data.host_keys[i] = NULL;
+                               continue;
+                       }
+               }
                sensitive_data.host_keys[i] = key;
                if (key == NULL) {
                        error("Could not load host key: %s",
index f52ecd4..2923a8a 100644 (file)
@@ -1,5 +1,5 @@
 #      $OpenBSD: sshd_config,v 1.77 2008/02/08 23:24:07 djm Exp $
-#      $DragonFly: src/crypto/openssh-5/sshd_config,v 1.2 2008/04/07 01:20:17 pavalos Exp $
+#      $DragonFly: src/crypto/openssh-5/sshd_config,v 1.3 2008/05/16 10:48:44 corecode Exp $
 
 # This is the sshd server system-wide configuration file.  See
 # sshd_config(5) for more information.
@@ -49,6 +49,7 @@ Protocol 2
 
 #RSAAuthentication yes
 #PubkeyAuthentication yes
+#PermitBlacklistedKeys no
 #AuthorizedKeysFile    .ssh/authorized_keys
 
 # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts