summaryrefslogtreecommitdiff
path: root/authfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'authfile.c')
-rw-r--r--authfile.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/authfile.c b/authfile.c
index f2aec267a..be650af67 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/* Version identification string for SSH v1 identity files. */ 73/* Version identification string for SSH v1 identity files. */
73static const char authfile_id_string[] = 74static const char authfile_id_string[] =
@@ -906,3 +907,140 @@ key_in_file(Key *key, const char *filename, int strict_type)
906 return ret; 907 return ret;
907} 908}
908 909
910/* Scan a blacklist of known-vulnerable keys in blacklist_file. */
911static int
912blacklisted_key_in_file(Key *key, const char *blacklist_file, char **fp)
913{
914 int fd = -1;
915 char *dgst_hex = NULL;
916 char *dgst_packed = NULL, *p;
917 int i;
918 size_t line_len;
919 struct stat st;
920 char buf[256];
921 off_t start, lower, upper;
922 int ret = 0;
923
924 debug("Checking blacklist file %s", blacklist_file);
925 fd = open(blacklist_file, O_RDONLY);
926 if (fd < 0) {
927 ret = -1;
928 goto out;
929 }
930
931 dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
932 /* Remove all colons */
933 dgst_packed = xcalloc(1, strlen(dgst_hex) + 1);
934 for (i = 0, p = dgst_packed; dgst_hex[i]; i++)
935 if (dgst_hex[i] != ':')
936 *p++ = dgst_hex[i];
937 /* Only compare least-significant 80 bits (to keep the blacklist
938 * size down)
939 */
940 line_len = strlen(dgst_packed + 12);
941 if (line_len > 32)
942 goto out;
943
944 /* Skip leading comments */
945 start = 0;
946 for (;;) {
947 ssize_t r;
948 char *newline;
949
950 r = atomicio(read, fd, buf, sizeof(buf));
951 if (r <= 0)
952 goto out;
953 if (buf[0] != '#')
954 break;
955
956 newline = memchr(buf, '\n', sizeof(buf));
957 if (!newline)
958 goto out;
959 start += newline + 1 - buf;
960 if (lseek(fd, start, SEEK_SET) < 0)
961 goto out;
962 }
963
964 /* Initialise binary search record numbers */
965 if (fstat(fd, &st) < 0)
966 goto out;
967 lower = 0;
968 upper = (st.st_size - start) / (line_len + 1);
969
970 while (lower != upper) {
971 off_t cur;
972 int cmp;
973
974 cur = lower + (upper - lower) / 2;
975
976 /* Read this line and compare to digest; this is
977 * overflow-safe since cur < max(off_t) / (line_len + 1) */
978 if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0)
979 break;
980 if (atomicio(read, fd, buf, line_len) != line_len)
981 break;
982 cmp = memcmp(buf, dgst_packed + 12, line_len);
983 if (cmp < 0) {
984 if (cur == lower)
985 break;
986 lower = cur;
987 } else if (cmp > 0) {
988 if (cur == upper)
989 break;
990 upper = cur;
991 } else {
992 debug("Found %s in blacklist", dgst_hex);
993 ret = 1;
994 break;
995 }
996 }
997
998out:
999 if (dgst_packed)
1000 xfree(dgst_packed);
1001 if (ret != 1 && dgst_hex) {
1002 xfree(dgst_hex);
1003 dgst_hex = NULL;
1004 }
1005 if (fp)
1006 *fp = dgst_hex;
1007 if (fd >= 0)
1008 close(fd);
1009 return ret;
1010}
1011
1012/*
1013 * Scan blacklists of known-vulnerable keys. If a vulnerable key is found,
1014 * its fingerprint is returned in *fp, unless fp is NULL.
1015 */
1016int
1017blacklisted_key(Key *key, char **fp)
1018{
1019 Key *public;
1020 char *blacklist_file;
1021 int ret, ret2;
1022
1023 public = key_demote(key);
1024 if (public->type == KEY_RSA1)
1025 public->type = KEY_RSA;
1026
1027 xasprintf(&blacklist_file, "%s.%s-%u",
1028 _PATH_BLACKLIST, key_type(public), key_size(public));
1029 ret = blacklisted_key_in_file(public, blacklist_file, fp);
1030 xfree(blacklist_file);
1031 if (ret > 0) {
1032 key_free(public);
1033 return ret;
1034 }
1035
1036 xasprintf(&blacklist_file, "%s.%s-%u",
1037 _PATH_BLACKLIST_CONFIG, key_type(public), key_size(public));
1038 ret2 = blacklisted_key_in_file(public, blacklist_file, fp);
1039 xfree(blacklist_file);
1040 if (ret2 > ret)
1041 ret = ret2;
1042
1043 key_free(public);
1044 return ret;
1045}
1046