Skip to content

Commit

Permalink
KEYS: Restore partial ID matching functionality for asymmetric keys
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Dmitry Kasatkin <[email protected]>
Signed-off-by: David Howells <[email protected]>
  • Loading branch information
Dmitry Kasatkin authored and dhowells committed Oct 6, 2014
1 parent dd2f6c4 commit f1b731d
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 25 deletions.
3 changes: 0 additions & 3 deletions crypto/asymmetric_keys/asymmetric_keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 57 additions & 13 deletions crypto/asymmetric_keys/asymmetric_type.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -113,15 +134,29 @@ 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)
{
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);
}

/*
Expand All @@ -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.
Expand All @@ -141,13 +177,20 @@ 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;
if (spec[0] == 'i' &&
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;
}
Expand All @@ -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;

Expand Down Expand Up @@ -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__);

Expand All @@ -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);
Expand Down
9 changes: 6 additions & 3 deletions crypto/asymmetric_keys/pkcs7_trust.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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",
Expand All @@ -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));
Expand Down
18 changes: 13 additions & 5 deletions crypto/asymmetric_keys/x509_public_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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))
Expand Down
3 changes: 2 additions & 1 deletion include/crypto/public_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
3 changes: 3 additions & 0 deletions include/keys/asymmetric-type.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit f1b731d

Please sign in to comment.