diff options
Diffstat (limited to 'authfile.c')
-rw-r--r-- | authfile.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/authfile.c b/authfile.c index 735c64780..5348a014d 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,113 @@ 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 | char * | ||
683 | blacklist_filename(const Key *key) | ||
684 | { | ||
685 | char *name; | ||
686 | |||
687 | xasprintf(&name, "%s.%s-%u", | ||
688 | _PATH_BLACKLIST, key_type(key), key_size(key)); | ||
689 | return name; | ||
690 | } | ||
691 | |||
692 | /* Scan a blacklist of known-vulnerable keys. */ | ||
693 | int | ||
694 | blacklisted_key(const Key *key) | ||
695 | { | ||
696 | char *blacklist_file; | ||
697 | int fd = -1; | ||
698 | char *dgst_hex = NULL; | ||
699 | char *dgst_packed = NULL, *p; | ||
700 | int i; | ||
701 | size_t line_len; | ||
702 | struct stat st; | ||
703 | char buf[256]; | ||
704 | off_t start, lower, upper; | ||
705 | int ret = 0; | ||
706 | |||
707 | blacklist_file = blacklist_filename(key); | ||
708 | debug("Checking blacklist file %s", blacklist_file); | ||
709 | fd = open(blacklist_file, O_RDONLY); | ||
710 | if (fd < 0) | ||
711 | goto out; | ||
712 | |||
713 | dgst_hex = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); | ||
714 | /* Remove all colons */ | ||
715 | dgst_packed = xcalloc(1, strlen(dgst_hex) + 1); | ||
716 | for (i = 0, p = dgst_packed; dgst_hex[i]; i++) | ||
717 | if (dgst_hex[i] != ':') | ||
718 | *p++ = dgst_hex[i]; | ||
719 | /* Only compare least-significant 80 bits (to keep the blacklist | ||
720 | * size down) | ||
721 | */ | ||
722 | line_len = strlen(dgst_packed + 12); | ||
723 | if (line_len > 32) | ||
724 | goto out; | ||
725 | |||
726 | /* Skip leading comments */ | ||
727 | start = 0; | ||
728 | for (;;) { | ||
729 | ssize_t r; | ||
730 | char *newline; | ||
731 | |||
732 | r = atomicio(read, fd, buf, 256); | ||
733 | if (r <= 0) | ||
734 | goto out; | ||
735 | if (buf[0] != '#') | ||
736 | break; | ||
737 | |||
738 | newline = memchr(buf, '\n', 256); | ||
739 | if (!newline) | ||
740 | goto out; | ||
741 | start += newline + 1 - buf; | ||
742 | if (lseek(fd, start, SEEK_SET) < 0) | ||
743 | goto out; | ||
744 | } | ||
745 | |||
746 | /* Initialise binary search record numbers */ | ||
747 | if (fstat(fd, &st) < 0) | ||
748 | goto out; | ||
749 | lower = 0; | ||
750 | upper = (st.st_size - start) / (line_len + 1); | ||
751 | |||
752 | while (lower != upper) { | ||
753 | off_t cur; | ||
754 | char buf[32]; | ||
755 | int cmp; | ||
756 | |||
757 | cur = lower + (upper - lower) / 2; | ||
758 | |||
759 | /* Read this line and compare to digest; this is | ||
760 | * overflow-safe since cur < max(off_t) / (line_len + 1) */ | ||
761 | if (lseek(fd, start + cur * (line_len + 1), SEEK_SET) < 0) | ||
762 | break; | ||
763 | if (atomicio(read, fd, buf, line_len) != line_len) | ||
764 | break; | ||
765 | cmp = memcmp(buf, dgst_packed + 12, line_len); | ||
766 | if (cmp < 0) { | ||
767 | if (cur == lower) | ||
768 | break; | ||
769 | lower = cur; | ||
770 | } else if (cmp > 0) { | ||
771 | if (cur == upper) | ||
772 | break; | ||
773 | upper = cur; | ||
774 | } else { | ||
775 | debug("Found %s in blacklist", dgst_hex); | ||
776 | ret = 1; | ||
777 | break; | ||
778 | } | ||
779 | } | ||
780 | |||
781 | out: | ||
782 | if (dgst_packed) | ||
783 | xfree(dgst_packed); | ||
784 | if (dgst_hex) | ||
785 | xfree(dgst_hex); | ||
786 | if (fd >= 0) | ||
787 | close(fd); | ||
788 | xfree(blacklist_file); | ||
789 | return ret; | ||
790 | } | ||