]> git.pld-linux.org Git - packages/openssh.git/commitdiff
- blacklist support and ssh-vulnkey tool for openssh (from Debian)
authorJacek Konieczny <jajcus@pld-linux.org>
Tue, 20 May 2008 13:15:28 +0000 (13:15 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    openssh-blacklist.diff -> 1.1

openssh-blacklist.diff [new file with mode: 0644]

diff --git a/openssh-blacklist.diff b/openssh-blacklist.diff
new file mode 100644 (file)
index 0000000..ba10d94
--- /dev/null
@@ -0,0 +1,991 @@
+This patch is against OpenSSH 4.7p1, although should apply to other versions
+without too much difficulty. It makes the following changes:
+
+  * Add key blacklisting support. Keys listed in
+    /etc/ssh/blacklist.TYPE-LENGTH will be rejected for authentication by
+    sshd, unless "PermitBlacklistedKeys yes" is set in /etc/ssh/sshd_config.
+
+  * Add a new program, ssh-vulnkey, which can be used to check keys against
+    these blacklists.
+
+This patch is up to date with respect to Debian openssh 1:4.7p1-10.
+
+--- openssh-4.7p1.orig/sshd_config.5
++++ openssh-4.7p1/sshd_config.5
+@@ -615,6 +615,20 @@
+ Specifies whether password authentication is allowed.
+ The default is
+ .Dq yes .
++.It Cm PermitBlacklistedKeys
++Specifies whether
++.Xr sshd 8
++should allow keys recorded in its blacklist of known-compromised keys (see
++.Xr ssh-vulnkey 1 ) .
++If
++.Dq yes ,
++then attempts to authenticate with compromised keys will be logged but
++accepted.
++If
++.Dq no ,
++then attempts to authenticate with compromised keys will be rejected.
++The default is
++.Dq no .
+ .It Cm PermitEmptyPasswords
+ When password authentication is allowed, it specifies whether the
+ server allows login to accounts with empty password strings.
+--- openssh-4.7p1.orig/sshd.c
++++ openssh-4.7p1/sshd.c
+@@ -1466,6 +1466,21 @@
+       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",
+--- openssh-4.7p1.orig/servconf.c
++++ openssh-4.7p1/servconf.c
+@@ -96,6 +96,7 @@
+       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;
+@@ -218,6 +219,8 @@
+               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)
+@@ -287,7 +290,7 @@
+       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,
+@@ -387,6 +390,7 @@
+       { "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 },
+@@ -943,6 +947,10 @@
+               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;
+--- openssh-4.7p1.orig/servconf.h
++++ openssh-4.7p1/servconf.h
+@@ -94,6 +94,7 @@
+                                                * 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 */
+--- openssh-4.7p1.orig/Makefile.in
++++ openssh-4.7p1/Makefile.in
+@@ -60,7 +60,7 @@
+ INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
+ INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
+-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT)
++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-agent$(EXEEXT) scp$(EXEEXT) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-vulnkey$(EXEEXT)
+ LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
+       canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
+@@ -88,8 +88,8 @@
+       loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
+       audit.o audit-bsm.o platform.o
+-MANPAGES      = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out sshd_config.5.out ssh_config.5.out
+-MANPAGES_IN   = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 sshd_config.5 ssh_config.5
++MANPAGES      = scp.1.out ssh-add.1.out ssh-agent.1.out ssh-keygen.1.out ssh-keyscan.1.out ssh.1.out sshd.8.out sftp-server.8.out sftp.1.out ssh-rand-helper.8.out ssh-keysign.8.out ssh-vulnkey.1.out sshd_config.5.out ssh_config.5.out
++MANPAGES_IN   = scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-rand-helper.8 ssh-keysign.8 ssh-vulnkey.1 sshd_config.5 ssh_config.5
+ MANTYPE               = @MANTYPE@
+ CONFIGFILES=sshd_config.out ssh_config.out moduli.out
+@@ -165,6 +165,9 @@
+ ssh-rand-helper${EXEEXT}: $(LIBCOMPAT) libssh.a ssh-rand-helper.o
+       $(LD) -o $@ ssh-rand-helper.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++ssh-vulnkey$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-vulnkey.o
++      $(LD) -o $@ ssh-vulnkey.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
++
+ # test driver for the loginrec code - not built by default
+ logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
+       $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS)
+@@ -264,6 +267,7 @@
+       $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign $(DESTDIR)$(SSH_KEYSIGN)
+       $(INSTALL) -m 0755 $(STRIP_OPT) sftp $(DESTDIR)$(bindir)/sftp
+       $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server $(DESTDIR)$(SFTP_SERVER)
++      $(INSTALL) -m 0755 $(STRIP_OPT) ssh-vulnkey $(DESTDIR)$(bindir)/ssh-vulnkey
+       $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
+       $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
+       $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
+@@ -280,6 +284,7 @@
+       $(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
+       $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+       $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
++      $(INSTALL) -m 644 ssh-vulnkey.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-vulnkey.1
+       -rm -f $(DESTDIR)$(bindir)/slogin
+       ln -s ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/slogin.1
+@@ -361,6 +366,7 @@
+       -rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT)
+       -rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
+       -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
++      -rm -f $(DESTDIR)$(bindir)/ssh-vulnkey$(EXEEXT)
+       -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT)
+       -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
+       -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
+@@ -373,6 +379,7 @@
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
++      -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-vulnkey.1
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-rand-helper.8
+       -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
+--- openssh-4.7p1.orig/auth-rh-rsa.c
++++ openssh-4.7p1/auth-rh-rsa.c
+@@ -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 @@
+ 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;
+--- openssh-4.7p1.orig/authfile.h
++++ openssh-4.7p1/authfile.h
+@@ -23,4 +23,7 @@
+ 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
+--- openssh-4.7p1.orig/ssh-vulnkey.1
++++ openssh-4.7p1/ssh-vulnkey.1
+@@ -0,0 +1,187 @@
++.\" Copyright (c) 2008 Canonical Ltd.  All rights reserved.
++.\"
++.\" Redistribution and use in source and binary forms, with or without
++.\" modification, are permitted provided that the following conditions
++.\" are met:
++.\" 1. Redistributions of source code must retain the above copyright
++.\"    notice, this list of conditions and the following disclaimer.
++.\" 2. Redistributions in binary form must reproduce the above copyright
++.\"    notice, this list of conditions and the following disclaimer in the
++.\"    documentation and/or other materials provided with the distribution.
++.\"
++.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++.\" (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 12 2008 $
++.Dt SSH-VULNKEY 1
++.Os
++.Sh NAME
++.Nm ssh-vulnkey
++.Nd check blacklist of compromised keys
++.Sh SYNOPSIS
++.Nm
++.Op Fl q
++.Ar file ...
++.Nm
++.Fl a
++.Sh DESCRIPTION
++.Nm
++checks a key against a blacklist of compromised keys.
++.Pp
++A substantial number of keys are known to have been generated using a broken
++version of OpenSSL distributed by Debian which failed to seed its random
++number generator correctly.
++Keys generated using these OpenSSL versions should be assumed to be
++compromised.
++This tool may be useful in checking for such keys.
++.Pp
++Keys that are compromised cannot be repaired; replacements must be generated
++using
++.Xr ssh-keygen 1 .
++Make sure to update
++.Pa authorized_keys
++files on all systems where compromised keys were permitted to authenticate.
++.Pp
++The argument list will be interpreted as a list of paths to public key files
++or
++.Pa authorized_keys
++files.
++If no suitable file is found at a given path,
++.Nm
++will append
++.Pa .pub
++and retry, in case it was given a private key file.
++If no files are given as arguments,
++.Nm
++will check
++.Pa ~/.ssh/id_rsa ,
++.Pa ~/.ssh/id_dsa ,
++.Pa ~/.ssh/identity ,
++.Pa ~/.ssh/authorized_keys
++and
++.Pa ~/.ssh/authorized_keys2 ,
++as well as the system's host keys if readable.
++.Pp
++If
++.Dq -
++is given as an argument,
++.Nm
++will read from standard input.
++This can be used to process output from
++.Xr ssh-keyscan 1 ,
++for example:
++.Pp
++.Dl $ ssh-keyscan -t rsa remote.example.org | ssh-vulnkey -
++.Pp
++.Nm
++will exit zero if any of the given keys were in the compromised list,
++otherwise non-zero.
++.Pp
++Unless the
++.Cm PermitBlacklistedKeys
++option is used,
++.Xr sshd 8
++will reject attempts to authenticate with keys in the compromised list.
++.Pp
++The options are as follows:
++.Bl -tag -width Ds
++.It Fl a
++Check keys of all users on the system.
++You will typically need to run
++.Nm
++as root to use this option.
++For each user,
++.Nm
++will check
++.Pa ~/.ssh/id_rsa ,
++.Pa ~/.ssh/id_dsa ,
++.Pa ~/.ssh/identity ,
++.Pa ~/.ssh/authorized_keys
++and
++.Pa ~/.ssh/authorized_keys2 .
++It will also check the system's host keys.
++.It Fl q
++Quiet mode.
++Normally,
++.Nm
++outputs the fingerprint of each key scanned, with a description of its
++status.
++This option suppresses that output.
++.El
++.Sh BLACKLIST FILE FORMAT
++The blacklist file may start with comments, on lines starting with
++.Dq # .
++After these initial comments, it must follow a strict format:
++.Pp
++.Bl -bullet -offset indent -compact
++.It
++All the lines must be exactly the same length (20 characters followed by a
++newline) and must be in sorted order.
++.It
++Each line must consist of the lower-case hexadecimal MD5 key fingerprint,
++without colons, and with the first 12 characters removed (that is, the least
++significant 80 bits of the fingerprint).
++.El
++.Pp
++The key fingerprint may be generated using
++.Xr ssh-keygen 1 :
++.Pp
++.Dl $ ssh-keygen -l -f /path/to/key
++.Pp
++This strict format is necessary to allow the blacklist file to be checked
++quickly, using a binary-search algorithm.
++.Sh FILES
++.Bl -tag -width Ds
++.It Pa ~/.ssh/id_rsa
++If present, contains the protocol version 2 RSA authentication identity of
++the user.
++.It Pa ~/.ssh/id_dsa
++If present, contains the protocol version 2 DSA authentication identity of
++the user.
++.It Pa ~/.ssh/identity
++If present, contains the protocol version 1 RSA authentication identity of
++the user.
++.It Pa ~/.ssh/authorized_keys
++If present, lists the public keys (RSA/DSA) that can be used for logging in
++as this user.
++.It Pa ~/.ssh/authorized_keys2
++Obsolete name for
++.Pa ~/.ssh/authorized_keys .
++This file may still be present on some old systems, but should not be
++created if it is missing.
++.It Pa /etc/ssh/ssh_host_rsa_key
++If present, contains the protocol version 2 RSA identity of the system.
++.It Pa /etc/ssh/ssh_host_dsa_key
++If present, contains the protocol version 2 DSA identity of the system.
++.It Pa /etc/ssh/ssh_host_key
++If present, contains the protocol version 1 RSA identity of the system.
++.It Pa /etc/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH
++If present, lists the blacklisted keys of type
++.Ar TYPE
++.Pf ( Dq RSA1 ,
++.Dq RSA ,
++or
++.Dq DSA )
++and bit length
++.Ar LENGTH .
++The format of this file is described above.
++.El
++.Sh SEE ALSO
++.Xr ssh-keygen 1 ,
++.Xr sshd 8
++.Sh AUTHORS
++.An -nosplit
++.An Colin Watson Aq cjwatson@ubuntu.com
++.Pp
++Florian Weimer suggested the option to check keys of all users, and the idea
++of processing
++.Xr ssh-keyscan 1
++output.
+--- openssh-4.7p1.orig/auth2-hostbased.c
++++ openssh-4.7p1/auth2-hostbased.c
+@@ -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 @@
+ 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();
+--- openssh-4.7p1.orig/authfile.c
++++ openssh-4.7p1/authfile.c
+@@ -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_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;
++}
+--- openssh-4.7p1.orig/ssh-vulnkey.c
++++ openssh-4.7p1/ssh-vulnkey.c
+@@ -0,0 +1,325 @@
++/*
++ * Copyright (c) 2008 Canonical Ltd.  All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ * 1. Redistributions of source code must retain the above copyright
++ *    notice, this list of conditions and the following disclaimer.
++ * 2. Redistributions in binary form must reproduce the above copyright
++ *    notice, this list of conditions and the following disclaimer in the
++ *    documentation and/or other materials provided with the distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#include "includes.h"
++
++#include <sys/types.h>
++#include <sys/stat.h>
++
++#include <string.h>
++#include <stdio.h>
++#include <fcntl.h>
++#include <unistd.h>
++
++#include <openssl/evp.h>
++
++#include "xmalloc.h"
++#include "ssh.h"
++#include "log.h"
++#include "key.h"
++#include "authfile.h"
++#include "pathnames.h"
++#include "misc.h"
++
++extern char *__progname;
++
++/* Default files to check */
++static char *default_host_files[] = {
++      _PATH_HOST_RSA_KEY_FILE,
++      _PATH_HOST_DSA_KEY_FILE,
++      _PATH_HOST_KEY_FILE,
++      NULL
++};
++static char *default_files[] = {
++      _PATH_SSH_CLIENT_ID_RSA,
++      _PATH_SSH_CLIENT_ID_DSA,
++      _PATH_SSH_CLIENT_IDENTITY,
++      _PATH_SSH_USER_PERMITTED_KEYS,
++      _PATH_SSH_USER_PERMITTED_KEYS2,
++      NULL
++};
++
++static int quiet = 0;
++
++static void
++usage(void)
++{
++      fprintf(stderr, "usage: %s [-aq] [file ...]\n", __progname);
++      fprintf(stderr, "Options:\n");
++      fprintf(stderr, "  -a          Check keys of all users.\n");
++      fprintf(stderr, "  -q          Quiet mode.\n");
++      exit(1);
++}
++
++void
++describe_key(const char *msg, const Key *key, const char *comment)
++{
++      char *fp;
++
++      fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
++      if (!quiet)
++              printf("%s: %u %s %s\n", msg, key_size(key), fp, comment);
++      xfree(fp);
++}
++
++int
++do_key(const Key *key, const char *comment)
++{
++      char *blacklist_file;
++      struct stat st;
++      int ret = 1;
++
++      blacklist_file = blacklist_filename(key);
++      if (stat(blacklist_file, &st) < 0)
++              describe_key("Unknown (no blacklist information)",
++                  key, comment);
++      else if (blacklisted_key(key)) {
++              describe_key("COMPROMISED", key, comment);
++              ret = 0;
++      } else
++              describe_key("Not blacklisted", key, comment);
++      xfree(blacklist_file);
++
++      return ret;
++}
++
++int
++do_filename(const char *filename, int quiet_open)
++{
++      FILE *f;
++      char line[SSH_MAX_PUBKEY_BYTES];
++      char *cp;
++      u_long linenum = 0;
++      Key *key;
++      char *comment = NULL;
++      int found = 0, ret = 1;
++
++      /* Copy much of key_load_public's logic here so that we can read
++       * several keys from a single file (e.g. authorized_keys).
++       */
++
++      if (strcmp(filename, "-") != 0) {
++              f = fopen(filename, "r");
++              if (!f) {
++                      char pubfile[MAXPATHLEN];
++                      if (strlcpy(pubfile, filename, sizeof pubfile) <
++                          sizeof(pubfile) &&
++                          strlcat(pubfile, ".pub", sizeof pubfile) <
++                          sizeof(pubfile))
++                              f = fopen(pubfile, "r");
++              }
++              if (!f) {
++                      if (!quiet_open)
++                              perror(filename);
++                      return -1;
++              }
++      } else
++              f = stdin;
++      while (read_keyfile_line(f, filename, line, sizeof(line),
++                  &linenum) != -1) {
++              int i;
++              char *space;
++              int type;
++
++              /* Chop trailing newline. */
++              i = strlen(line) - 1;
++              if (line[i] == '\n')
++                      line[i] = '\0';
++
++              /* Skip leading whitespace, empty and comment lines. */
++              for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
++                      ;
++              if (!*cp || *cp == '\n' || *cp == '#')
++                      continue;
++
++              /* Cope with ssh-keyscan output and options in
++               * authorized_keys files.
++               */
++              space = strchr(cp, ' ');
++              if (!space)
++                      continue;
++              *space = '\0';
++              type = key_type_from_name(cp);
++              *space = ' ';
++              /* Leading number (RSA1) or valid type (RSA/DSA) indicates
++               * that we have no host name or options to skip.
++               */
++              if (atoi(cp) == 0 && type == KEY_UNSPEC) {
++                      int quoted = 0;
++
++                      for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
++                              if (*cp == '\\' && cp[1] == '"')
++                                      cp++;   /* Skip both */
++                              else if (*cp == '"')
++                                      quoted = !quoted;
++                      }
++                      /* Skip remaining whitespace. */
++                      for (; *cp == ' ' || *cp == '\t'; cp++)
++                              ;
++                      if (!*cp)
++                              continue;
++              }
++
++              /* Read and process the key itself. */
++              key = key_new(KEY_RSA1);
++              if (key_read(key, &cp) == 1) {
++                      while (*cp == ' ' || *cp == '\t')
++                              cp++;
++                      if (!do_key(key, *cp ? cp : filename))
++                              ret = 0;
++                      found = 1;
++              } else {
++                      key_free(key);
++                      key = key_new(KEY_UNSPEC);
++                      if (key_read(key, &cp) == 1) {
++                              while (*cp == ' ' || *cp == '\t')
++                                      cp++;
++                              if (!do_key(key, *cp ? cp : filename))
++                                      ret = 0;
++                              found = 1;
++                      }
++              }
++              key_free(key);
++      }
++      if (f != stdin)
++              fclose(f);
++
++      if (!found && filename) {
++              key = key_load_public(filename, &comment);
++              if (key) {
++                      if (!do_key(key, comment))
++                              ret = 0;
++                      found = 1;
++              }
++              if (comment)
++                      xfree(comment);
++      }
++
++      return ret;
++}
++
++int
++do_host(void)
++{
++      int i;
++      struct stat st;
++      int ret = 1;
++
++      for (i = 0; default_host_files[i]; i++) {
++              if (stat(default_host_files[i], &st) < 0)
++                      continue;
++              if (!do_filename(default_host_files[i], 1))
++                      ret = 0;
++      }
++
++      return ret;
++}
++
++int
++do_user(const char *dir)
++{
++      int i;
++      char buf[MAXPATHLEN];
++      struct stat st;
++      int ret = 1;
++
++      for (i = 0; default_files[i]; i++) {
++              snprintf(buf, sizeof(buf), "%s/%s", dir, default_files[i]);
++              if (stat(buf, &st) < 0)
++                      continue;
++              if (!do_filename(buf, 0))
++                      ret = 0;
++      }
++
++      return ret;
++}
++
++int
++main(int argc, char **argv)
++{
++      int opt, all_users = 0;
++      int ret = 1;
++      extern int optind;
++
++      /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
++      sanitise_stdfd();
++
++      __progname = ssh_get_progname(argv[0]);
++
++      SSLeay_add_all_algorithms();
++      log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
++
++      /* We don't need the RNG ourselves, but symbol references here allow
++       * ld to link us properly.
++       */
++      init_rng();
++      seed_rng();
++
++      while ((opt = getopt(argc, argv, "ahq")) != -1) {
++              switch (opt) {
++              case 'a':
++                      all_users = 1;
++                      break;
++              case 'q':
++                      quiet = 1;
++                      break;
++              case 'h':
++              default:
++                      usage();
++              }
++      }
++
++      if (all_users) {
++              struct passwd *pw;
++
++              if (!do_host())
++                      ret = 0;
++
++              while ((pw = getpwent()) != NULL) {
++                      if (pw->pw_dir) {
++                              if (!do_user(pw->pw_dir))
++                                      ret = 0;
++                      }
++              }
++      } else if (optind == argc) {
++              struct passwd *pw;
++
++              if (!do_host())
++                      ret = 0;
++
++              if ((pw = getpwuid(getuid())) == NULL)
++                      fprintf(stderr, "No user found with uid %u\n",
++                          (u_int)getuid());
++              else {
++                      if (!do_user(pw->pw_dir))
++                              ret = 0;
++              }
++      } else {
++              while (optind < argc)
++                      if (!do_filename(argv[optind++], 0))
++                              ret = 0;
++      }
++
++      return ret;
++}
+--- openssh-4.7p1.orig/auth-rsa.c
++++ openssh-4.7p1/auth-rsa.c
+@@ -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 @@
+               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 @@
+                           "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,
+--- openssh-4.7p1.orig/pathnames.h
++++ openssh-4.7p1/pathnames.h
+@@ -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
+--- openssh-4.7p1.orig/auth2-pubkey.c
++++ openssh-4.7p1/auth2-pubkey.c
+@@ -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 @@
+ 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);
This page took 0.097811 seconds and 4 git commands to generate.