1 This patch is against OpenSSH 4.7p1, although should apply to other versions
2 without too much difficulty. It makes the following changes:
4 * Add key blacklisting support. Keys listed in
5 /etc/ssh/blacklist.TYPE-LENGTH will be rejected for authentication by
6 sshd, unless "PermitBlacklistedKeys yes" is set in /etc/ssh/sshd_config.
8 * Add a new program, ssh-vulnkey, which can be used to check keys against
11 This patch is up to date with respect to Debian openssh 1:4.7p1-10.
13 --- openssh-4.7p1.orig/sshd_config.5
14 +++ openssh-4.7p1/sshd_config.5
16 Specifies whether password authentication is allowed.
19 +.It Cm PermitBlacklistedKeys
22 +should allow keys recorded in its blacklist of known-compromised keys (see
23 +.Xr ssh-vulnkey 1 ) .
26 +then attempts to authenticate with compromised keys will be logged but
30 +then attempts to authenticate with compromised keys will be rejected.
33 .It Cm PermitEmptyPasswords
34 When password authentication is allowed, it specifies whether the
35 server allows login to accounts with empty password strings.
36 --- openssh-4.7p1.orig/sshd.c
37 +++ openssh-4.7p1/sshd.c
38 @@ -1466,6 +1466,21 @@
40 for (i = 0; i < options.num_host_key_files; i++) {
41 key = key_load_private(options.host_key_files[i], "", NULL);
42 + if (key && blacklisted_key(key)) {
44 + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
45 + if (options.permit_blacklisted_keys)
46 + error("Host key %s blacklisted (see "
47 + "ssh-vulnkey(1)); continuing anyway", fp);
49 + error("Host key %s blacklisted (see "
50 + "ssh-vulnkey(1))", fp);
52 + if (!options.permit_blacklisted_keys) {
53 + sensitive_data.host_keys[i] = NULL;
57 sensitive_data.host_keys[i] = key;
59 error("Could not load host key: %s",
60 --- openssh-4.7p1.orig/servconf.c
61 +++ openssh-4.7p1/servconf.c
63 options->password_authentication = -1;
64 options->kbd_interactive_authentication = -1;
65 options->challenge_response_authentication = -1;
66 + options->permit_blacklisted_keys = -1;
67 options->permit_empty_passwd = -1;
68 options->permit_user_env = -1;
69 options->use_login = -1;
71 options->kbd_interactive_authentication = 0;
72 if (options->challenge_response_authentication == -1)
73 options->challenge_response_authentication = 1;
74 + if (options->permit_blacklisted_keys == -1)
75 + options->permit_blacklisted_keys = 0;
76 if (options->permit_empty_passwd == -1)
77 options->permit_empty_passwd = 0;
78 if (options->permit_user_env == -1)
80 sListenAddress, sAddressFamily,
81 sPrintMotd, sPrintLastLog, sIgnoreRhosts,
82 sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
83 - sStrictModes, sEmptyPasswd, sTCPKeepAlive,
84 + sStrictModes, sPermitBlacklistedKeys, sEmptyPasswd, sTCPKeepAlive,
85 sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
86 sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
87 sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
89 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
90 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
91 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
92 + { "permitblacklistedkeys", sPermitBlacklistedKeys, SSHCFG_GLOBAL },
93 { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
94 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
95 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
97 intptr = &options->tcp_keep_alive;
100 + case sPermitBlacklistedKeys:
101 + intptr = &options->permit_blacklisted_keys;
105 intptr = &options->permit_empty_passwd;
107 --- openssh-4.7p1.orig/servconf.h
108 +++ openssh-4.7p1/servconf.h
111 int kbd_interactive_authentication; /* If true, permit */
112 int challenge_response_authentication;
113 + int permit_blacklisted_keys; /* If true, permit */
114 int zero_knowledge_password_authentication;
115 /* If true, permit jpake auth */
116 int permit_empty_passwd; /* If false, do not permit empty
117 --- openssh-4.7p1.orig/Makefile.in
118 +++ openssh-4.7p1/Makefile.in
120 INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
121 INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
123 -TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT)
124 +TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-ldap-helper$(EXEEXT) ssh-vulnkey$(EXEEXT)
126 LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
127 canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
129 audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \
130 roaming_common.o roaming_serv.o ldapauth.o
132 -MANPAGES = moduli.5.out 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-keysign.8.out ssh-pkcs11-helper.8.out ssh-ldap-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap.conf.5.out
133 -MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-ldap-helper.8 sshd_config.5 ssh_config.5 ssh-ldap.conf.5
134 +MANPAGES = moduli.5.out 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-keysign.8.out ssh-pkcs11-helper.8.out ssh-ldap-helper.8.out sshd_config.5.out ssh_config.5.out ssh-ldap.conf.5.out ssh-vulnkey.1.out
135 +MANPAGES_IN = moduli.5 scp.1 ssh-add.1 ssh-agent.1 ssh-keygen.1 ssh-keyscan.1 ssh.1 sshd.8 sftp-server.8 sftp.1 ssh-keysign.8 ssh-pkcs11-helper.8 ssh-ldap-helper.8 sshd_config.5 ssh_config.5 ssh-ldap.conf.5 ssh-vulnkey.1
138 CONFIGFILES=sshd_config.out ssh_config.out moduli.out
140 ssh-rand-helper${EXEEXT}: $(LIBCOMPAT) libssh.a ssh-rand-helper.o
141 $(LD) -o $@ ssh-rand-helper.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
143 +ssh-vulnkey$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-vulnkey.o
144 + $(LD) -o $@ ssh-vulnkey.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
146 # test driver for the loginrec code - not built by default
147 logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o
148 $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS)
150 $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT)
151 $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT)
152 $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
153 + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-vulnkey$(EXEEXT) $(DESTDIR)$(bindir)/ssh-vulnkey$(EXEEXT)
154 $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1
155 $(INSTALL) -m 644 scp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/scp.1
156 $(INSTALL) -m 644 ssh-add.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-add.1
158 $(INSTALL) -m 644 sftp.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
159 $(INSTALL) -m 644 sftp-server.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
160 $(INSTALL) -m 644 ssh-keysign.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-keysign.8
161 + $(INSTALL) -m 644 ssh-vulnkey.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-vulnkey.1
162 $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
163 -rm -f $(DESTDIR)$(bindir)/slogin
164 ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
166 -rm -f $(DESTDIR)$(bindir)/ssh-agent$(EXEEXT)
167 -rm -f $(DESTDIR)$(bindir)/ssh-keygen$(EXEEXT)
168 -rm -f $(DESTDIR)$(bindir)/ssh-keyscan$(EXEEXT)
169 + -rm -f $(DESTDIR)$(bindir)/ssh-vulnkey$(EXEEXT)
170 -rm -f $(DESTDIR)$(bindir)/sftp$(EXEEXT)
171 -rm -f $(DESTDIR)$(sbindir)/sshd$(EXEEXT)
172 -rm -r $(DESTDIR)$(SFTP_SERVER)$(EXEEXT)
174 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keygen.1
175 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/sftp.1
176 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-keyscan.1
177 + -rm -f $(DESTDIR)$(mandir)/$(mansubdir)1/ssh-vulnkey.1
178 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sshd.8
179 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-rand-helper.8
180 -rm -f $(DESTDIR)$(mandir)/$(mansubdir)8/sftp-server.8
181 --- openssh-4.7p1.orig/auth-rh-rsa.c
182 +++ openssh-4.7p1/auth-rh-rsa.c
187 +#include "xmalloc.h"
192 #include "servconf.h"
194 #include "hostfile.h"
195 +#include "authfile.h"
196 #include "pathnames.h"
198 #include "canohost.h"
200 auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost,
201 Key *client_host_key)
204 HostStatus host_status;
206 + if (blacklisted_key(client_host_key)) {
207 + fp = key_fingerprint(client_host_key, SSH_FP_MD5, SSH_FP_HEX);
208 + if (options.permit_blacklisted_keys)
209 + logit("Public key %s blacklisted (see "
210 + "ssh-vulnkey(1)); continuing anyway", fp);
212 + logit("Public key %s blacklisted (see "
213 + "ssh-vulnkey(1))", fp);
215 + if (!options.permit_blacklisted_keys)
219 if (auth_key_is_revoked(client_host_key))
222 --- openssh-4.7p1.orig/authfile.h
223 +++ openssh-4.7p1/authfile.h
225 Key *key_load_private_pem(int, int, const char *, char **);
226 int key_perm_ok(int, const char *);
228 +char *blacklist_filename(const Key *key);
229 +int blacklisted_key(const Key *key);
232 --- openssh-4.7p1.orig/ssh-vulnkey.1
233 +++ openssh-4.7p1/ssh-vulnkey.1
235 +.\" Copyright (c) 2008 Canonical Ltd. All rights reserved.
237 +.\" Redistribution and use in source and binary forms, with or without
238 +.\" modification, are permitted provided that the following conditions
240 +.\" 1. Redistributions of source code must retain the above copyright
241 +.\" notice, this list of conditions and the following disclaimer.
242 +.\" 2. Redistributions in binary form must reproduce the above copyright
243 +.\" notice, this list of conditions and the following disclaimer in the
244 +.\" documentation and/or other materials provided with the distribution.
246 +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
247 +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
248 +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
249 +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
250 +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
251 +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
252 +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
253 +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254 +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
255 +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
257 +.Dd $Mdocdate: May 12 2008 $
262 +.Nd check blacklist of compromised keys
271 +checks a key against a blacklist of compromised keys.
273 +A substantial number of keys are known to have been generated using a broken
274 +version of OpenSSL distributed by Debian which failed to seed its random
275 +number generator correctly.
276 +Keys generated using these OpenSSL versions should be assumed to be
278 +This tool may be useful in checking for such keys.
280 +Keys that are compromised cannot be repaired; replacements must be generated
285 +files on all systems where compromised keys were permitted to authenticate.
287 +The argument list will be interpreted as a list of paths to public key files
291 +If no suitable file is found at a given path,
295 +and retry, in case it was given a private key file.
296 +If no files are given as arguments,
301 +.Pa ~/.ssh/identity ,
302 +.Pa ~/.ssh/authorized_keys
304 +.Pa ~/.ssh/authorized_keys2 ,
305 +as well as the system's host keys if readable.
309 +is given as an argument,
311 +will read from standard input.
312 +This can be used to process output from
316 +.Dl $ ssh-keyscan -t rsa remote.example.org | ssh-vulnkey -
319 +will exit zero if any of the given keys were in the compromised list,
323 +.Cm PermitBlacklistedKeys
326 +will reject attempts to authenticate with keys in the compromised list.
328 +The options are as follows:
331 +Check keys of all users on the system.
332 +You will typically need to run
334 +as root to use this option.
340 +.Pa ~/.ssh/identity ,
341 +.Pa ~/.ssh/authorized_keys
343 +.Pa ~/.ssh/authorized_keys2 .
344 +It will also check the system's host keys.
349 +outputs the fingerprint of each key scanned, with a description of its
351 +This option suppresses that output.
353 +.Sh BLACKLIST FILE FORMAT
354 +The blacklist file may start with comments, on lines starting with
356 +After these initial comments, it must follow a strict format:
358 +.Bl -bullet -offset indent -compact
360 +All the lines must be exactly the same length (20 characters followed by a
361 +newline) and must be in sorted order.
363 +Each line must consist of the lower-case hexadecimal MD5 key fingerprint,
364 +without colons, and with the first 12 characters removed (that is, the least
365 +significant 80 bits of the fingerprint).
368 +The key fingerprint may be generated using
371 +.Dl $ ssh-keygen -l -f /path/to/key
373 +This strict format is necessary to allow the blacklist file to be checked
374 +quickly, using a binary-search algorithm.
377 +.It Pa ~/.ssh/id_rsa
378 +If present, contains the protocol version 2 RSA authentication identity of
380 +.It Pa ~/.ssh/id_dsa
381 +If present, contains the protocol version 2 DSA authentication identity of
383 +.It Pa ~/.ssh/identity
384 +If present, contains the protocol version 1 RSA authentication identity of
386 +.It Pa ~/.ssh/authorized_keys
387 +If present, lists the public keys (RSA/DSA) that can be used for logging in
389 +.It Pa ~/.ssh/authorized_keys2
391 +.Pa ~/.ssh/authorized_keys .
392 +This file may still be present on some old systems, but should not be
393 +created if it is missing.
394 +.It Pa /etc/ssh/ssh_host_rsa_key
395 +If present, contains the protocol version 2 RSA identity of the system.
396 +.It Pa /etc/ssh/ssh_host_dsa_key
397 +If present, contains the protocol version 2 DSA identity of the system.
398 +.It Pa /etc/ssh/ssh_host_key
399 +If present, contains the protocol version 1 RSA identity of the system.
400 +.It Pa /etc/ssh/blacklist. Ns Ar TYPE Ns Pa - Ns Ar LENGTH
401 +If present, lists the blacklisted keys of type
409 +The format of this file is described above.
416 +.An Colin Watson Aq cjwatson@ubuntu.com
418 +Florian Weimer suggested the option to check keys of all users, and the idea
422 --- openssh-5.6p1/auth2-hostbased.c~ 2010-08-24 14:10:03.000000000 +0300
423 +++ openssh-5.6p1/auth2-hostbased.c 2010-08-24 14:12:10.632553591 +0300
427 #include "hostfile.h"
428 +#include "authfile.h"
430 #include "canohost.h"
436 + if (blacklisted_key(key)) {
437 + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
438 + if (options.permit_blacklisted_keys)
439 + logit("Public key %s blacklisted (see "
440 + "ssh-vulnkey(1)); continuing anyway", fp);
442 + logit("Public key %s blacklisted (see "
443 + "ssh-vulnkey(1))", fp);
445 + if (!options.permit_blacklisted_keys)
449 if (auth_key_is_revoked(key))
452 --- openssh-4.7p1.orig/authfile.c
453 +++ openssh-4.7p1/authfile.c
457 #include "atomicio.h"
458 +#include "pathnames.h"
460 /* Version identification string for SSH v1 identity files. */
461 static const char authfile_id_string[] =
462 @@ -677,3 +678,113 @@
468 +blacklist_filename(const Key *key)
472 + xasprintf(&name, "%s.%s-%u",
473 + _PATH_BLACKLIST, key_type(key), key_size(key));
477 +/* Scan a blacklist of known-vulnerable keys. */
479 +blacklisted_key(const Key *key)
481 + char *blacklist_file;
483 + char *dgst_hex = NULL;
484 + char *dgst_packed = NULL, *p;
489 + off_t start, lower, upper;
492 + blacklist_file = blacklist_filename(key);
493 + debug("Checking blacklist file %s", blacklist_file);
494 + fd = open(blacklist_file, O_RDONLY);
498 + dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
499 + /* Remove all colons */
500 + dgst_packed = xcalloc(1, strlen(dgst_hex) + 1);
501 + for (i = 0, p = dgst_packed; dgst_hex[i]; i++)
502 + if (dgst_hex[i] != ':')
503 + *p++ = dgst_hex[i];
504 + /* Only compare least-significant 80 bits (to keep the blacklist
507 + line_len = strlen(dgst_packed + 12);
511 + /* Skip leading comments */
517 + r = atomicio(read, fd, buf, 256);
523 + newline = memchr(buf, '\n', 256);
526 + start += newline + 1 - buf;
527 + if (lseek(fd, start, SEEK_SET) < 0)
531 + /* Initialise binary search record numbers */
532 + if (fstat(fd, &st) < 0)
535 + upper = (st.st_size - start) / (line_len + 1);
537 + while (lower != upper) {
542 + cur = lower + (upper - lower) / 2;
544 + /* Read this line and compare to digest; this is
545 + * overflow-safe since cur < max(off_t) / (line_len + 1) */
546 + if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0)
548 + if (atomicio(read, fd, buf, line_len) != line_len)
550 + cmp = memcmp(buf, dgst_packed + 12, line_len);
555 + } else if (cmp > 0) {
560 + debug("Found %s in blacklist", dgst_hex);
568 + xfree(dgst_packed);
573 + xfree(blacklist_file);
576 --- openssh-4.7p1.orig/ssh-vulnkey.c
577 +++ openssh-4.7p1/ssh-vulnkey.c
580 + * Copyright (c) 2008 Canonical Ltd. All rights reserved.
582 + * Redistribution and use in source and binary forms, with or without
583 + * modification, are permitted provided that the following conditions
585 + * 1. Redistributions of source code must retain the above copyright
586 + * notice, this list of conditions and the following disclaimer.
587 + * 2. Redistributions in binary form must reproduce the above copyright
588 + * notice, this list of conditions and the following disclaimer in the
589 + * documentation and/or other materials provided with the distribution.
591 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
592 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
593 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
594 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
595 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
596 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
597 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
598 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
599 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
600 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
603 +#include "includes.h"
605 +#include <sys/types.h>
606 +#include <sys/stat.h>
613 +#include <openssl/evp.h>
615 +#include "xmalloc.h"
619 +#include "authfile.h"
620 +#include "pathnames.h"
623 +extern char *__progname;
625 +/* Default files to check */
626 +static char *default_host_files[] = {
627 + _PATH_HOST_RSA_KEY_FILE,
628 + _PATH_HOST_DSA_KEY_FILE,
629 + _PATH_HOST_KEY_FILE,
632 +static char *default_files[] = {
633 + _PATH_SSH_CLIENT_ID_RSA,
634 + _PATH_SSH_CLIENT_ID_DSA,
635 + _PATH_SSH_CLIENT_IDENTITY,
636 + _PATH_SSH_USER_PERMITTED_KEYS,
637 + _PATH_SSH_USER_PERMITTED_KEYS2,
641 +static int quiet = 0;
646 + fprintf(stderr, "usage: %s [-aq] [file ...]\n", __progname);
647 + fprintf(stderr, "Options:\n");
648 + fprintf(stderr, " -a Check keys of all users.\n");
649 + fprintf(stderr, " -q Quiet mode.\n");
654 +describe_key(const char *msg, const Key *key, const char *comment)
658 + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
660 + printf("%s: %u %s %s\n", msg, key_size(key), fp, comment);
665 +do_key(const Key *key, const char *comment)
667 + char *blacklist_file;
671 + blacklist_file = blacklist_filename(key);
672 + if (stat(blacklist_file, &st) < 0)
673 + describe_key("Unknown (no blacklist information)",
675 + else if (blacklisted_key(key)) {
676 + describe_key("COMPROMISED", key, comment);
679 + describe_key("Not blacklisted", key, comment);
680 + xfree(blacklist_file);
686 +do_filename(const char *filename, int quiet_open)
689 + char line[SSH_MAX_PUBKEY_BYTES];
691 + u_long linenum = 0;
693 + char *comment = NULL;
694 + int found = 0, ret = 1;
696 + /* Copy much of key_load_public's logic here so that we can read
697 + * several keys from a single file (e.g. authorized_keys).
700 + if (strcmp(filename, "-") != 0) {
701 + f = fopen(filename, "r");
703 + char pubfile[MAXPATHLEN];
704 + if (strlcpy(pubfile, filename, sizeof pubfile) <
706 + strlcat(pubfile, ".pub", sizeof pubfile) <
708 + f = fopen(pubfile, "r");
717 + while (read_keyfile_line(f, filename, line, sizeof(line),
723 + /* Chop trailing newline. */
724 + i = strlen(line) - 1;
725 + if (line[i] == '\n')
728 + /* Skip leading whitespace, empty and comment lines. */
729 + for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
731 + if (!*cp || *cp == '\n' || *cp == '#')
734 + /* Cope with ssh-keyscan output and options in
735 + * authorized_keys files.
737 + space = strchr(cp, ' ');
741 + type = key_type_from_name(cp);
743 + /* Leading number (RSA1) or valid type (RSA/DSA) indicates
744 + * that we have no host name or options to skip.
746 + if (atoi(cp) == 0 && type == KEY_UNSPEC) {
749 + for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
750 + if (*cp == '\\' && cp[1] == '"')
751 + cp++; /* Skip both */
752 + else if (*cp == '"')
755 + /* Skip remaining whitespace. */
756 + for (; *cp == ' ' || *cp == '\t'; cp++)
762 + /* Read and process the key itself. */
763 + key = key_new(KEY_RSA1);
764 + if (key_read(key, &cp) == 1) {
765 + while (*cp == ' ' || *cp == '\t')
767 + if (!do_key(key, *cp ? cp : filename))
772 + key = key_new(KEY_UNSPEC);
773 + if (key_read(key, &cp) == 1) {
774 + while (*cp == ' ' || *cp == '\t')
776 + if (!do_key(key, *cp ? cp : filename))
786 + if (!found && filename) {
787 + key = key_load_public(filename, &comment);
789 + if (!do_key(key, comment))
807 + for (i = 0; default_host_files[i]; i++) {
808 + if (stat(default_host_files[i], &st) < 0)
810 + if (!do_filename(default_host_files[i], 1))
818 +do_user(const char *dir)
821 + char buf[MAXPATHLEN];
825 + for (i = 0; default_files[i]; i++) {
826 + snprintf(buf, sizeof(buf), "%s/%s", dir, default_files[i]);
827 + if (stat(buf, &st) < 0)
829 + if (!do_filename(buf, 0))
837 +main(int argc, char **argv)
839 + int opt, all_users = 0;
843 + /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
846 + __progname = ssh_get_progname(argv[0]);
848 + SSLeay_add_all_algorithms();
849 + log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
851 + /* We don't need the RNG ourselves, but symbol references here allow
852 + * ld to link us properly.
857 + while ((opt = getopt(argc, argv, "ahq")) != -1) {
877 + while ((pw = getpwent()) != NULL) {
879 + if (!do_user(pw->pw_dir))
883 + } else if (optind == argc) {
889 + if ((pw = getpwuid(getuid())) == NULL)
890 + fprintf(stderr, "No user found with uid %u\n",
893 + if (!do_user(pw->pw_dir))
897 + while (optind < argc)
898 + if (!do_filename(argv[optind++], 0))
904 --- openssh-4.7p1.orig/auth-rsa.c
905 +++ openssh-4.7p1/auth-rsa.c
907 #include "servconf.h"
909 #include "hostfile.h"
910 +#include "authfile.h"
920 /* Skip leading whitespace, empty and comment lines. */
921 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
923 "actual %d vs. announced %d.",
924 file, linenum, BN_num_bits(key->rsa->n), bits);
926 + if (blacklisted_key(key)) {
927 + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
928 + if (options.permit_blacklisted_keys)
929 + logit("Public key %s blacklisted (see "
930 + "ssh-vulnkey(1)); continuing anyway", fp);
932 + logit("Public key %s blacklisted (see "
933 + "ssh-vulnkey(1))", fp);
935 + if (!options.permit_blacklisted_keys)
939 /* We have found the desired key. */
941 * If our options do not allow this key to be used,
942 --- openssh-4.7p1.orig/pathnames.h
943 +++ openssh-4.7p1/pathnames.h
945 /* Backwards compatibility */
946 #define _PATH_DH_PRIMES SSHDIR "/primes"
948 +#define _PATH_BLACKLIST SSHDIR "/blacklist"
950 #ifndef _PATH_SSH_PROGRAM
951 #define _PATH_SSH_PROGRAM "/usr/bin/ssh"
953 --- openssh-5.9p1/auth2-pubkey.c~ 2011-09-29 00:36:17.000000000 +0300
954 +++ openssh-5.9p1/auth2-pubkey.c 2011-09-29 00:37:17.847762648 +0300
958 #include "hostfile.h"
959 +#include "authfile.h"
961 #include "pathnames.h"
965 user_key_allowed(struct passwd *pw, Key *key)
971 + if (blacklisted_key(key)) {
972 + fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
973 + if (options.permit_blacklisted_keys)
974 + logit("Public key %s blacklisted (see "
975 + "ssh-vulnkey(1)); continuing anyway", fp);
977 + logit("Public key %s blacklisted (see "
978 + "ssh-vulnkey(1))", fp);
980 + if (!options.permit_blacklisted_keys)
984 #ifdef WITH_AUTHORIZED_KEYS_COMMAND
985 success = user_key_via_command_allowed2(pw, key);