[PATCH v1 2/9] certs: Make blacklist_vet_description() more strict
From: Mickaël Salaün <mic@digikod.net>
Date: 2020-11-20 18:05:02
Also in:
keyrings, linux-crypto, linux-integrity, lkml
Subsystem:
certificate handling, the rest · Maintainers:
David Howells, David Woodhouse, Linus Torvalds
From: Mickaël Salaün <redacted> Before exposing this new key type to user space, make sure that only meaningful blacklisted hashes are accepted. This is also checked for builtin blacklisted hashes, but a following commit make sure that the user will notice (at built time) and will fix the configuration if it already included errors. Check that a blacklist key description starts with a valid prefix and then a valid hexadecimal string. Cc: David Howells <dhowells@redhat.com> Cc: David Woodhouse <dwmw2@infradead.org> Signed-off-by: Mickaël Salaün <redacted> --- certs/blacklist.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-)
diff --git a/certs/blacklist.c b/certs/blacklist.c
index 4e1a58170d5c..961359885881 100644
--- a/certs/blacklist.c
+++ b/certs/blacklist.c@@ -17,6 +17,16 @@ #include <keys/system_keyring.h> #include "blacklist.h" +/* + * According to crypto/asymmetric_keys/x509_cert_parser.c:x509_note_pkey_algo(), + * the size of the currently longest supported hash algorithm is 512 bits, + * which translates into 128 hex characters. + */ +#define MAX_HASH_LEN 128 + +static const char tbs_prefix[] = "tbs"; +static const char bin_prefix[] = "bin"; + static struct key *blacklist_keyring; /*
@@ -25,24 +35,40 @@ static struct key *blacklist_keyring; */ static int blacklist_vet_description(const char *desc) { - int n = 0; - - if (*desc == ':') - return -EINVAL; - for (; *desc; desc++) - if (*desc == ':') - goto found_colon; + int i, prefix_len, tbs_step = 0, bin_step = 0; + + /* The following algorithm only works if prefix lenghts match. */ + BUILD_BUG_ON(sizeof(tbs_prefix) != sizeof(bin_prefix)); + prefix_len = sizeof(tbs_prefix) - 1; + for (i = 0; *desc; desc++, i++) { + if (*desc == ':') { + if (tbs_step == prefix_len) + goto found_colon; + if (bin_step == prefix_len) + goto found_colon; + return -EINVAL; + } + if (i >= prefix_len) + return -EINVAL; + if (*desc == tbs_prefix[i]) + tbs_step++; + if (*desc == bin_prefix[i]) + bin_step++; + } return -EINVAL; found_colon: desc++; - for (; *desc; desc++) { + for (i = 0; *desc && i < MAX_HASH_LEN; desc++, i++) { if (!isxdigit(*desc) || isupper(*desc)) return -EINVAL; - n++; } + if (*desc) + /* The hash is greater than MAX_HASH_LEN. */ + return -EINVAL; - if (n == 0 || n & 1) + /* Checks for an even number of hexadecimal characters. */ + if (i == 0 || i & 1) return -EINVAL; return 0; }
--
2.29.2