forked from Minki/linux
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:
parent
dd2f6c4481
commit
f1b731dbc2
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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))
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user