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