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 2bd887845..deac28f6a 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[] = |
@@ -814,3 +815,140 @@ key_in_file(Key *key, const char *filename, int strict_type) | |||
814 | return ret; | 815 | return ret; |
815 | } | 816 | } |
816 | 817 | ||
818 | /* Scan a blacklist of known-vulnerable keys in blacklist_file. */ | ||
819 | static int | ||
820 | blacklisted_key_in_file(const Key *key, const char *blacklist_file, char **fp) | ||
821 | { | ||
822 | int fd = -1; | ||
823 | char *dgst_hex = NULL; | ||
824 | char *dgst_packed = NULL, *p; | ||
825 | int i; | ||
826 | size_t line_len; | ||
827 | struct stat st; | ||
828 | char buf[256]; | ||
829 | off_t start, lower, upper; | ||
830 | int ret = 0; | ||
831 | |||
832 | debug("Checking blacklist file %s", blacklist_file); | ||
833 | fd = open(blacklist_file, O_RDONLY); | ||
834 | if (fd < 0) { | ||
835 | ret = -1; | ||
836 | goto out; | ||
837 | } | ||
838 | |||
839 | dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); | ||
840 | /* Remove all colons */ | ||
841 | dgst_packed = xcalloc(1, strlen(dgst_hex) + 1); | ||
842 | for (i = 0, p = dgst_packed; dgst_hex[i]; i++) | ||
843 | if (dgst_hex[i] != ':') | ||
844 | *p++ = dgst_hex[i]; | ||
845 | /* Only compare least-significant 80 bits (to keep the blacklist | ||
846 | * size down) | ||
847 | */ | ||
848 | line_len = strlen(dgst_packed + 12); | ||
849 | if (line_len > 32) | ||
850 | goto out; | ||
851 | |||
852 | /* Skip leading comments */ | ||
853 | start = 0; | ||
854 | for (;;) { | ||
855 | ssize_t r; | ||
856 | char *newline; | ||
857 | |||
858 | r = atomicio(read, fd, buf, sizeof(buf)); | ||
859 | if (r <= 0) | ||
860 | goto out; | ||
861 | if (buf[0] != '#') | ||
862 | break; | ||
863 | |||
864 | newline = memchr(buf, '\n', sizeof(buf)); | ||
865 | if (!newline) | ||
866 | goto out; | ||
867 | start += newline + 1 - buf; | ||
868 | if (lseek(fd, start, SEEK_SET) < 0) | ||
869 | goto out; | ||
870 | } | ||
871 | |||
872 | /* Initialise binary search record numbers */ | ||
873 | if (fstat(fd, &st) < 0) | ||
874 | goto out; | ||
875 | lower = 0; | ||
876 | upper = (st.st_size - start) / (line_len + 1); | ||
877 | |||
878 | while (lower != upper) { | ||
879 | off_t cur; | ||
880 | int cmp; | ||
881 | |||
882 | cur = lower + (upper - lower) / 2; | ||
883 | |||
884 | /* Read this line and compare to digest; this is | ||
885 | * overflow-safe since cur < max(off_t) / (line_len + 1) */ | ||
886 | if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0) | ||
887 | break; | ||
888 | if (atomicio(read, fd, buf, line_len) != line_len) | ||
889 | break; | ||
890 | cmp = memcmp(buf, dgst_packed + 12, line_len); | ||
891 | if (cmp < 0) { | ||
892 | if (cur == lower) | ||
893 | break; | ||
894 | lower = cur; | ||
895 | } else if (cmp > 0) { | ||
896 | if (cur == upper) | ||
897 | break; | ||
898 | upper = cur; | ||
899 | } else { | ||
900 | debug("Found %s in blacklist", dgst_hex); | ||
901 | ret = 1; | ||
902 | break; | ||
903 | } | ||
904 | } | ||
905 | |||
906 | out: | ||
907 | if (dgst_packed) | ||
908 | xfree(dgst_packed); | ||
909 | if (ret != 1 && dgst_hex) { | ||
910 | xfree(dgst_hex); | ||
911 | dgst_hex = NULL; | ||
912 | } | ||
913 | if (fp) | ||
914 | *fp = dgst_hex; | ||
915 | if (fd >= 0) | ||
916 | close(fd); | ||
917 | return ret; | ||
918 | } | ||
919 | |||
920 | /* | ||
921 | * Scan blacklists of known-vulnerable keys. If a vulnerable key is found, | ||
922 | * its fingerprint is returned in *fp, unless fp is NULL. | ||
923 | */ | ||
924 | int | ||
925 | blacklisted_key(const Key *key, char **fp) | ||
926 | { | ||
927 | Key *public; | ||
928 | char *blacklist_file; | ||
929 | int ret, ret2; | ||
930 | |||
931 | public = key_demote(key); | ||
932 | if (public->type == KEY_RSA1) | ||
933 | public->type = KEY_RSA; | ||
934 | |||
935 | xasprintf(&blacklist_file, "%s.%s-%u", | ||
936 | _PATH_BLACKLIST, key_type(public), key_size(public)); | ||
937 | ret = blacklisted_key_in_file(public, blacklist_file, fp); | ||
938 | xfree(blacklist_file); | ||
939 | if (ret > 0) { | ||
940 | key_free(public); | ||
941 | return ret; | ||
942 | } | ||
943 | |||
944 | xasprintf(&blacklist_file, "%s.%s-%u", | ||
945 | _PATH_BLACKLIST_CONFIG, key_type(public), key_size(public)); | ||
946 | ret2 = blacklisted_key_in_file(public, blacklist_file, fp); | ||
947 | xfree(blacklist_file); | ||
948 | if (ret2 > ret) | ||
949 | ret = ret2; | ||
950 | |||
951 | key_free(public); | ||
952 | return ret; | ||
953 | } | ||
954 | |||