KEYS: Restore partial ID matching functionality for asymmetric keys
authorDmitry Kasatkin <d.kasatkin@samsung.com>
Mon, 6 Oct 2014 14:21:05 +0000 (15:21 +0100)
committerDavid Howells <dhowells@redhat.com>
Mon, 6 Oct 2014 14:21:05 +0000 (15:21 +0100)
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>
crypto/asymmetric_keys/asymmetric_keys.h
crypto/asymmetric_keys/asymmetric_type.c
crypto/asymmetric_keys/pkcs7_trust.c
crypto/asymmetric_keys/x509_public_key.c
include/crypto/public_key.h
include/keys/asymmetric-type.h

index fd21ac28e0a023b94de6f80fdee4970bc8e98fb6..f97330886d587527c7211acb5d41831f382530f0 100644 (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
index 29983cbb658d176903942d9bee8fbe17e2924467..052e944bb10924d85b9f372c843144f05868c6fa 100644 (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);
index ae47be6128c411f6fc3c3f44e729a14218c9b55c..1d29376072da4a502e720fe10fc8fb34f6c4749a 100644 (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));
index 8bffb06b2683fa59e38e61aeeac2c7b62d4be6c5..6ef54495be873e2c3603fe2ef7ff9399f4845728 100644 (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))
index fa73a6fd536c1e2fcfc1010c04d6dd9e5a827c2e..54add206990166ff44aca927d024d4d62b8256a1 100644 (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 */
index 044ab0d3aa451b83db72d1e7d12b8738950dcfbb..c0754abb2f5676b8d8df7c0df4d44efdc3767d48 100644 (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,