diff --git a/certs/blacklist.c b/certs/blacklist.c index 1cdf309a5b08..b254c87ceb3a 100644 --- a/certs/blacklist.c +++ b/certs/blacklist.c @@ -19,6 +19,16 @@ #include "blacklist.h" #include "common.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; #ifdef CONFIG_SYSTEM_REVOCATION_LIST @@ -32,24 +42,40 @@ extern __initconst const unsigned long revocation_certificate_list_size; */ static int blacklist_vet_description(const char *desc) { - int n = 0; + int i, prefix_len, tbs_step = 0, bin_step = 0; - if (*desc == ':') - return -EINVAL; - for (; *desc; desc++) - if (*desc == ':') - goto found_colon; + /* The following algorithm only works if prefix lengths 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 -ENOPKG; - if (n == 0 || n & 1) + /* Checks for an even number of hexadecimal characters. */ + if (i == 0 || i & 1) return -EINVAL; return 0; }