summaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorDmitry Kasatkin <d.kasatkin@samsung.com>2014-10-06 16:21:05 +0200
committerDavid Howells <dhowells@redhat.com>2014-10-06 16:21:05 +0200
commitf1b731dbc2530cab93fcfc5fcb18c9f3a100feeb (patch)
treeb5b02c3fd51b13e11a5212e4b726f5e2df653f8a /crypto
parentX.509: If available, use the raw subjKeyId to form the key description (diff)
downloadlinux-f1b731dbc2530cab93fcfc5fcb18c9f3a100feeb.tar.xz
linux-f1b731dbc2530cab93fcfc5fcb18c9f3a100feeb.zip
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>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/asymmetric_keys/asymmetric_keys.h3
-rw-r--r--crypto/asymmetric_keys/asymmetric_type.c70
-rw-r--r--crypto/asymmetric_keys/pkcs7_trust.c9
-rw-r--r--crypto/asymmetric_keys/x509_public_key.c18
4 files changed, 76 insertions, 24 deletions
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h
index fd21ac28e0a0..f97330886d58 100644
--- a/crypto/asymmetric_keys/asymmetric_keys.h
+++ b/crypto/asymmetric_keys/asymmetric_keys.h
@@ -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
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index 29983cbb658d..052e944bb109 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -66,22 +66,43 @@ 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);
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index ae47be6128c4..1d29376072da 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -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));
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 8bffb06b2683..6ef54495be87 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -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))