summaryrefslogtreecommitdiff
path: root/authfile.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@ubuntu.com>2014-02-09 16:09:50 +0000
committerColin Watson <cjwatson@debian.org>2014-02-09 16:17:31 +0000
commit8909ff0e3cd07d1b042d1be1c8b8828dbf6c9a83 (patch)
treeebee4092f1411059e34da6f66b4ebd64f4411020 /authfile.c
parent07f2a771c490bd68cd5c5ea9c535705e93bd94f3 (diff)
Reject vulnerable keys to mitigate Debian OpenSSL flaw
In 2008, Debian (and derived distributions such as Ubuntu) shipped an OpenSSL package with a flawed random number generator, causing OpenSSH to generate only a very limited set of keys which were subject to private half precomputation. To mitigate this, this patch checks key authentications against a blacklist of known-vulnerable keys, and adds a new ssh-vulnkey program which can be used to explicitly check keys against that blacklist. See CVE-2008-0166. Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1469 Last-Update: 2013-09-14 Patch-Name: ssh-vulnkey.patch
Diffstat (limited to 'authfile.c')
-rw-r--r--authfile.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/authfile.c b/authfile.c
index 63ae16bbd..983359157 100644
--- a/authfile.c
+++ b/authfile.c
@@ -68,6 +68,7 @@
68#include "rsa.h" 68#include "rsa.h"
69#include "misc.h" 69#include "misc.h"
70#include "atomicio.h" 70#include "atomicio.h"
71#include "pathnames.h"
71 72
72#define MAX_KEY_FILE_SIZE (1024 * 1024) 73#define MAX_KEY_FILE_SIZE (1024 * 1024)
73 74
@@ -944,3 +945,138 @@ key_in_file(Key *key, const char *filename, int strict_type)
944 return ret; 945 return ret;
945} 946}
946 947
948/* Scan a blacklist of known-vulnerable keys in blacklist_file. */
949static int
950blacklisted_key_in_file(Key *key, const char *blacklist_file, char **fp)
951{
952 int fd = -1;
953 char *dgst_hex = NULL;
954 char *dgst_packed = NULL, *p;
955 int i;
956 size_t line_len;
957 struct stat st;
958 char buf[256];
959 off_t start, lower, upper;
960 int ret = 0;
961
962 debug("Checking blacklist file %s", blacklist_file);
963 fd = open(blacklist_file, O_RDONLY);
964 if (fd < 0) {
965 ret = -1;
966 goto out;
967 }
968
969 dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
970 /* Remove all colons */
971 dgst_packed = xcalloc(1, strlen(dgst_hex) + 1);
972 for (i = 0, p = dgst_packed; dgst_hex[i]; i++)
973 if (dgst_hex[i] != ':')
974 *p++ = dgst_hex[i];
975 /* Only compare least-significant 80 bits (to keep the blacklist
976 * size down)
977 */
978 line_len = strlen(dgst_packed + 12);
979 if (line_len > 32)
980 goto out;
981
982 /* Skip leading comments */
983 start = 0;
984 for (;;) {
985 ssize_t r;
986 char *newline;
987
988 r = atomicio(read, fd, buf, sizeof(buf));
989 if (r <= 0)
990 goto out;
991 if (buf[0] != '#')
992 break;
993
994 newline = memchr(buf, '\n', sizeof(buf));
995 if (!newline)
996 goto out;
997 start += newline + 1 - buf;
998 if (lseek(fd, start, SEEK_SET) < 0)
999 goto out;
1000 }
1001
1002 /* Initialise binary search record numbers */
1003 if (fstat(fd, &st) < 0)
1004 goto out;
1005 lower = 0;
1006 upper = (st.st_size - start) / (line_len + 1);
1007
1008 while (lower != upper) {
1009 off_t cur;
1010 int cmp;
1011
1012 cur = lower + (upper - lower) / 2;
1013
1014 /* Read this line and compare to digest; this is
1015 * overflow-safe since cur < max(off_t) / (line_len + 1) */
1016 if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0)
1017 break;
1018 if (atomicio(read, fd, buf, line_len) != line_len)
1019 break;
1020 cmp = memcmp(buf, dgst_packed + 12, line_len);
1021 if (cmp < 0) {
1022 if (cur == lower)
1023 break;
1024 lower = cur;
1025 } else if (cmp > 0) {
1026 if (cur == upper)
1027 break;
1028 upper = cur;
1029 } else {
1030 debug("Found %s in blacklist", dgst_hex);
1031 ret = 1;
1032 break;
1033 }
1034 }
1035
1036out:
1037 free(dgst_packed);
1038 if (ret != 1 && dgst_hex) {
1039 free(dgst_hex);
1040 dgst_hex = NULL;
1041 }
1042 if (fp)
1043 *fp = dgst_hex;
1044 if (fd >= 0)
1045 close(fd);
1046 return ret;
1047}
1048
1049/*
1050 * Scan blacklists of known-vulnerable keys. If a vulnerable key is found,
1051 * its fingerprint is returned in *fp, unless fp is NULL.
1052 */
1053int
1054blacklisted_key(Key *key, char **fp)
1055{
1056 Key *public;
1057 char *blacklist_file;
1058 int ret, ret2;
1059
1060 public = key_demote(key);
1061 if (public->type == KEY_RSA1)
1062 public->type = KEY_RSA;
1063
1064 xasprintf(&blacklist_file, "%s.%s-%u",
1065 _PATH_BLACKLIST, key_type(public), key_size(public));
1066 ret = blacklisted_key_in_file(public, blacklist_file, fp);
1067 free(blacklist_file);
1068 if (ret > 0) {
1069 key_free(public);
1070 return ret;
1071 }
1072
1073 xasprintf(&blacklist_file, "%s.%s-%u",
1074 _PATH_BLACKLIST_CONFIG, key_type(public), key_size(public));
1075 ret2 = blacklisted_key_in_file(public, blacklist_file, fp);
1076 free(blacklist_file);
1077 if (ret2 > ret)
1078 ret = ret2;
1079
1080 key_free(public);
1081 return ret;
1082}