Commit f1b731db authored by Dmitry Kasatkin's avatar Dmitry Kasatkin Committed by David Howells

KEYS: Restore partial ID matching functionality for asymmetric keys

Bring back the functionality whereby an asymmetric key can be matched with a
partial match on one of its IDs.

Whilst we're at it, allow for the possibility of having an increased number of
IDs.
Reported-by: default avatarDmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: default avatarDmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent dd2f6c44
...@@ -9,9 +9,6 @@ ...@@ -9,9 +9,6 @@
* 2 of the Licence, or (at your option) any later version. * 2 of the Licence, or (at your option) any later version.
*/ */
extern bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids,
const struct asymmetric_key_id *match_id);
extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id); extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
static inline static inline
......
...@@ -65,23 +65,44 @@ bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1, ...@@ -65,23 +65,44 @@ bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
} }
EXPORT_SYMBOL_GPL(asymmetric_key_id_same); EXPORT_SYMBOL_GPL(asymmetric_key_id_same);
/**
* asymmetric_key_id_partial - Return true if two asymmetric keys IDs
* partially match
* @kid_1, @kid_2: The key IDs to compare
*/
bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
const struct asymmetric_key_id *kid2)
{
if (!kid1 || !kid2)
return false;
if (kid1->len < kid2->len)
return false;
return memcmp(kid1->data + (kid1->len - kid2->len),
kid2->data, kid2->len) == 0;
}
EXPORT_SYMBOL_GPL(asymmetric_key_id_partial);
/** /**
* asymmetric_match_key_ids - Search asymmetric key IDs * asymmetric_match_key_ids - Search asymmetric key IDs
* @kids: The list of key IDs to check * @kids: The list of key IDs to check
* @match_id: The key ID we're looking for * @match_id: The key ID we're looking for
* @match: The match function to use
*/ */
bool asymmetric_match_key_ids(const struct asymmetric_key_ids *kids, static bool asymmetric_match_key_ids(
const struct asymmetric_key_id *match_id) const struct asymmetric_key_ids *kids,
const struct asymmetric_key_id *match_id,
bool (*match)(const struct asymmetric_key_id *kid1,
const struct asymmetric_key_id *kid2))
{ {
int i;
if (!kids || !match_id) if (!kids || !match_id)
return false; return false;
if (asymmetric_key_id_same(kids->id[0], match_id)) for (i = 0; i < ARRAY_SIZE(kids->id); i++)
return true; if (match(kids->id[i], match_id))
if (asymmetric_key_id_same(kids->id[1], match_id))
return true; return true;
return false; return false;
} }
EXPORT_SYMBOL_GPL(asymmetric_match_key_ids);
/** /**
* asymmetric_key_hex_to_key_id - Convert a hex string into a key ID. * asymmetric_key_hex_to_key_id - Convert a hex string into a key ID.
...@@ -113,7 +134,7 @@ struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id) ...@@ -113,7 +134,7 @@ struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id)
} }
/* /*
* Match asymmetric keys by ID. * Match asymmetric keys by an exact match on an ID.
*/ */
static bool asymmetric_key_cmp(const struct key *key, static bool asymmetric_key_cmp(const struct key *key,
const struct key_match_data *match_data) const struct key_match_data *match_data)
...@@ -121,7 +142,21 @@ static bool asymmetric_key_cmp(const struct key *key, ...@@ -121,7 +142,21 @@ static bool asymmetric_key_cmp(const struct key *key,
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key); const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
const struct asymmetric_key_id *match_id = match_data->preparsed; const struct asymmetric_key_id *match_id = match_data->preparsed;
return asymmetric_match_key_ids(kids, match_id); return asymmetric_match_key_ids(kids, match_id,
asymmetric_key_id_same);
}
/*
* Match asymmetric keys by a partial match on an IDs.
*/
static bool asymmetric_key_cmp_partial(const struct key *key,
const struct key_match_data *match_data)
{
const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
const struct asymmetric_key_id *match_id = match_data->preparsed;
return asymmetric_match_key_ids(kids, match_id,
asymmetric_key_id_partial);
} }
/* /*
...@@ -131,7 +166,8 @@ static bool asymmetric_key_cmp(const struct key *key, ...@@ -131,7 +166,8 @@ static bool asymmetric_key_cmp(const struct key *key,
* There are some specifiers for matching key IDs rather than by the key * There are some specifiers for matching key IDs rather than by the key
* description: * description:
* *
* "id:<id>" - request a key by any available ID * "id:<id>" - find a key by partial match on any available ID
* "ex:<id>" - find a key by exact match on any available ID
* *
* These have to be searched by iteration rather than by direct lookup because * These have to be searched by iteration rather than by direct lookup because
* the key is hashed according to its description. * the key is hashed according to its description.
...@@ -141,6 +177,8 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data) ...@@ -141,6 +177,8 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
struct asymmetric_key_id *match_id; struct asymmetric_key_id *match_id;
const char *spec = match_data->raw_data; const char *spec = match_data->raw_data;
const char *id; const char *id;
bool (*cmp)(const struct key *, const struct key_match_data *) =
asymmetric_key_cmp;
if (!spec || !*spec) if (!spec || !*spec)
return -EINVAL; return -EINVAL;
...@@ -148,6 +186,11 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data) ...@@ -148,6 +186,11 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
spec[1] == 'd' && spec[1] == 'd' &&
spec[2] == ':') { spec[2] == ':') {
id = spec + 3; id = spec + 3;
cmp = asymmetric_key_cmp_partial;
} else if (spec[0] == 'e' &&
spec[1] == 'x' &&
spec[2] == ':') {
id = spec + 3;
} else { } else {
goto default_match; goto default_match;
} }
...@@ -157,7 +200,7 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data) ...@@ -157,7 +200,7 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
return PTR_ERR(match_id); return PTR_ERR(match_id);
match_data->preparsed = match_id; match_data->preparsed = match_id;
match_data->cmp = asymmetric_key_cmp; match_data->cmp = cmp;
match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE; match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
return 0; return 0;
...@@ -251,6 +294,7 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) ...@@ -251,6 +294,7 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
{ {
struct asymmetric_key_subtype *subtype = prep->type_data[0]; struct asymmetric_key_subtype *subtype = prep->type_data[0];
struct asymmetric_key_ids *kids = prep->type_data[1]; struct asymmetric_key_ids *kids = prep->type_data[1];
int i;
pr_devel("==>%s()\n", __func__); pr_devel("==>%s()\n", __func__);
...@@ -259,8 +303,8 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep) ...@@ -259,8 +303,8 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
module_put(subtype->owner); module_put(subtype->owner);
} }
if (kids) { if (kids) {
kfree(kids->id[0]); for (i = 0; i < ARRAY_SIZE(kids->id); i++)
kfree(kids->id[1]); kfree(kids->id[i]);
kfree(kids); kfree(kids);
} }
kfree(prep->description); kfree(prep->description);
......
...@@ -54,7 +54,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, ...@@ -54,7 +54,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
/* Look to see if this certificate is present in the trusted /* Look to see if this certificate is present in the trusted
* keys. * keys.
*/ */
key = x509_request_asymmetric_key(trust_keyring, x509->id); key = x509_request_asymmetric_key(trust_keyring, x509->id,
false);
if (!IS_ERR(key)) { if (!IS_ERR(key)) {
/* One of the X.509 certificates in the PKCS#7 message /* One of the X.509 certificates in the PKCS#7 message
* is apparently the same as one we already trust. * is apparently the same as one we already trust.
...@@ -85,7 +86,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, ...@@ -85,7 +86,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
* trusted keys. * trusted keys.
*/ */
if (last && last->authority) { if (last && last->authority) {
key = x509_request_asymmetric_key(trust_keyring, last->authority); key = x509_request_asymmetric_key(trust_keyring, last->authority,
false);
if (!IS_ERR(key)) { if (!IS_ERR(key)) {
x509 = last; x509 = last;
pr_devel("sinfo %u: Root cert %u signer is key %x\n", pr_devel("sinfo %u: Root cert %u signer is key %x\n",
...@@ -100,7 +102,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, ...@@ -100,7 +102,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
* the signed info directly. * the signed info directly.
*/ */
key = x509_request_asymmetric_key(trust_keyring, key = x509_request_asymmetric_key(trust_keyring,
sinfo->signing_cert_id); sinfo->signing_cert_id,
false);
if (!IS_ERR(key)) { if (!IS_ERR(key)) {
pr_devel("sinfo %u: Direct signer is key %x\n", pr_devel("sinfo %u: Direct signer is key %x\n",
sinfo->index, key_serial(key)); sinfo->index, key_serial(key));
......
...@@ -53,13 +53,15 @@ __setup("ca_keys=", ca_keys_setup); ...@@ -53,13 +53,15 @@ __setup("ca_keys=", ca_keys_setup);
* x509_request_asymmetric_key - Request a key by X.509 certificate params. * x509_request_asymmetric_key - Request a key by X.509 certificate params.
* @keyring: The keys to search. * @keyring: The keys to search.
* @kid: The key ID. * @kid: The key ID.
* @partial: Use partial match if true, exact if false.
* *
* Find a key in the given keyring by subject name and key ID. These might, * Find a key in the given keyring by subject name and key ID. These might,
* for instance, be the issuer name and the authority key ID of an X.509 * for instance, be the issuer name and the authority key ID of an X.509
* certificate that needs to be verified. * certificate that needs to be verified.
*/ */
struct key *x509_request_asymmetric_key(struct key *keyring, struct key *x509_request_asymmetric_key(struct key *keyring,
const struct asymmetric_key_id *kid) const struct asymmetric_key_id *kid,
bool partial)
{ {
key_ref_t key; key_ref_t key;
char *id, *p; char *id, *p;
...@@ -69,8 +71,13 @@ struct key *x509_request_asymmetric_key(struct key *keyring, ...@@ -69,8 +71,13 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
if (!id) if (!id)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (partial) {
*p++ = 'i'; *p++ = 'i';
*p++ = 'd'; *p++ = 'd';
} else {
*p++ = 'e';
*p++ = 'x';
}
*p++ = ':'; *p++ = ':';
p = bin2hex(p, kid->data, kid->len); p = bin2hex(p, kid->data, kid->len);
*p = 0; *p = 0;
...@@ -207,10 +214,11 @@ static int x509_validate_trust(struct x509_certificate *cert, ...@@ -207,10 +214,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
if (!trust_keyring) if (!trust_keyring)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (ca_keyid && !asymmetric_key_id_same(cert->authority, ca_keyid)) if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid))
return -EPERM; return -EPERM;
key = x509_request_asymmetric_key(trust_keyring, cert->authority); key = x509_request_asymmetric_key(trust_keyring, cert->authority,
false);
if (!IS_ERR(key)) { if (!IS_ERR(key)) {
if (!use_builtin_keys if (!use_builtin_keys
|| test_bit(KEY_FLAG_BUILTIN, &key->flags)) || test_bit(KEY_FLAG_BUILTIN, &key->flags))
......
...@@ -101,6 +101,7 @@ extern int verify_signature(const struct key *key, ...@@ -101,6 +101,7 @@ extern int verify_signature(const struct key *key,
struct asymmetric_key_id; struct asymmetric_key_id;
extern struct key *x509_request_asymmetric_key(struct key *keyring, extern struct key *x509_request_asymmetric_key(struct key *keyring,
const struct asymmetric_key_id *kid); const struct asymmetric_key_id *kid,
bool partial);
#endif /* _LINUX_PUBLIC_KEY_H */ #endif /* _LINUX_PUBLIC_KEY_H */
...@@ -51,6 +51,9 @@ struct asymmetric_key_ids { ...@@ -51,6 +51,9 @@ struct asymmetric_key_ids {
extern bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1, extern bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
const struct asymmetric_key_id *kid2); const struct asymmetric_key_id *kid2);
extern bool asymmetric_key_id_partial(const struct asymmetric_key_id *kid1,
const struct asymmetric_key_id *kid2);
extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1, extern struct asymmetric_key_id *asymmetric_key_generate_id(const void *val_1,
size_t len_1, size_t len_1,
const void *val_2, const void *val_2,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment