1 --- openssh-5.0p1/Makefile.in
2 +++ openssh-5.0p1/Makefile.in
5 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)
7 -LIBSSH_OBJS=acss.o authfd.o authfile.o bufaux.o bufbn.o buffer.o \
8 +LIBSSH_OBJS=acss.o authfd.o authfile.o blacklist.o bufaux.o bufbn.o buffer.o \
9 canohost.o channels.o cipher.o cipher-acss.o cipher-aes.o \
10 cipher-bf1.o cipher-ctr.o cipher-3des1.o cleanup.o \
11 compat.o compress.o crc32.o deattack.o fatal.o hostfile.o \
12 --- openssh-5.0p1/auth-rh-rsa.c
13 +++ openssh-5.0p1/auth-rh-rsa.c
17 #include "monitor_wrap.h"
18 +#include "blacklist.h"
21 extern ServerOptions options;
23 if (!auth_rhosts(pw, cuser))
26 + if (blacklisted_key(client_host_key, 0))
29 host_status = check_key_in_hostfiles(pw, client_host_key,
30 chost, _PATH_SSH_SYSTEM_HOSTFILE,
31 options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE);
32 --- openssh-5.0p1/auth-rsa.c
33 +++ openssh-5.0p1/auth-rsa.c
35 #include "monitor_wrap.h"
38 +#include "blacklist.h"
41 extern ServerOptions options;
43 "actual %d vs. announced %d.",
44 file, linenum, BN_num_bits(key->rsa->n), bits);
46 + if (blacklisted_key(key, 0))
49 /* We have found the desired key. */
51 * If our options do not allow this key to be used,
52 --- openssh-5.0p1/auth2-hostbased.c
53 +++ openssh-5.0p1/auth2-hostbased.c
56 #include "monitor_wrap.h"
57 #include "pathnames.h"
58 +#include "blacklist.h"
61 extern ServerOptions options;
63 HostStatus host_status;
66 + if (blacklisted_key(key, 0))
69 resolvedname = get_canonical_hostname(options.use_dns);
70 ipaddr = get_remote_ipaddr();
72 --- openssh-5.0p1/auth2-pubkey.c
73 +++ openssh-5.0p1/auth2-pubkey.c
76 #include "monitor_wrap.h"
78 +#include "blacklist.h"
81 extern ServerOptions options;
86 + if (blacklisted_key(key, 0))
89 file = authorized_keys_file(pw);
90 success = user_key_allowed2(pw, key, file);
94 +++ openssh-5.0p1/blacklist.c
97 + * Support for RSA/DSA key blacklisting based on partial fingerprints,
98 + * developed under Openwall Project for Owl - http://www.openwall.com/Owl/
100 + * Copyright (c) 2008 Dmitry V. Levin <ldv at cvs.openwall.com>
102 + * Permission to use, copy, modify, and distribute this software for any
103 + * purpose with or without fee is hereby granted, provided that the above
104 + * copyright notice and this permission notice appear in all copies.
106 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
107 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
108 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
109 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
110 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
111 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
112 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
114 + * The blacklist encoding was designed by Solar Designer and Dmitry V. Levin.
115 + * No intellectual property rights to the encoding scheme are claimed.
117 + * This effort was supported by CivicActions - http://www.civicactions.com
119 + * The file size to encode 294,903 of 48-bit fingerprints is just 1.3 MB,
120 + * which corresponds to less than 4.5 bytes per fingerprint.
123 +#include "includes.h"
129 +#include "atomicio.h"
130 +#include "blacklist.h"
131 +#include "canohost.h"
133 +#include "pathnames.h"
134 +#include "servconf.h"
135 +#include "xmalloc.h"
137 +extern ServerOptions options;
141 + /* format version identifier */
143 + /* index size, in bits */
144 + uint8_t index_size;
145 + /* offset size, in bits */
146 + uint8_t offset_size;
147 + /* record size, in bits */
148 + uint8_t record_bits;
149 + /* number of records */
150 + uint8_t records[3];
154 +} __attribute__((packed)) blacklist_header;
159 + return (c >= 'a') ? (c - 'a' + 10) : (c - '0');
162 +static blacklist_error_t
163 +validate_blacklist(const char *fname, int fd, unsigned *bytes,
164 + unsigned *records, unsigned *shift)
168 + blacklist_header header;
170 + if (fstat(fd, &st)) {
171 + error("fstat for blacklist file %s failed: %m", fname);
172 + return BLACKLIST_ERROR_ACCESS;
175 + if (atomicio(read, fd, &header, sizeof(header)) != sizeof(header)) {
176 + error("read blacklist file %s header failed: %m", fname);
177 + return BLACKLIST_ERROR_ACCESS;
180 + if (memcmp(header.version, "SSH-FP", 6)) {
181 + error("blacklist file %s has unrecognized format", fname);
182 + return BLACKLIST_ERROR_FORMAT;
185 + if (header.index_size != 16 || header.offset_size != 16 ||
186 + memcmp(header.version, "SSH-FP00", 8)) {
187 + error("blacklist file %s has unsupported format", fname);
188 + return BLACKLIST_ERROR_VERSION;
191 + *bytes = (header.record_bits >> 3) - 2;
193 + (((header.records[0] << 8) +
194 + header.records[1]) << 8) + header.records[2];
195 + *shift = (header.shift[0] << 8) + header.shift[1];
197 + expected = sizeof(header) + 0x20000 + (*records) * (*bytes);
198 + if (st.st_size != expected) {
199 + error("blacklist file %s size mismatch: "
200 + "expected size %u, found size %lu",
201 + fname, expected, (unsigned long) st.st_size);
202 + return BLACKLIST_ERROR_ACCESS;
205 + return BLACKLIST_ERROR_NONE;
209 +expected_offset(uint16_t index, uint16_t shift, unsigned records)
211 + return ((index * (long long) records) >> 16) - shift;
215 +xlseek(const char *fname, int fd, unsigned seek)
217 + if (lseek(fd, seek, SEEK_SET) != seek) {
218 + error("lseek for blacklist file %s failed: %m", fname);
219 + return BLACKLIST_ERROR_ACCESS;
221 + return BLACKLIST_ERROR_NONE;
224 +static blacklist_error_t
225 +check(const char *fname, int fd, const char *s)
227 + unsigned bytes, records, shift;
228 + unsigned num, i, j;
229 + int off_start, off_end;
230 + blacklist_error_t rc;
232 + /* max number of bytes stored in record_bits, minus two bytes used for index */
233 + uint8_t buf[(0xff >> 3) - 2];
235 + if ((rc = validate_blacklist(fname, fd, &bytes, &records, &shift)))
238 + index = (((((c2u(s[0]) << 4) | c2u(s[1])) << 4) |
239 + c2u(s[2])) << 4) | c2u(s[3]);
240 + if (xlseek(fname, fd, sizeof(blacklist_header) + index * 2))
241 + return BLACKLIST_ERROR_ACCESS;
243 + if (atomicio(read, fd, buf, 4) != 4) {
244 + error("read blacklist file %s offsets failed: %m", fname);
245 + return BLACKLIST_ERROR_ACCESS;
248 + off_start = (buf[0] << 8) + buf[1] +
249 + expected_offset(index, shift, records);
250 + if (off_start < 0 || (unsigned) off_start > records) {
251 + error("blacklist file %s off_start overflow [%d] for index %#x",
252 + fname, off_start, index);
253 + return BLACKLIST_ERROR_ACCESS;
255 + if (index < 0xffff) {
256 + off_end = (buf[2] << 8) + buf[3] +
257 + expected_offset(index + 1, shift, records);
258 + if (off_end < off_start || (unsigned) off_end > records) {
259 + error("blacklist file %s off_end overflow [%d] for index %#x",
260 + fname, off_end, index);
261 + return BLACKLIST_ERROR_ACCESS;
266 + if (xlseek(fname, fd,
267 + sizeof(blacklist_header) + 0x20000 + off_start * bytes))
268 + return BLACKLIST_ERROR_ACCESS;
270 + num = off_end - off_start;
271 + for (i = 0; i < num; ++i) {
272 + if (atomicio(read, fd, buf, bytes) != bytes) {
273 + error("read blacklist file %s fingerprints failed: %m",
275 + return BLACKLIST_ERROR_ACCESS;
278 + for (j = 0; j < bytes; ++j)
279 + if (((c2u(s[4 + j * 2]) << 4) | c2u(s[5 + j * 2])) !=
283 + debug("blacklisted fingerprint: %s offset=%u, number=%u",
285 + return BLACKLIST_ERROR_ALL;
289 + debug("non-blacklisted fingerprint: %s offset=%u, number=%u",
290 + s, off_start, num);
291 + return BLACKLIST_ERROR_NONE;
294 +static blacklist_error_t
295 +blacklisted_fingerprint(const char *hex)
298 + blacklist_error_t rc = BLACKLIST_ERROR_ACCESS;
299 + const char *fname = _PATH_BLACKLIST;
302 + debug("Checking fingerprint %s using blacklist file %s", hex, fname);
305 + for (p = s; *hex; ++hex)
310 + if (strlen(s) != 32 || strlen(s) != strspn(s, "0123456789abcdef")) {
311 + error("%s: invalid fingerprint", s);
315 + if ((fd = open(fname, O_RDONLY)) < 0) {
316 + if (ENOENT == errno) {
317 + rc = BLACKLIST_ERROR_MISSING;
318 + verbose("open blacklist file %s failed: %m", fname);
320 + logit("open blacklist file %s failed: %m", fname);
324 + rc = check(fname, fd, s);
333 +blacklisted_key(Key *key, int hostkey)
337 + char *fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
339 + switch ((rc = blacklisted_fingerprint(fp))) {
340 + case BLACKLIST_ERROR_NONE:
342 + case BLACKLIST_ERROR_ALL:
343 + text = (options.ignore_blacklist_errors == rc) ?
344 + "Permitted" : "Rejected";
346 + logit("%s blacklisted host key %s", text, fp);
348 + logit("%s blacklisted public key %s from %.100s",
349 + text, fp, get_remote_ipaddr());
353 + logit("Unable to check blacklist for host key %s",
356 + logit("Unable to check blacklist for public key %s from %.100s",
357 + fp, get_remote_ipaddr());
361 + return (rc > options.ignore_blacklist_errors);
365 +++ openssh-5.0p1/blacklist.h
368 + * Support for RSA/DSA key blacklisting based on partial fingerprints,
369 + * developed under Openwall Project for Owl - http://www.openwall.com/Owl/
371 + * Copyright (c) 2008 Dmitry V. Levin <ldv at cvs.openwall.com>
373 + * Permission to use, copy, modify, and distribute this software for any
374 + * purpose with or without fee is hereby granted, provided that the above
375 + * copyright notice and this permission notice appear in all copies.
377 + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
378 + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
379 + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
380 + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
381 + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
382 + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
383 + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
386 +#ifndef BLACKLIST_H_
387 +#define BLACKLIST_H_
391 +int blacklisted_key(Key *, int);
395 + BLACKLIST_ERROR_NONE = 0,
396 + BLACKLIST_ERROR_MISSING,
397 + BLACKLIST_ERROR_VERSION,
398 + BLACKLIST_ERROR_FORMAT,
399 + BLACKLIST_ERROR_ACCESS,
400 + BLACKLIST_ERROR_ALL
401 +} blacklist_error_t;
403 +#endif /* BLACKLIST_H_ */
404 --- openssh-5.0p1/pathnames.h
405 +++ openssh-5.0p1/pathnames.h
407 /* Backwards compatibility */
408 #define _PATH_DH_PRIMES SSHDIR "/primes"
410 +#define _PATH_BLACKLIST SSHDIR "/blacklist"
412 #ifndef _PATH_SSH_PROGRAM
413 #define _PATH_SSH_PROGRAM "/usr/bin/ssh"
415 --- openssh-5.0p1/servconf.c
416 +++ openssh-5.0p1/servconf.c
419 #include "channels.h"
420 #include "groupaccess.h"
421 +#include "blacklist.h"
423 static void add_listen_addr(ServerOptions *, char *, u_short);
424 static void add_one_listen_addr(ServerOptions *, char *, u_short);
426 options->password_authentication = -1;
427 options->kbd_interactive_authentication = -1;
428 options->challenge_response_authentication = -1;
429 + options->ignore_blacklist_errors = -1;
430 options->permit_empty_passwd = -1;
431 options->permit_user_env = -1;
432 options->use_login = -1;
434 options->kbd_interactive_authentication = 0;
435 if (options->challenge_response_authentication == -1)
436 options->challenge_response_authentication = 1;
437 + if (options->ignore_blacklist_errors == -1)
438 + options->ignore_blacklist_errors = BLACKLIST_ERROR_ALL; //VERSION;
439 if (options->permit_empty_passwd == -1)
440 options->permit_empty_passwd = 0;
441 if (options->permit_user_env == -1)
443 sListenAddress, sAddressFamily,
444 sPrintMotd, sPrintLastLog, sIgnoreRhosts,
445 sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
446 - sStrictModes, sEmptyPasswd, sTCPKeepAlive,
447 + sStrictModes, sIgnoreBlacklistErrors, sEmptyPasswd, sTCPKeepAlive,
448 sPermitUserEnvironment, sUseLogin, sAllowTcpForwarding, sCompression,
449 sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
450 sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
452 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL },
453 { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL },
454 { "strictmodes", sStrictModes, SSHCFG_GLOBAL },
455 + { "ignoreblacklisterrors", sIgnoreBlacklistErrors, SSHCFG_GLOBAL },
456 { "permitemptypasswords", sEmptyPasswd, SSHCFG_GLOBAL },
457 { "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
458 { "uselogin", sUseLogin, SSHCFG_GLOBAL },
460 intptr = &options->tcp_keep_alive;
463 + case sIgnoreBlacklistErrors:
464 + intptr = &options->ignore_blacklist_errors;
465 + arg = strdelim(&cp);
466 + if (!arg || *arg == '\0')
467 + fatal("%s line %d: missing none/missing/version/format/access/all argument.",
468 + filename, linenum);
469 + value = 0; /* silence compiler */
470 + if (strcmp(arg, "none") == 0)
471 + value = BLACKLIST_ERROR_NONE;
472 + else if (strcmp(arg, "missing") == 0)
473 + value = BLACKLIST_ERROR_MISSING;
474 + else if (strcmp(arg, "version") == 0)
475 + value = BLACKLIST_ERROR_VERSION;
476 + else if (strcmp(arg, "format") == 0)
477 + value = BLACKLIST_ERROR_FORMAT;
478 + else if (strcmp(arg, "access") == 0)
479 + value = BLACKLIST_ERROR_ACCESS;
480 + else if (strcmp(arg, "all") == 0)
481 + value = BLACKLIST_ERROR_ALL;
483 + fatal("%s line %d: Bad none/missing/version/format/access/all argument: %s",
484 + filename, linenum, arg);
485 + if (*activep && *intptr == -1)
490 intptr = &options->permit_empty_passwd;
492 --- openssh-5.0p1/servconf.h
493 +++ openssh-5.0p1/servconf.h
496 int kbd_interactive_authentication; /* If true, permit */
497 int challenge_response_authentication;
498 + int ignore_blacklist_errors; /* none/missing/version/format/access/all */
499 int permit_empty_passwd; /* If false, do not permit empty
501 int permit_user_env; /* If true, read ~/.ssh/environment */
502 --- openssh-5.0p1/sshd.c
503 +++ openssh-5.0p1/sshd.c
505 #include "monitor_wrap.h"
506 #include "monitor_fdpass.h"
508 +#include "blacklist.h"
512 @@ -1484,6 +1494,11 @@
513 sensitive_data.host_keys[i] = NULL;
516 + if (blacklisted_key(key, 1)) {
517 + sensitive_data.host_keys[i] = NULL;
523 sensitive_data.ssh1_host_key = key;
524 --- openssh-5.0p1/sshd_config.5
525 +++ openssh-5.0p1/sshd_config.5
527 Specifies whether password authentication is allowed.
530 +.It Cm IgnoreBlacklistErrors
533 +should allow keys recorded in its blacklist of known-compromised keys.
536 +then attempts to authenticate with compromised keys will be logged
540 +then attempts to authenticate with compromised keys will be rejected,
541 +but blacklist file access errors will be ignored.
544 +then attempts to authenticate with compromised keys will be rejected, but
545 +blacklist file access errors due to missing blacklist file or blacklist
546 +file unrecognized format will be ignored.
549 +then attempts to authenticate with compromised keys will be rejected, but
550 +blacklist file access errors due to missing blacklist file or blacklist
551 +file format version mismatch will be ignored.
554 +then attempts to authenticate with compromised keys will be rejected,
555 +but blacklist file access errors due to missing blacklist file will
559 +then attempts to authenticate with compromised keys, or in case of
560 +any blacklist file access error, will be rejected.
563 .It Cm PermitEmptyPasswords
564 When password authentication is allowed, it specifies whether the
565 server allows login to accounts with empty password strings.