Merge branch 'x86-cpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / crypto / asymmetric_keys / x509_public_key.c
index f3d62307e6eef7bf507dc78dddc4822739100cf9..a6c42031628e94172a112700f6cdb5cd01da9789 100644 (file)
@@ -25,7 +25,7 @@
 #include "x509_parser.h"
 
 static bool use_builtin_keys;
-static char *ca_keyid;
+static struct asymmetric_key_id *ca_keyid;
 
 #ifndef MODULE
 static int __init ca_keys_setup(char *str)
@@ -33,10 +33,16 @@ static int __init ca_keys_setup(char *str)
        if (!str)               /* default system keyring */
                return 1;
 
-       if (strncmp(str, "id:", 3) == 0)
-               ca_keyid = str; /* owner key 'id:xxxxxx' */
-       else if (strcmp(str, "builtin") == 0)
+       if (strncmp(str, "id:", 3) == 0) {
+               struct asymmetric_key_id *p;
+               p = asymmetric_key_hex_to_key_id(str + 3);
+               if (p == ERR_PTR(-EINVAL))
+                       pr_err("Unparsable hex string in ca_keys\n");
+               else if (!IS_ERR(p))
+                       ca_keyid = p;   /* owner key 'id:xxxxxx' */
+       } else if (strcmp(str, "builtin") == 0) {
                use_builtin_keys = true;
+       }
 
        return 1;
 }
@@ -46,31 +52,35 @@ __setup("ca_keys=", ca_keys_setup);
 /**
  * x509_request_asymmetric_key - Request a key by X.509 certificate params.
  * @keyring: The keys to search.
- * @subject: The name of the subject to whom the key belongs.
- * @key_id: The subject key ID as a hex string.
+ * @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 char *subject,
-                                       const char *key_id)
+                                       const struct asymmetric_key_id *kid,
+                                       bool partial)
 {
        key_ref_t key;
-       size_t subject_len = strlen(subject), key_id_len = strlen(key_id);
-       char *id;
+       char *id, *p;
 
-       /* Construct an identifier "<subjname>:<keyid>". */
-       id = kmalloc(subject_len + 2 + key_id_len + 1, GFP_KERNEL);
+       /* Construct an identifier "id:<keyid>". */
+       p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL);
        if (!id)
                return ERR_PTR(-ENOMEM);
 
-       memcpy(id, subject, subject_len);
-       id[subject_len + 0] = ':';
-       id[subject_len + 1] = ' ';
-       memcpy(id + subject_len + 2, key_id, key_id_len);
-       id[subject_len + 2 + key_id_len] = 0;
+       if (partial) {
+               *p++ = 'i';
+               *p++ = 'd';
+       } else {
+               *p++ = 'e';
+               *p++ = 'x';
+       }
+       *p++ = ':';
+       p = bin2hex(p, kid->data, kid->len);
+       *p = 0;
 
        pr_debug("Look up: \"%s\"\n", id);
 
@@ -112,6 +122,8 @@ int x509_get_sig_params(struct x509_certificate *cert)
 
        pr_devel("==>%s()\n", __func__);
 
+       if (cert->unsupported_crypto)
+               return -ENOPKG;
        if (cert->sig.rsa.s)
                return 0;
 
@@ -124,8 +136,13 @@ int x509_get_sig_params(struct x509_certificate *cert)
         * big the hash operational data will be.
         */
        tfm = crypto_alloc_shash(hash_algo_name[cert->sig.pkey_hash_algo], 0, 0);
-       if (IS_ERR(tfm))
-               return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+       if (IS_ERR(tfm)) {
+               if (PTR_ERR(tfm) == -ENOENT) {
+                       cert->unsupported_crypto = true;
+                       return -ENOPKG;
+               }
+               return PTR_ERR(tfm);
+       }
 
        desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
        digest_size = crypto_shash_digestsize(tfm);
@@ -172,6 +189,8 @@ int x509_check_signature(const struct public_key *pub,
                return ret;
 
        ret = public_key_verify_signature(pub, &cert->sig);
+       if (ret == -ENOPKG)
+               cert->unsupported_crypto = true;
        pr_debug("Cert Verification: %d\n", ret);
        return ret;
 }
@@ -195,11 +214,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
        if (!trust_keyring)
                return -EOPNOTSUPP;
 
-       if (ca_keyid && !asymmetric_keyid_match(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->issuer, 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))
@@ -214,9 +233,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
  */
 static int x509_key_preparse(struct key_preparsed_payload *prep)
 {
+       struct asymmetric_key_ids *kids;
        struct x509_certificate *cert;
+       const char *q;
        size_t srlen, sulen;
-       char *desc = NULL;
+       char *desc = NULL, *p;
        int ret;
 
        cert = x509_cert_parse(prep->data, prep->datalen);
@@ -249,19 +270,12 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
                 pkey_algo_name[cert->sig.pkey_algo],
                 hash_algo_name[cert->sig.pkey_hash_algo]);
 
-       if (!cert->fingerprint) {
-               pr_warn("Cert for '%s' must have a SubjKeyId extension\n",
-                       cert->subject);
-               ret = -EKEYREJECTED;
-               goto error_free_cert;
-       }
-
        cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
        cert->pub->id_type = PKEY_ID_X509;
 
        /* Check the signature on the key if it appears to be self-signed */
        if (!cert->authority ||
-           strcmp(cert->fingerprint, cert->authority) == 0) {
+           asymmetric_key_id_same(cert->skid, cert->authority)) {
                ret = x509_check_signature(cert->pub, cert); /* self-signed */
                if (ret < 0)
                        goto error_free_cert;
@@ -273,31 +287,52 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 
        /* Propose a description */
        sulen = strlen(cert->subject);
-       srlen = strlen(cert->fingerprint);
+       if (cert->raw_skid) {
+               srlen = cert->raw_skid_size;
+               q = cert->raw_skid;
+       } else {
+               srlen = cert->raw_serial_size;
+               q = cert->raw_serial;
+       }
+       if (srlen > 1 && *q == 0) {
+               srlen--;
+               q++;
+       }
+
        ret = -ENOMEM;
-       desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
+       desc = kmalloc(sulen + 2 + srlen * 2 + 1, GFP_KERNEL);
        if (!desc)
                goto error_free_cert;
-       memcpy(desc, cert->subject, sulen);
-       desc[sulen] = ':';
-       desc[sulen + 1] = ' ';
-       memcpy(desc + sulen + 2, cert->fingerprint, srlen);
-       desc[sulen + 2 + srlen] = 0;
+       p = memcpy(desc, cert->subject, sulen);
+       p += sulen;
+       *p++ = ':';
+       *p++ = ' ';
+       p = bin2hex(p, q, srlen);
+       *p = 0;
+
+       kids = kmalloc(sizeof(struct asymmetric_key_ids), GFP_KERNEL);
+       if (!kids)
+               goto error_free_desc;
+       kids->id[0] = cert->id;
+       kids->id[1] = cert->skid;
 
        /* We're pinning the module by being linked against it */
        __module_get(public_key_subtype.owner);
        prep->type_data[0] = &public_key_subtype;
-       prep->type_data[1] = cert->fingerprint;
+       prep->type_data[1] = kids;
        prep->payload[0] = cert->pub;
        prep->description = desc;
        prep->quotalen = 100;
 
        /* We've finished with the certificate */
        cert->pub = NULL;
-       cert->fingerprint = NULL;
+       cert->id = NULL;
+       cert->skid = NULL;
        desc = NULL;
        ret = 0;
 
+error_free_desc:
+       kfree(desc);
 error_free_cert:
        x509_free_certificate(cert);
        return ret;