diff options
Diffstat (limited to 'authfile.c')
-rw-r--r-- | authfile.c | 138 |
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. */ |
73 | static const char authfile_id_string[] = | 74 | static 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. */ | ||
911 | static int | ||
912 | blacklisted_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 | |||
998 | out: | ||
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 | */ | ||
1016 | int | ||
1017 | blacklisted_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 | |||