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 224c6aa80..4d0823209 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[] = |
@@ -754,3 +755,140 @@ key_in_file(Key *key, const char *filename, int strict_type) | |||
754 | return ret; | 755 | return ret; |
755 | } | 756 | } |
756 | 757 | ||
758 | /* Scan a blacklist of known-vulnerable keys in blacklist_file. */ | ||
759 | static int | ||
760 | blacklisted_key_in_file(const Key *key, const char *blacklist_file, char **fp) | ||
761 | { | ||
762 | int fd = -1; | ||
763 | char *dgst_hex = NULL; | ||
764 | char *dgst_packed = NULL, *p; | ||
765 | int i; | ||
766 | size_t line_len; | ||
767 | struct stat st; | ||
768 | char buf[256]; | ||
769 | off_t start, lower, upper; | ||
770 | int ret = 0; | ||
771 | |||
772 | debug("Checking blacklist file %s", blacklist_file); | ||
773 | fd = open(blacklist_file, O_RDONLY); | ||
774 | if (fd < 0) { | ||
775 | ret = -1; | ||
776 | goto out; | ||
777 | } | ||
778 | |||
779 | dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); | ||
780 | /* Remove all colons */ | ||
781 | dgst_packed = xcalloc(1, strlen(dgst_hex) + 1); | ||
782 | for (i = 0, p = dgst_packed; dgst_hex[i]; i++) | ||
783 | if (dgst_hex[i] != ':') | ||
784 | *p++ = dgst_hex[i]; | ||
785 | /* Only compare least-significant 80 bits (to keep the blacklist | ||
786 | * size down) | ||
787 | */ | ||
788 | line_len = strlen(dgst_packed + 12); | ||
789 | if (line_len > 32) | ||
790 | goto out; | ||
791 | |||
792 | /* Skip leading comments */ | ||
793 | start = 0; | ||
794 | for (;;) { | ||
795 | ssize_t r; | ||
796 | char *newline; | ||
797 | |||
798 | r = atomicio(read, fd, buf, sizeof(buf)); | ||
799 | if (r <= 0) | ||
800 | goto out; | ||
801 | if (buf[0] != '#') | ||
802 | break; | ||
803 | |||
804 | newline = memchr(buf, '\n', sizeof(buf)); | ||
805 | if (!newline) | ||
806 | goto out; | ||
807 | start += newline + 1 - buf; | ||
808 | if (lseek(fd, start, SEEK_SET) < 0) | ||
809 | goto out; | ||
810 | } | ||
811 | |||
812 | /* Initialise binary search record numbers */ | ||
813 | if (fstat(fd, &st) < 0) | ||
814 | goto out; | ||
815 | lower = 0; | ||
816 | upper = (st.st_size - start) / (line_len + 1); | ||
817 | |||
818 | while (lower != upper) { | ||
819 | off_t cur; | ||
820 | int cmp; | ||
821 | |||
822 | cur = lower + (upper - lower) / 2; | ||
823 | |||
824 | /* Read this line and compare to digest; this is | ||
825 | * overflow-safe since cur < max(off_t) / (line_len + 1) */ | ||
826 | if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0) | ||
827 | break; | ||
828 | if (atomicio(read, fd, buf, line_len) != line_len) | ||
829 | break; | ||
830 | cmp = memcmp(buf, dgst_packed + 12, line_len); | ||
831 | if (cmp < 0) { | ||
832 | if (cur == lower) | ||
833 | break; | ||
834 | lower = cur; | ||
835 | } else if (cmp > 0) { | ||
836 | if (cur == upper) | ||
837 | break; | ||
838 | upper = cur; | ||
839 | } else { | ||
840 | debug("Found %s in blacklist", dgst_hex); | ||
841 | ret = 1; | ||
842 | break; | ||
843 | } | ||
844 | } | ||
845 | |||
846 | out: | ||
847 | if (dgst_packed) | ||
848 | xfree(dgst_packed); | ||
849 | if (ret != 1 && dgst_hex) { | ||
850 | xfree(dgst_hex); | ||
851 | dgst_hex = NULL; | ||
852 | } | ||
853 | if (fp) | ||
854 | *fp = dgst_hex; | ||
855 | if (fd >= 0) | ||
856 | close(fd); | ||
857 | return ret; | ||
858 | } | ||
859 | |||
860 | /* | ||
861 | * Scan blacklists of known-vulnerable keys. If a vulnerable key is found, | ||
862 | * its fingerprint is returned in *fp, unless fp is NULL. | ||
863 | */ | ||
864 | int | ||
865 | blacklisted_key(const Key *key, char **fp) | ||
866 | { | ||
867 | Key *public; | ||
868 | char *blacklist_file; | ||
869 | int ret, ret2; | ||
870 | |||
871 | public = key_demote(key); | ||
872 | if (public->type == KEY_RSA1) | ||
873 | public->type = KEY_RSA; | ||
874 | |||
875 | xasprintf(&blacklist_file, "%s.%s-%u", | ||
876 | _PATH_BLACKLIST, key_type(public), key_size(public)); | ||
877 | ret = blacklisted_key_in_file(public, blacklist_file, fp); | ||
878 | xfree(blacklist_file); | ||
879 | if (ret > 0) { | ||
880 | key_free(public); | ||
881 | return ret; | ||
882 | } | ||
883 | |||
884 | xasprintf(&blacklist_file, "%s.%s-%u", | ||
885 | _PATH_BLACKLIST_CONFIG, key_type(public), key_size(public)); | ||
886 | ret2 = blacklisted_key_in_file(public, blacklist_file, fp); | ||
887 | xfree(blacklist_file); | ||
888 | if (ret2 > ret) | ||
889 | ret = ret2; | ||
890 | |||
891 | key_free(public); | ||
892 | return ret; | ||
893 | } | ||
894 | |||