summaryrefslogtreecommitdiff
path: root/authfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'authfile.c')
-rw-r--r--authfile.c111
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. */
70static const char authfile_id_string[] = 71static 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
682char *
683blacklist_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. */
693int
694blacklisted_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
781out:
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}