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 735c64780..0d837b9bd 100644 --- a/authfile.c +++ b/authfile.c | |||
@@ -65,6 +65,7 @@ | |||
65 | #include "rsa.h" | 65 | #include "rsa.h" |
66 | #include "misc.h" | 66 | #include "misc.h" |
67 | #include "atomicio.h" | 67 | #include "atomicio.h" |
68 | #include "pathnames.h" | ||
68 | 69 | ||
69 | /* Version identification string for SSH v1 identity files. */ | 70 | /* Version identification string for SSH v1 identity files. */ |
70 | static const char authfile_id_string[] = | 71 | static const char authfile_id_string[] = |
@@ -677,3 +678,140 @@ key_load_public(const char *filename, char **commentp) | |||
677 | key_free(pub); | 678 | key_free(pub); |
678 | return NULL; | 679 | return NULL; |
679 | } | 680 | } |
681 | |||
682 | /* Scan a blacklist of known-vulnerable keys in blacklist_file. */ | ||
683 | static int | ||
684 | blacklisted_key_in_file(const Key *key, const char *blacklist_file, char **fp) | ||
685 | { | ||
686 | int fd = -1; | ||
687 | char *dgst_hex = NULL; | ||
688 | char *dgst_packed = NULL, *p; | ||
689 | int i; | ||
690 | size_t line_len; | ||
691 | struct stat st; | ||
692 | char buf[256]; | ||
693 | off_t start, lower, upper; | ||
694 | int ret = 0; | ||
695 | |||
696 | debug("Checking blacklist file %s", blacklist_file); | ||
697 | fd = open(blacklist_file, O_RDONLY); | ||
698 | if (fd < 0) { | ||
699 | ret = -1; | ||
700 | goto out; | ||
701 | } | ||
702 | |||
703 | dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); | ||
704 | /* Remove all colons */ | ||
705 | dgst_packed = xcalloc(1, strlen(dgst_hex) + 1); | ||
706 | for (i = 0, p = dgst_packed; dgst_hex[i]; i++) | ||
707 | if (dgst_hex[i] != ':') | ||
708 | *p++ = dgst_hex[i]; | ||
709 | /* Only compare least-significant 80 bits (to keep the blacklist | ||
710 | * size down) | ||
711 | */ | ||
712 | line_len = strlen(dgst_packed + 12); | ||
713 | if (line_len > 32) | ||
714 | goto out; | ||
715 | |||
716 | /* Skip leading comments */ | ||
717 | start = 0; | ||
718 | for (;;) { | ||
719 | ssize_t r; | ||
720 | char *newline; | ||
721 | |||
722 | r = atomicio(read, fd, buf, sizeof(buf)); | ||
723 | if (r <= 0) | ||
724 | goto out; | ||
725 | if (buf[0] != '#') | ||
726 | break; | ||
727 | |||
728 | newline = memchr(buf, '\n', sizeof(buf)); | ||
729 | if (!newline) | ||
730 | goto out; | ||
731 | start += newline + 1 - buf; | ||
732 | if (lseek(fd, start, SEEK_SET) < 0) | ||
733 | goto out; | ||
734 | } | ||
735 | |||
736 | /* Initialise binary search record numbers */ | ||
737 | if (fstat(fd, &st) < 0) | ||
738 | goto out; | ||
739 | lower = 0; | ||
740 | upper = (st.st_size - start) / (line_len + 1); | ||
741 | |||
742 | while (lower != upper) { | ||
743 | off_t cur; | ||
744 | int cmp; | ||
745 | |||
746 | cur = lower + (upper - lower) / 2; | ||
747 | |||
748 | /* Read this line and compare to digest; this is | ||
749 | * overflow-safe since cur < max(off_t) / (line_len + 1) */ | ||
750 | if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0) | ||
751 | break; | ||
752 | if (atomicio(read, fd, buf, line_len) != line_len) | ||
753 | break; | ||
754 | cmp = memcmp(buf, dgst_packed + 12, line_len); | ||
755 | if (cmp < 0) { | ||
756 | if (cur == lower) | ||
757 | break; | ||
758 | lower = cur; | ||
759 | } else if (cmp > 0) { | ||
760 | if (cur == upper) | ||
761 | break; | ||
762 | upper = cur; | ||
763 | } else { | ||
764 | debug("Found %s in blacklist", dgst_hex); | ||
765 | ret = 1; | ||
766 | break; | ||
767 | } | ||
768 | } | ||
769 | |||
770 | out: | ||
771 | if (dgst_packed) | ||
772 | xfree(dgst_packed); | ||
773 | if (ret != 1 && dgst_hex) { | ||
774 | xfree(dgst_hex); | ||
775 | dgst_hex = NULL; | ||
776 | } | ||
777 | if (fp) | ||
778 | *fp = dgst_hex; | ||
779 | if (fd >= 0) | ||
780 | close(fd); | ||
781 | return ret; | ||
782 | } | ||
783 | |||
784 | /* | ||
785 | * Scan blacklists of known-vulnerable keys. If a vulnerable key is found, | ||
786 | * its fingerprint is returned in *fp, unless fp is NULL. | ||
787 | */ | ||
788 | int | ||
789 | blacklisted_key(const Key *key, char **fp) | ||
790 | { | ||
791 | Key *public; | ||
792 | char *blacklist_file; | ||
793 | int ret, ret2; | ||
794 | |||
795 | public = key_demote(key); | ||
796 | if (public->type == KEY_RSA1) | ||
797 | public->type = KEY_RSA; | ||
798 | |||
799 | xasprintf(&blacklist_file, "%s.%s-%u", | ||
800 | _PATH_BLACKLIST, key_type(public), key_size(public)); | ||
801 | ret = blacklisted_key_in_file(public, blacklist_file, fp); | ||
802 | xfree(blacklist_file); | ||
803 | if (ret > 0) { | ||
804 | key_free(public); | ||
805 | return ret; | ||
806 | } | ||
807 | |||
808 | xasprintf(&blacklist_file, "%s.%s-%u", | ||
809 | _PATH_BLACKLIST_CONFIG, key_type(public), key_size(public)); | ||
810 | ret2 = blacklisted_key_in_file(public, blacklist_file, fp); | ||
811 | xfree(blacklist_file); | ||
812 | if (ret2 > ret) | ||
813 | ret = ret2; | ||
814 | |||
815 | key_free(public); | ||
816 | return ret; | ||
817 | } | ||