Bugzilla – Attachment 1508 Details for
Bug 1469
Should sshd detect and reject vulnerable SSH keys (re: Debian DSA-1571 and DSA-1576)
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
blacklisting and ssh-vulnkey
openssh-blacklist.diff (text/plain), 32.22 KB, created by
Colin Watson
on 2008-05-26 23:44:30 AEST
(
hide
)
Description:
blacklisting and ssh-vulnkey
Filename:
MIME Type:
Creator:
Colin Watson
Created:
2008-05-26 23:44:30 AEST
Size:
32.22 KB
patch
obsolete
>--- 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,24 @@ > 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) == 1) { >+ fp = key_fingerprint(client_host_key, SSH_FP_MD5, SSH_FP_HEX); >+ if (options.permit_blacklisted_keys) >+ logit("Public key %s from %s blacklisted (see " >+ "ssh-vulnkey(1)); continuing anyway", >+ fp, get_remote_ipaddr()); >+ else >+ logit("Public key %s from %s blacklisted (see " >+ "ssh-vulnkey(1))", >+ fp, get_remote_ipaddr()); >+ 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,6 @@ > Key *key_load_private_pem(int, int, const char *, char **); > int key_perm_ok(int, const char *); > >+int blacklisted_key(const Key *key); >+ > #endif >--- openssh-4.7p1.orig/sshd_config.5 >+++ openssh-4.7p1/sshd_config.5 >@@ -563,6 +563,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/ssh-vulnkey.1 >+++ openssh-4.7p1/ssh-vulnkey.1 >@@ -0,0 +1,242 @@ >+.\" 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 | Fl v >+.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 >+Unless the >+.Cm PermitBlacklistedKeys >+option is used, >+.Xr sshd 8 >+will reject attempts to authenticate with keys in the compromised list. >+.Pp >+The output from >+.Nm >+looks like this: >+.Pp >+.Bd -literal -offset indent >+/etc/ssh/ssh_host_key:1: COMPROMISED: RSA1 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx root@host >+/home/user/.ssh/id_dsa:1: Not blacklisted: DSA 1024 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx /home/user/.ssh/id_dsa.pub >+/home/user/.ssh/authorized_keys:3: Unknown (blacklist file not installed): RSA 1024 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx user@host >+.Ed >+.Pp >+Each line is of the following format (any lines beginning with >+.Dq # >+should be ignored by scripts): >+.Pp >+.Dl Ar filename : Ns Ar line : Ar status : Ar type Ar size Ar fingerprint Ar comment >+.Pp >+It is important to distinguish between the possible values of >+.Ar status : >+.Pp >+.Bl -tag -width Ds >+.It COMPROMISED >+These keys are listed in a blacklist file, normally because their >+corresponding private keys are well-known. >+Replacements must be generated using >+.Xr ssh-keygen 1 . >+.It Not blacklisted >+A blacklist file exists for this key type and size, but this key is not >+listed in it. >+Unless there is some particular reason to believe otherwise, this key >+may be used safely. >+(Note that DSA keys used with the broken version of OpenSSL distributed >+by Debian may be compromised in the event that anyone captured a network >+trace, even if they were generated with a secure version of OpenSSL.) >+.It Unknown (blacklist file not installed) >+No blacklist file exists for this key type and size. >+You should find a suitable published blacklist and install it before >+deciding whether this key is safe to use. >+.El >+.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. >+.It Fl v >+Verbose mode. >+Normally, >+.Nm >+does not output anything for keys that are not listed in their corresponding >+blacklist file (although it still produces output for keys for which there >+is no blacklist file, since their status is unknown). >+This option causes >+.Nm >+to produce output for all keys. >+.El >+.Sh EXIT STATUS >+.Nm >+will exit zero if any of the given keys were in the compromised list, >+otherwise non-zero. >+.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 /usr/share/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH >+If present, lists the blacklisted keys of type >+.Ar TYPE >+.Pf ( Dq RSA >+or >+.Dq DSA ) >+and bit length >+.Ar LENGTH . >+The format of this file is described above. >+RSA1 keys are converted to RSA before being checked in the blacklist. >+Note that the fingerprints of RSA1 keys are computed differently, so you >+will not be able to find them in the blacklist by hand. >+.It Pa /etc/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH >+Same as >+.Pa /usr/share/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH , >+but may be edited by the system administrator to add new blacklist entries. >+.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,26 @@ > 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) == 1) { >+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); >+ if (options.permit_blacklisted_keys) >+ logit("Public key %s from %s blacklisted (see " >+ "ssh-vulnkey(1)); continuing anyway", >+ fp, get_remote_ipaddr()); >+ else >+ logit("Public key %s from %s blacklisted (see " >+ "ssh-vulnkey(1))", >+ fp, get_remote_ipaddr()); >+ xfree(fp); >+ if (!options.permit_blacklisted_keys) >+ return 0; >+ } >+ > resolvedname = get_canonical_hostname(options.use_dns); > ipaddr = get_remote_ipaddr(); > >--- openssh-4.7p1.orig/sshd.c >+++ openssh-4.7p1/sshd.c >@@ -1457,6 +1457,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) == 1) { >+ 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/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,133 @@ > key_free(pub); > return NULL; > } >+ >+/* Scan a blacklist of known-vulnerable keys in blacklist_file. */ >+static int >+blacklisted_key_in_file(const Key *key, const 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; >+ >+ debug("Checking blacklist file %s", blacklist_file); >+ fd = open(blacklist_file, O_RDONLY); >+ if (fd < 0) { >+ ret = -1; >+ 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, sizeof(buf)); >+ if (r <= 0) >+ goto out; >+ if (buf[0] != '#') >+ break; >+ >+ newline = memchr(buf, '\n', sizeof(buf)); >+ 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; >+ 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); >+ return ret; >+} >+ >+/* Scan blacklists of known-vulnerable keys. */ >+int >+blacklisted_key(const Key *key) >+{ >+ Key *public; >+ char *blacklist_file; >+ int ret, ret2; >+ >+ public = key_demote(key); >+ if (public->type == KEY_RSA1) >+ public->type = KEY_RSA; >+ >+ xasprintf(&blacklist_file, "%s.%s-%u", >+ _PATH_BLACKLIST, key_type(public), key_size(public)); >+ ret = blacklisted_key_in_file(public, blacklist_file); >+ xfree(blacklist_file); >+ if (ret > 0) { >+ key_free(public); >+ return ret; >+ } >+ >+ xasprintf(&blacklist_file, "%s.%s-%u", >+ _PATH_BLACKLIST_CONFIG, key_type(public), key_size(public)); >+ ret2 = blacklisted_key_in_file(public, blacklist_file); >+ xfree(blacklist_file); >+ if (ret2 > ret) >+ ret = ret2; >+ >+ key_free(public); >+ return ret; >+} >--- openssh-4.7p1.orig/ssh-vulnkey.c >+++ openssh-4.7p1/ssh-vulnkey.c >@@ -0,0 +1,360 @@ >+/* >+ * 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 <errno.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 "uidswap.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 verbosity = 0; >+ >+static void >+usage(void) >+{ >+ fprintf(stderr, "usage: %s [-aqv] [file ...]\n", __progname); >+ fprintf(stderr, "Options:\n"); >+ fprintf(stderr, " -a Check keys of all users.\n"); >+ fprintf(stderr, " -q Quiet mode.\n"); >+ fprintf(stderr, " -v Verbose mode.\n"); >+ exit(1); >+} >+ >+void >+describe_key(const char *filename, u_long linenum, const char *msg, >+ const Key *key, const char *comment, int min_verbosity) >+{ >+ char *fp; >+ >+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); >+ if (verbosity >= min_verbosity) { >+ if (strchr(filename, ':')) >+ printf("\"%s\"", filename); >+ else >+ printf("%s", filename); >+ printf(":%lu: %s: %s %u %s %s\n", linenum, msg, >+ key_type(key), key_size(key), fp, comment); >+ } >+ xfree(fp); >+} >+ >+int >+do_key(const char *filename, u_long linenum, >+ const Key *key, const char *comment) >+{ >+ Key *public; >+ int blacklist_status; >+ int ret = 1; >+ >+ public = key_demote(key); >+ if (public->type == KEY_RSA1) >+ public->type = KEY_RSA; >+ >+ blacklist_status = blacklisted_key(public); >+ if (blacklist_status == -1) >+ describe_key(filename, linenum, >+ "Unknown (blacklist file not installed)", key, comment, 0); >+ else if (blacklist_status == 1) { >+ describe_key(filename, linenum, >+ "COMPROMISED", key, comment, 0); >+ ret = 0; >+ } else >+ describe_key(filename, linenum, >+ "Not blacklisted", key, comment, 1); >+ >+ key_free(public); >+ >+ 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) { >+ int save_errno; >+ f = fopen(filename, "r"); >+ save_errno = errno; >+ if (!f) { >+ char pubfile[MAXPATHLEN]; >+ if (strlcpy(pubfile, filename, sizeof pubfile) < >+ sizeof(pubfile) && >+ strlcat(pubfile, ".pub", sizeof pubfile) < >+ sizeof(pubfile)) >+ f = fopen(pubfile, "r"); >+ } >+ errno = save_errno; /* earlier errno is more useful */ >+ if (!f) { >+ if (!quiet_open) >+ perror(filename); >+ return -1; >+ } >+ if (verbosity > 0) >+ printf("# %s\n", filename); >+ } else >+ f = stdin; >+ while (read_keyfile_line(f, filename, line, sizeof(line), >+ &linenum) != -1) { >+ int i; >+ char *space; >+ int type; >+ char *end; >+ >+ /* 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 ((strtol(cp, &end, 10) == 0 || *end != ' ') && >+ 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(filename, linenum, >+ 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(filename, linenum, >+ 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(filename, 1, key, comment)) >+ ret = 0; >+ found = 1; >+ } >+ if (comment) >+ xfree(comment); >+ } >+ >+ return ret; >+} >+ >+int >+do_host(int quiet_open) >+{ >+ int i; >+ struct stat st; >+ int ret = 1; >+ >+ for (i = 0; default_host_files[i]; i++) { >+ if (stat(default_host_files[i], &st) < 0 && errno == ENOENT) >+ continue; >+ if (!do_filename(default_host_files[i], quiet_open)) >+ ret = 0; >+ } >+ >+ return ret; >+} >+ >+int >+do_user(const char *dir) >+{ >+ int i; >+ char *file; >+ struct stat st; >+ int ret = 1; >+ >+ for (i = 0; default_files[i]; i++) { >+ xasprintf(&file, "%s/%s", dir, default_files[i]); >+ if (stat(file, &st) < 0 && errno == ENOENT) { >+ xfree(file); >+ continue; >+ } >+ if (!do_filename(file, 0)) >+ ret = 0; >+ xfree(file); >+ } >+ >+ 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, "ahqv")) != -1) { >+ switch (opt) { >+ case 'a': >+ all_users = 1; >+ break; >+ case 'q': >+ verbosity--; >+ break; >+ case 'v': >+ verbosity++; >+ break; >+ case 'h': >+ default: >+ usage(); >+ } >+ } >+ >+ if (all_users) { >+ struct passwd *pw; >+ >+ if (!do_host(0)) >+ ret = 0; >+ >+ while ((pw = getpwent()) != NULL) { >+ if (pw->pw_dir) { >+ temporarily_use_uid(pw); >+ if (!do_user(pw->pw_dir)) >+ ret = 0; >+ restore_uid(); >+ } >+ } >+ } else if (optind == argc) { >+ struct passwd *pw; >+ >+ if (!do_host(1)) >+ ret = 0; >+ >+ if ((pw = getpwuid(geteuid())) == NULL) >+ fprintf(stderr, "No user found with uid %u\n", >+ (u_int)geteuid()); >+ 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/servconf.c >+++ openssh-4.7p1/servconf.c >@@ -212,6 +212,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) >@@ -281,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, >@@ -371,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 }, >@@ -919,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/auth-rsa.c >+++ openssh-4.7p1/auth-rsa.c >@@ -40,7 +40,9 @@ > #include "servconf.h" > #include "key.h" > #include "hostfile.h" >+#include "authfile.h" > #include "auth.h" >+#include "canohost.h" > #ifdef GSSAPI > #include "ssh-gss.h" > #endif >@@ -221,6 +223,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 +268,21 @@ > "actual %d vs. announced %d.", > file, linenum, BN_num_bits(key->rsa->n), bits); > >+ if (blacklisted_key(key) == 1) { >+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); >+ if (options.permit_blacklisted_keys) >+ logit("Public key %s from %s blacklisted (see " >+ "ssh-vulnkey(1)); continuing anyway", >+ fp, get_remote_ipaddr()); >+ else >+ logit("Public key %s from %s blacklisted (see " >+ "ssh-vulnkey(1))", >+ fp, get_remote_ipaddr()); >+ 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 >@@ -18,6 +18,10 @@ > #define SSHDIR ETCDIR "/ssh" > #endif > >+#ifndef _PATH_SSH_DATADIR >+#define _PATH_SSH_DATADIR "/usr/share/ssh" >+#endif >+ > #ifndef _PATH_SSH_PIDDIR > #define _PATH_SSH_PIDDIR "/var/run" > #endif >@@ -43,6 +47,9 @@ > /* Backwards compatibility */ > #define _PATH_DH_PRIMES SSHDIR "/primes" > >+#define _PATH_BLACKLIST _PATH_SSH_DATADIR "/blacklist" >+#define _PATH_BLACKLIST_CONFIG SSHDIR "/blacklist" >+ > #ifndef _PATH_SSH_PROGRAM > #define _PATH_SSH_PROGRAM "/usr/bin/ssh" > #endif >--- openssh-4.7p1.orig/servconf.h >+++ openssh-4.7p1/servconf.h >@@ -92,6 +92,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/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,25 @@ > int > user_key_allowed(struct passwd *pw, Key *key) > { >+ char *fp; > int success; > char *file; > >+ if (blacklisted_key(key) == 1) { >+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); >+ if (options.permit_blacklisted_keys) >+ logit("Public key %s from %s blacklisted (see " >+ "ssh-vulnkey(1)); continuing anyway", >+ fp, get_remote_ipaddr()); >+ else >+ logit("Public key %s from %s blacklisted (see " >+ "ssh-vulnkey(1))", >+ fp, get_remote_ipaddr()); >+ xfree(fp); >+ if (!options.permit_blacklisted_keys) >+ return 0; >+ } >+ > file = authorized_keys_file(pw); > success = user_key_allowed2(pw, key, file); > xfree(file); >--- openssh-4.7p1.orig/Makefile.in >+++ openssh-4.7p1/Makefile.in >@@ -26,6 +26,7 @@ > SFTP_SERVER=$(libexecdir)/sftp-server > SSH_KEYSIGN=$(libexecdir)/ssh-keysign > RAND_HELPER=$(libexecdir)/ssh-rand-helper >+SSH_DATADIR=$(datadir)/ssh > PRIVSEP_PATH=@PRIVSEP_PATH@ > SSH_PRIVSEP_USER=@SSH_PRIVSEP_USER@ > STRIP_OPT=@STRIP_OPT@ >@@ -37,7 +38,8 @@ > -D_PATH_SSH_KEY_SIGN=\"$(SSH_KEYSIGN)\" \ > -D_PATH_SSH_PIDDIR=\"$(piddir)\" \ > -D_PATH_PRIVSEP_CHROOT_DIR=\"$(PRIVSEP_PATH)\" \ >- -DSSH_RAND_HELPER=\"$(RAND_HELPER)\" >+ -DSSH_RAND_HELPER=\"$(RAND_HELPER)\" \ >+ -D_PATH_SSH_DATADIR=\"$(SSH_DATADIR)\" > > CC=@CC@ > LD=@LD@ >@@ -60,7 +62,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 +90,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 +167,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 +269,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 >@@ -279,6 +285,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 >@@ -360,6 +367,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) >@@ -372,6 +380,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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1469
:
1508
|
1510
|
1529
|
1530
|
1531