]> git.pld-linux.org Git - packages/openssh.git/blame - openssh-blacklist.diff
- up to 5.5p1
[packages/openssh.git] / openssh-blacklist.diff
CommitLineData
a66b6504
JK
1This patch is against OpenSSH 4.7p1, although should apply to other versions
2without too much difficulty. It makes the following changes:
3
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.
7
8 * Add a new program, ssh-vulnkey, which can be used to check keys against
9 these blacklists.
10
11This patch is up to date with respect to Debian openssh 1:4.7p1-10.
12
13--- openssh-4.7p1.orig/sshd_config.5
14+++ openssh-4.7p1/sshd_config.5
15@@ -615,6 +615,20 @@
16 Specifies whether password authentication is allowed.
17 The default is
18 .Dq yes .
19+.It Cm PermitBlacklistedKeys
20+Specifies whether
21+.Xr sshd 8
22+should allow keys recorded in its blacklist of known-compromised keys (see
23+.Xr ssh-vulnkey 1 ) .
24+If
25+.Dq yes ,
26+then attempts to authenticate with compromised keys will be logged but
27+accepted.
28+If
29+.Dq no ,
30+then attempts to authenticate with compromised keys will be rejected.
31+The default is
32+.Dq no .
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 @@
39
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)) {
43+ char *fp;
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);
48+ else
49+ error("Host key %s blacklisted (see "
50+ "ssh-vulnkey(1))", fp);
51+ xfree(fp);
52+ if (!options.permit_blacklisted_keys) {
53+ sensitive_data.host_keys[i] = NULL;
54+ continue;
55+ }
56+ }
57 sensitive_data.host_keys[i] = key;
58 if (key == NULL) {
59 error("Could not load host key: %s",
60--- openssh-4.7p1.orig/servconf.c
61+++ openssh-4.7p1/servconf.c
62@@ -96,6 +96,7 @@
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;
70@@ -218,6 +219,8 @@
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)
79@@ -287,7 +290,7 @@
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,
88@@ -387,6 +390,7 @@
89 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
90 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
91 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
92+ { "permitblacklistedkeys", sPermitBlacklistedKeys, SSHCFG_GLOBAL },
898e7d18 93 { "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
a66b6504
JK
94 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
95 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
96@@ -943,6 +947,10 @@
97 intptr = &options->tcp_keep_alive;
98 goto parse_flag;
99
100+ case sPermitBlacklistedKeys:
101+ intptr = &options->permit_blacklisted_keys;
102+ goto parse_flag;
103+
104 case sEmptyPasswd:
105 intptr = &options->permit_empty_passwd;
106 goto parse_flag;
107--- openssh-4.7p1.orig/servconf.h
108+++ openssh-4.7p1/servconf.h
109@@ -94,6 +94,7 @@
6b22dba3 110 * authentication. /
a66b6504
JK
111 int kbd_interactive_authentication; /* If true, permit */
112 int challenge_response_authentication;
113+ int permit_blacklisted_keys; /* If true, permit */
898e7d18
JR
114 int zero_knowledge_password_authentication;
115 /* If true, permit jpake auth */
a66b6504 116 int permit_empty_passwd; /* If false, do not permit empty
a66b6504
JK
117--- openssh-4.7p1.orig/Makefile.in
118+++ openssh-4.7p1/Makefile.in
50835229 119@@ -62,7 +62,7 @@
a66b6504
JK
120 INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@
121 INSTALL_SSH_RAND_HELPER=@INSTALL_SSH_RAND_HELPER@
122
50835229
AM
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) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(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) ssh-rand-helper${EXEEXT} sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-vulnkey$(EXEEXT)
a66b6504
JK
125
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 \
50835229
AM
128@@ -93,8 +93,8 @@
129 audit.o audit-bsm.o platform.o sftp-server.o sftp-common.o \
130 roaming_common.o roaming_serv.o ldapauth.o
a66b6504 131
50835229
AM
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-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.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-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.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-rand-helper.8.out ssh-keysign.8.out ssh-pkcs11-helper.8.out sshd_config.5.out ssh_config.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-rand-helper.8 ssh-keysign.8 ssh-pkcs11-helper.8 sshd_config.5 ssh_config.5 ssh-vulnkey.1
a66b6504
JK
136 MANTYPE = @MANTYPE@
137
138 CONFIGFILES=sshd_config.out ssh_config.out moduli.out
139@@ -165,6 +165,9 @@
140 ssh-rand-helper${EXEEXT}: $(LIBCOMPAT) libssh.a ssh-rand-helper.o
141 $(LD) -o $@ ssh-rand-helper.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
142
143+ssh-vulnkey$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-vulnkey.o
144+ $(LD) -o $@ ssh-vulnkey.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
145+
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)
6b22dba3
AM
149@@ -271,6 +271,7 @@
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)
a66b6504
JK
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
50835229 157@@ -289,6 +289,7 @@
a66b6504
JK
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
50835229 162 $(INSTALL) -m 644 ssh-pkcs11-helper.8.out $(DESTDIR)$(mandir)/$(mansubdir)8/ssh-pkcs11-helper.8
a66b6504 163 -rm -f $(DESTDIR)$(bindir)/slogin
50835229 164 ln -s ./ssh$(EXEEXT) $(DESTDIR)$(bindir)/slogin
a66b6504
JK
165@@ -361,6 +366,7 @@
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)
173@@ -373,6 +379,7 @@
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
183@@ -20,6 +20,7 @@
184 #include <pwd.h>
185 #include <stdarg.h>
186
187+#include "xmalloc.h"
188 #include "packet.h"
189 #include "uidswap.h"
190 #include "log.h"
191@@ -27,6 +28,7 @@
192 #include "servconf.h"
193 #include "key.h"
194 #include "hostfile.h"
195+#include "authfile.h"
196 #include "pathnames.h"
197 #include "auth.h"
198 #include "canohost.h"
199@@ -42,8 +44,22 @@
200 auth_rhosts_rsa_key_allowed(struct passwd *pw, char *cuser, char *chost,
201 Key *client_host_key)
202 {
203+ char *fp;
204 HostStatus host_status;
205
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);
211+ else
212+ logit("Public key %s blacklisted (see "
213+ "ssh-vulnkey(1))", fp);
214+ xfree(fp);
215+ if (!options.permit_blacklisted_keys)
216+ return 0;
217+ }
218+
50835229 219 if (auth_key_is_revoked(client_host_key))
a66b6504 220 return 0;
50835229 221
a66b6504
JK
222--- openssh-4.7p1.orig/authfile.h
223+++ openssh-4.7p1/authfile.h
224@@ -23,4 +23,7 @@
225 Key *key_load_private_pem(int, int, const char *, char **);
226 int key_perm_ok(int, const char *);
227
228+char *blacklist_filename(const Key *key);
229+int blacklisted_key(const Key *key);
230+
231 #endif
232--- openssh-4.7p1.orig/ssh-vulnkey.1
233+++ openssh-4.7p1/ssh-vulnkey.1
234@@ -0,0 +1,187 @@
235+.\" Copyright (c) 2008 Canonical Ltd. All rights reserved.
236+.\"
237+.\" Redistribution and use in source and binary forms, with or without
238+.\" modification, are permitted provided that the following conditions
239+.\" are met:
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.
245+.\"
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.
256+.\"
257+.Dd $Mdocdate: May 12 2008 $
258+.Dt SSH-VULNKEY 1
259+.Os
260+.Sh NAME
261+.Nm ssh-vulnkey
262+.Nd check blacklist of compromised keys
263+.Sh SYNOPSIS
264+.Nm
265+.Op Fl q
266+.Ar file ...
267+.Nm
268+.Fl a
269+.Sh DESCRIPTION
270+.Nm
271+checks a key against a blacklist of compromised keys.
272+.Pp
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
277+compromised.
278+This tool may be useful in checking for such keys.
279+.Pp
280+Keys that are compromised cannot be repaired; replacements must be generated
281+using
282+.Xr ssh-keygen 1 .
283+Make sure to update
284+.Pa authorized_keys
285+files on all systems where compromised keys were permitted to authenticate.
286+.Pp
287+The argument list will be interpreted as a list of paths to public key files
288+or
289+.Pa authorized_keys
290+files.
291+If no suitable file is found at a given path,
292+.Nm
293+will append
294+.Pa .pub
295+and retry, in case it was given a private key file.
296+If no files are given as arguments,
297+.Nm
298+will check
299+.Pa ~/.ssh/id_rsa ,
300+.Pa ~/.ssh/id_dsa ,
301+.Pa ~/.ssh/identity ,
302+.Pa ~/.ssh/authorized_keys
303+and
304+.Pa ~/.ssh/authorized_keys2 ,
305+as well as the system's host keys if readable.
306+.Pp
307+If
308+.Dq -
309+is given as an argument,
310+.Nm
311+will read from standard input.
312+This can be used to process output from
313+.Xr ssh-keyscan 1 ,
314+for example:
315+.Pp
316+.Dl $ ssh-keyscan -t rsa remote.example.org | ssh-vulnkey -
317+.Pp
318+.Nm
319+will exit zero if any of the given keys were in the compromised list,
320+otherwise non-zero.
321+.Pp
322+Unless the
323+.Cm PermitBlacklistedKeys
324+option is used,
325+.Xr sshd 8
326+will reject attempts to authenticate with keys in the compromised list.
327+.Pp
328+The options are as follows:
329+.Bl -tag -width Ds
330+.It Fl a
331+Check keys of all users on the system.
332+You will typically need to run
333+.Nm
334+as root to use this option.
335+For each user,
336+.Nm
337+will check
338+.Pa ~/.ssh/id_rsa ,
339+.Pa ~/.ssh/id_dsa ,
340+.Pa ~/.ssh/identity ,
341+.Pa ~/.ssh/authorized_keys
342+and
343+.Pa ~/.ssh/authorized_keys2 .
344+It will also check the system's host keys.
345+.It Fl q
346+Quiet mode.
347+Normally,
348+.Nm
349+outputs the fingerprint of each key scanned, with a description of its
350+status.
351+This option suppresses that output.
352+.El
353+.Sh BLACKLIST FILE FORMAT
354+The blacklist file may start with comments, on lines starting with
355+.Dq # .
356+After these initial comments, it must follow a strict format:
357+.Pp
358+.Bl -bullet -offset indent -compact
359+.It
360+All the lines must be exactly the same length (20 characters followed by a
361+newline) and must be in sorted order.
362+.It
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).
366+.El
367+.Pp
368+The key fingerprint may be generated using
369+.Xr ssh-keygen 1 :
370+.Pp
371+.Dl $ ssh-keygen -l -f /path/to/key
372+.Pp
373+This strict format is necessary to allow the blacklist file to be checked
374+quickly, using a binary-search algorithm.
375+.Sh FILES
376+.Bl -tag -width Ds
377+.It Pa ~/.ssh/id_rsa
378+If present, contains the protocol version 2 RSA authentication identity of
379+the user.
380+.It Pa ~/.ssh/id_dsa
381+If present, contains the protocol version 2 DSA authentication identity of
382+the user.
383+.It Pa ~/.ssh/identity
384+If present, contains the protocol version 1 RSA authentication identity of
385+the user.
386+.It Pa ~/.ssh/authorized_keys
387+If present, lists the public keys (RSA/DSA) that can be used for logging in
388+as this user.
389+.It Pa ~/.ssh/authorized_keys2
390+Obsolete name for
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
402+.Ar TYPE
403+.Pf ( Dq RSA1 ,
404+.Dq RSA ,
405+or
406+.Dq DSA )
407+and bit length
408+.Ar LENGTH .
409+The format of this file is described above.
410+.El
411+.Sh SEE ALSO
412+.Xr ssh-keygen 1 ,
413+.Xr sshd 8
414+.Sh AUTHORS
415+.An -nosplit
416+.An Colin Watson Aq cjwatson@ubuntu.com
417+.Pp
418+Florian Weimer suggested the option to check keys of all users, and the idea
419+of processing
420+.Xr ssh-keyscan 1
421+output.
422--- openssh-4.7p1.orig/auth2-hostbased.c
423+++ openssh-4.7p1/auth2-hostbased.c
424@@ -40,6 +40,7 @@
425 #include "compat.h"
426 #include "key.h"
427 #include "hostfile.h"
428+#include "authfile.h"
429 #include "auth.h"
430 #include "canohost.h"
431 #ifdef GSSAPI
432@@ -141,10 +142,24 @@
433 hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
434 Key *key)
435 {
436+ char *fp;
437 const char *resolvedname, *ipaddr, *lookup;
438 HostStatus host_status;
439 int len;
440
441+ if (blacklisted_key(key)) {
442+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
443+ if (options.permit_blacklisted_keys)
444+ logit("Public key %s blacklisted (see "
445+ "ssh-vulnkey(1)); continuing anyway", fp);
446+ else
447+ logit("Public key %s blacklisted (see "
448+ "ssh-vulnkey(1))", fp);
449+ xfree(fp);
450+ if (!options.permit_blacklisted_keys)
451+ return 0;
452+ }
453+
50835229
AM
454 if (auth_key_is_revoked(key))
455 return 0;
a66b6504
JK
456
457--- openssh-4.7p1.orig/authfile.c
458+++ openssh-4.7p1/authfile.c
459@@ -65,6 +65,7 @@
460 #include "rsa.h"
461 #include "misc.h"
462 #include "atomicio.h"
463+#include "pathnames.h"
464
465 /* Version identification string for SSH v1 identity files. */
466 static const char authfile_id_string[] =
467@@ -677,3 +678,113 @@
50835229 468 return ret;
a66b6504 469 }
50835229 470
a66b6504
JK
471+
472+char *
473+blacklist_filename(const Key *key)
474+{
475+ char *name;
476+
477+ xasprintf(&name, "%s.%s-%u",
478+ _PATH_BLACKLIST, key_type(key), key_size(key));
479+ return name;
480+}
481+
482+/* Scan a blacklist of known-vulnerable keys. */
483+int
484+blacklisted_key(const Key *key)
485+{
486+ char *blacklist_file;
487+ int fd = -1;
488+ char *dgst_hex = NULL;
489+ char *dgst_packed = NULL, *p;
490+ int i;
491+ size_t line_len;
492+ struct stat st;
493+ char buf[256];
494+ off_t start, lower, upper;
495+ int ret = 0;
496+
497+ blacklist_file = blacklist_filename(key);
498+ debug("Checking blacklist file %s", blacklist_file);
499+ fd = open(blacklist_file, O_RDONLY);
500+ if (fd < 0)
501+ goto out;
502+
503+ dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
504+ /* Remove all colons */
505+ dgst_packed = xcalloc(1, strlen(dgst_hex) + 1);
506+ for (i = 0, p = dgst_packed; dgst_hex[i]; i++)
507+ if (dgst_hex[i] != ':')
508+ *p++ = dgst_hex[i];
509+ /* Only compare least-significant 80 bits (to keep the blacklist
510+ * size down)
511+ */
512+ line_len = strlen(dgst_packed + 12);
513+ if (line_len > 32)
514+ goto out;
515+
516+ /* Skip leading comments */
517+ start = 0;
518+ for (;;) {
519+ ssize_t r;
520+ char *newline;
521+
522+ r = atomicio(read, fd, buf, 256);
523+ if (r <= 0)
524+ goto out;
525+ if (buf[0] != '#')
526+ break;
527+
528+ newline = memchr(buf, '\n', 256);
529+ if (!newline)
530+ goto out;
531+ start += newline + 1 - buf;
532+ if (lseek(fd, start, SEEK_SET) < 0)
533+ goto out;
534+ }
535+
536+ /* Initialise binary search record numbers */
537+ if (fstat(fd, &st) < 0)
538+ goto out;
539+ lower = 0;
540+ upper = (st.st_size - start) / (line_len + 1);
541+
542+ while (lower != upper) {
543+ off_t cur;
544+ char buf[32];
545+ int cmp;
546+
547+ cur = lower + (upper - lower) / 2;
548+
549+ /* Read this line and compare to digest; this is
550+ * overflow-safe since cur < max(off_t) / (line_len + 1) */
551+ if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0)
552+ break;
553+ if (atomicio(read, fd, buf, line_len) != line_len)
554+ break;
555+ cmp = memcmp(buf, dgst_packed + 12, line_len);
556+ if (cmp < 0) {
557+ if (cur == lower)
558+ break;
559+ lower = cur;
560+ } else if (cmp > 0) {
561+ if (cur == upper)
562+ break;
563+ upper = cur;
564+ } else {
565+ debug("Found %s in blacklist", dgst_hex);
566+ ret = 1;
567+ break;
568+ }
569+ }
570+
571+out:
572+ if (dgst_packed)
573+ xfree(dgst_packed);
574+ if (dgst_hex)
575+ xfree(dgst_hex);
576+ if (fd >= 0)
577+ close(fd);
578+ xfree(blacklist_file);
579+ return ret;
580+}
581--- openssh-4.7p1.orig/ssh-vulnkey.c
582+++ openssh-4.7p1/ssh-vulnkey.c
583@@ -0,0 +1,325 @@
584+/*
585+ * Copyright (c) 2008 Canonical Ltd. All rights reserved.
586+ *
587+ * Redistribution and use in source and binary forms, with or without
588+ * modification, are permitted provided that the following conditions
589+ * are met:
590+ * 1. Redistributions of source code must retain the above copyright
591+ * notice, this list of conditions and the following disclaimer.
592+ * 2. Redistributions in binary form must reproduce the above copyright
593+ * notice, this list of conditions and the following disclaimer in the
594+ * documentation and/or other materials provided with the distribution.
595+ *
596+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
597+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
598+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
599+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
600+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
601+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
602+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
603+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
604+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
605+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
606+ */
607+
608+#include "includes.h"
609+
610+#include <sys/types.h>
611+#include <sys/stat.h>
612+
613+#include <string.h>
614+#include <stdio.h>
615+#include <fcntl.h>
616+#include <unistd.h>
617+
618+#include <openssl/evp.h>
619+
620+#include "xmalloc.h"
621+#include "ssh.h"
622+#include "log.h"
623+#include "key.h"
624+#include "authfile.h"
625+#include "pathnames.h"
626+#include "misc.h"
627+
628+extern char *__progname;
629+
630+/* Default files to check */
631+static char *default_host_files[] = {
632+ _PATH_HOST_RSA_KEY_FILE,
633+ _PATH_HOST_DSA_KEY_FILE,
634+ _PATH_HOST_KEY_FILE,
635+ NULL
636+};
637+static char *default_files[] = {
638+ _PATH_SSH_CLIENT_ID_RSA,
639+ _PATH_SSH_CLIENT_ID_DSA,
640+ _PATH_SSH_CLIENT_IDENTITY,
641+ _PATH_SSH_USER_PERMITTED_KEYS,
642+ _PATH_SSH_USER_PERMITTED_KEYS2,
643+ NULL
644+};
645+
646+static int quiet = 0;
647+
648+static void
649+usage(void)
650+{
651+ fprintf(stderr, "usage: %s [-aq] [file ...]\n", __progname);
652+ fprintf(stderr, "Options:\n");
653+ fprintf(stderr, " -a Check keys of all users.\n");
654+ fprintf(stderr, " -q Quiet mode.\n");
655+ exit(1);
656+}
657+
658+void
659+describe_key(const char *msg, const Key *key, const char *comment)
660+{
661+ char *fp;
662+
663+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
664+ if (!quiet)
665+ printf("%s: %u %s %s\n", msg, key_size(key), fp, comment);
666+ xfree(fp);
667+}
668+
669+int
670+do_key(const Key *key, const char *comment)
671+{
672+ char *blacklist_file;
673+ struct stat st;
674+ int ret = 1;
675+
676+ blacklist_file = blacklist_filename(key);
677+ if (stat(blacklist_file, &st) < 0)
678+ describe_key("Unknown (no blacklist information)",
679+ key, comment);
680+ else if (blacklisted_key(key)) {
681+ describe_key("COMPROMISED", key, comment);
682+ ret = 0;
683+ } else
684+ describe_key("Not blacklisted", key, comment);
685+ xfree(blacklist_file);
686+
687+ return ret;
688+}
689+
690+int
691+do_filename(const char *filename, int quiet_open)
692+{
693+ FILE *f;
694+ char line[SSH_MAX_PUBKEY_BYTES];
695+ char *cp;
696+ u_long linenum = 0;
697+ Key *key;
698+ char *comment = NULL;
699+ int found = 0, ret = 1;
700+
701+ /* Copy much of key_load_public's logic here so that we can read
702+ * several keys from a single file (e.g. authorized_keys).
703+ */
704+
705+ if (strcmp(filename, "-") != 0) {
706+ f = fopen(filename, "r");
707+ if (!f) {
708+ char pubfile[MAXPATHLEN];
709+ if (strlcpy(pubfile, filename, sizeof pubfile) <
710+ sizeof(pubfile) &&
711+ strlcat(pubfile, ".pub", sizeof pubfile) <
712+ sizeof(pubfile))
713+ f = fopen(pubfile, "r");
714+ }
715+ if (!f) {
716+ if (!quiet_open)
717+ perror(filename);
718+ return -1;
719+ }
720+ } else
721+ f = stdin;
722+ while (read_keyfile_line(f, filename, line, sizeof(line),
723+ &linenum) != -1) {
724+ int i;
725+ char *space;
726+ int type;
727+
728+ /* Chop trailing newline. */
729+ i = strlen(line) - 1;
730+ if (line[i] == '\n')
731+ line[i] = '\0';
732+
733+ /* Skip leading whitespace, empty and comment lines. */
734+ for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
735+ ;
736+ if (!*cp || *cp == '\n' || *cp == '#')
737+ continue;
738+
739+ /* Cope with ssh-keyscan output and options in
740+ * authorized_keys files.
741+ */
742+ space = strchr(cp, ' ');
743+ if (!space)
744+ continue;
745+ *space = '\0';
746+ type = key_type_from_name(cp);
747+ *space = ' ';
748+ /* Leading number (RSA1) or valid type (RSA/DSA) indicates
749+ * that we have no host name or options to skip.
750+ */
751+ if (atoi(cp) == 0 && type == KEY_UNSPEC) {
752+ int quoted = 0;
753+
754+ for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
755+ if (*cp == '\\' && cp[1] == '"')
756+ cp++; /* Skip both */
757+ else if (*cp == '"')
758+ quoted = !quoted;
759+ }
760+ /* Skip remaining whitespace. */
761+ for (; *cp == ' ' || *cp == '\t'; cp++)
762+ ;
763+ if (!*cp)
764+ continue;
765+ }
766+
767+ /* Read and process the key itself. */
768+ key = key_new(KEY_RSA1);
769+ if (key_read(key, &cp) == 1) {
770+ while (*cp == ' ' || *cp == '\t')
771+ cp++;
772+ if (!do_key(key, *cp ? cp : filename))
773+ ret = 0;
774+ found = 1;
775+ } else {
776+ key_free(key);
777+ key = key_new(KEY_UNSPEC);
778+ if (key_read(key, &cp) == 1) {
779+ while (*cp == ' ' || *cp == '\t')
780+ cp++;
781+ if (!do_key(key, *cp ? cp : filename))
782+ ret = 0;
783+ found = 1;
784+ }
785+ }
786+ key_free(key);
787+ }
788+ if (f != stdin)
789+ fclose(f);
790+
791+ if (!found && filename) {
792+ key = key_load_public(filename, &comment);
793+ if (key) {
794+ if (!do_key(key, comment))
795+ ret = 0;
796+ found = 1;
797+ }
798+ if (comment)
799+ xfree(comment);
800+ }
801+
802+ return ret;
803+}
804+
805+int
806+do_host(void)
807+{
808+ int i;
809+ struct stat st;
810+ int ret = 1;
811+
812+ for (i = 0; default_host_files[i]; i++) {
813+ if (stat(default_host_files[i], &st) < 0)
814+ continue;
815+ if (!do_filename(default_host_files[i], 1))
816+ ret = 0;
817+ }
818+
819+ return ret;
820+}
821+
822+int
823+do_user(const char *dir)
824+{
825+ int i;
826+ char buf[MAXPATHLEN];
827+ struct stat st;
828+ int ret = 1;
829+
830+ for (i = 0; default_files[i]; i++) {
831+ snprintf(buf, sizeof(buf), "%s/%s", dir, default_files[i]);
832+ if (stat(buf, &st) < 0)
833+ continue;
834+ if (!do_filename(buf, 0))
835+ ret = 0;
836+ }
837+
838+ return ret;
839+}
840+
841+int
842+main(int argc, char **argv)
843+{
844+ int opt, all_users = 0;
845+ int ret = 1;
846+ extern int optind;
847+
848+ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
849+ sanitise_stdfd();
850+
851+ __progname = ssh_get_progname(argv[0]);
852+
853+ SSLeay_add_all_algorithms();
854+ log_init(argv[0], SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_USER, 1);
855+
856+ /* We don't need the RNG ourselves, but symbol references here allow
857+ * ld to link us properly.
858+ */
859+ init_rng();
860+ seed_rng();
861+
862+ while ((opt = getopt(argc, argv, "ahq")) != -1) {
863+ switch (opt) {
864+ case 'a':
865+ all_users = 1;
866+ break;
867+ case 'q':
868+ quiet = 1;
869+ break;
870+ case 'h':
871+ default:
872+ usage();
873+ }
874+ }
875+
876+ if (all_users) {
877+ struct passwd *pw;
878+
879+ if (!do_host())
880+ ret = 0;
881+
882+ while ((pw = getpwent()) != NULL) {
883+ if (pw->pw_dir) {
884+ if (!do_user(pw->pw_dir))
885+ ret = 0;
886+ }
887+ }
888+ } else if (optind == argc) {
889+ struct passwd *pw;
890+
891+ if (!do_host())
892+ ret = 0;
893+
894+ if ((pw = getpwuid(getuid())) == NULL)
895+ fprintf(stderr, "No user found with uid %u\n",
896+ (u_int)getuid());
897+ else {
898+ if (!do_user(pw->pw_dir))
899+ ret = 0;
900+ }
901+ } else {
902+ while (optind < argc)
903+ if (!do_filename(argv[optind++], 0))
904+ ret = 0;
905+ }
906+
907+ return ret;
908+}
909--- openssh-4.7p1.orig/auth-rsa.c
910+++ openssh-4.7p1/auth-rsa.c
911@@ -40,6 +40,7 @@
912 #include "servconf.h"
913 #include "key.h"
914 #include "hostfile.h"
915+#include "authfile.h"
916 #include "auth.h"
917 #ifdef GSSAPI
918 #include "ssh-gss.h"
919@@ -221,6 +222,7 @@
920 char *cp;
921 char *key_options;
922 int keybits;
923+ char *fp;
924
925 /* Skip leading whitespace, empty and comment lines. */
926 for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
927@@ -265,6 +267,19 @@
928 "actual %d vs. announced %d.",
929 file, linenum, BN_num_bits(key->rsa->n), bits);
930
931+ if (blacklisted_key(key)) {
932+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
933+ if (options.permit_blacklisted_keys)
934+ logit("Public key %s blacklisted (see "
935+ "ssh-vulnkey(1)); continuing anyway", fp);
936+ else
937+ logit("Public key %s blacklisted (see "
938+ "ssh-vulnkey(1))", fp);
939+ xfree(fp);
940+ if (!options.permit_blacklisted_keys)
941+ continue;
942+ }
943+
944 /* We have found the desired key. */
945 /*
946 * If our options do not allow this key to be used,
947--- openssh-4.7p1.orig/pathnames.h
948+++ openssh-4.7p1/pathnames.h
949@@ -43,6 +43,8 @@
950 /* Backwards compatibility */
951 #define _PATH_DH_PRIMES SSHDIR "/primes"
952
953+#define _PATH_BLACKLIST SSHDIR "/blacklist"
954+
955 #ifndef _PATH_SSH_PROGRAM
956 #define _PATH_SSH_PROGRAM "/usr/bin/ssh"
957 #endif
958--- openssh-4.7p1.orig/auth2-pubkey.c
959+++ openssh-4.7p1/auth2-pubkey.c
960@@ -42,6 +42,7 @@
961 #include "compat.h"
962 #include "key.h"
963 #include "hostfile.h"
964+#include "authfile.h"
965 #include "auth.h"
966 #include "pathnames.h"
967 #include "uidswap.h"
968@@ -269,9 +270,23 @@
969 int
970 user_key_allowed(struct passwd *pw, Key *key)
971 {
972+ char *fp;
973 int success;
974 char *file;
975
976+ if (blacklisted_key(key)) {
977+ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
978+ if (options.permit_blacklisted_keys)
979+ logit("Public key %s blacklisted (see "
980+ "ssh-vulnkey(1)); continuing anyway", fp);
981+ else
982+ logit("Public key %s blacklisted (see "
983+ "ssh-vulnkey(1))", fp);
984+ xfree(fp);
985+ if (!options.permit_blacklisted_keys)
986+ return 0;
987+ }
988+
50835229
AM
989 if (auth_key_is_revoked(key))
990 return 0;
991 if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
This page took 0.172954 seconds and 4 git commands to generate.