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: Dmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: Dmitry Kasatkin <d.kasatkin@samsung.com>
Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
Dmitry Kasatkin 2014-10-06 15:21:05 +01:00 committed by David Howells
parent dd2f6c4481
commit f1b731dbc2
6 changed files with 81 additions and 25 deletions

View File

@ -9,9 +9,6 @@
* 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);
static inline

View File

@ -65,23 +65,44 @@ bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
}
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
* @kids: The list of key IDs to check
* @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,
const struct asymmetric_key_id *match_id)
static bool asymmetric_match_key_ids(
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)
return false;
if (asymmetric_key_id_same(kids->id[0], match_id))
return true;
if (asymmetric_key_id_same(kids->id[1], match_id))
return true;
for (i = 0; i < ARRAY_SIZE(kids->id); i++)
if (match(kids->id[i], match_id))
return true;
return false;
}
EXPORT_SYMBOL_GPL(asymmetric_match_key_ids);
/**
* 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)
}
/*
* Match asymmetric keys by ID.
* Match asymmetric keys by an exact match on an ID.
*/
static bool asymmetric_key_cmp(const struct key *key,
const struct key_match_data *match_data)
@ -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_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,
* There are some specifiers for matching key IDs rather than by the key
* 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
* the key is hashed according to its description.
@ -141,6 +177,8 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
struct asymmetric_key_id *match_id;
const char *spec = match_data->raw_data;
const char *id;
bool (*cmp)(const struct key *, const struct key_match_data *) =
asymmetric_key_cmp;
if (!spec || !*spec)
return -EINVAL;
@ -148,6 +186,11 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
spec[1] == 'd' &&
spec[2] == ':') {
id = spec + 3;
cmp = asymmetric_key_cmp_partial;
} else if (spec[0] == 'e' &&
spec[1] == 'x' &&
spec[2] == ':') {
id = spec + 3;
} else {
goto default_match;
}
@ -157,7 +200,7 @@ static int asymmetric_key_match_preparse(struct key_match_data *match_data)
return PTR_ERR(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;
return 0;
@ -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_ids *kids = prep->type_data[1];
int i;
pr_devel("==>%s()\n", __func__);
@ -259,8 +303,8 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
module_put(subtype->owner);
}
if (kids) {
kfree(kids->id[0]);
kfree(kids->id[1]);
for (i = 0; i < ARRAY_SIZE(kids->id); i++)
kfree(kids->id[i]);
kfree(kids);
}
kfree(prep->description);

View File

@ -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
* keys.
*/
key = x509_request_asymmetric_key(trust_keyring, x509->id);
key = x509_request_asymmetric_key(trust_keyring, x509->id,
false);
if (!IS_ERR(key)) {
/* One of the X.509 certificates in the PKCS#7 message
* is apparently the same as one we already trust.
@ -85,7 +86,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
* trusted keys.
*/
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)) {
x509 = last;
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,
* the signed info directly.
*/
key = x509_request_asymmetric_key(trust_keyring,
sinfo->signing_cert_id);
sinfo->signing_cert_id,
false);
if (!IS_ERR(key)) {
pr_devel("sinfo %u: Direct signer is key %x\n",
sinfo->index, key_serial(key));

View File

@ -53,13 +53,15 @@ __setup("ca_keys=", ca_keys_setup);
* x509_request_asymmetric_key - Request a key by X.509 certificate params.
* @keyring: The keys to search.
* @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,
* for instance, be the issuer name and the authority key ID of an X.509
* certificate that needs to be verified.
*/
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;
char *id, *p;
@ -69,8 +71,13 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
if (!id)
return ERR_PTR(-ENOMEM);
*p++ = 'i';
*p++ = 'd';
if (partial) {
*p++ = 'i';
*p++ = 'd';
} else {
*p++ = 'e';
*p++ = 'x';
}
*p++ = ':';
p = bin2hex(p, kid->data, kid->len);
*p = 0;
@ -207,10 +214,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
if (!trust_keyring)
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;
key = x509_request_asymmetric_key(trust_keyring, cert->authority);
key = x509_request_asymmetric_key(trust_keyring, cert->authority,
false);
if (!IS_ERR(key)) {
if (!use_builtin_keys
|| test_bit(KEY_FLAG_BUILTIN, &key->flags))

View File

@ -101,6 +101,7 @@ extern int verify_signature(const struct key *key,
struct asymmetric_key_id;
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 */

View File

@ -51,6 +51,9 @@ struct asymmetric_key_ids {
extern bool asymmetric_key_id_same(const struct asymmetric_key_id *kid1,
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,
size_t len_1,
const void *val_2,