]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - crypto/asymmetric_keys/x509_public_key.c
crypto: asymmetric_keys - Fix unaligned access in x509_get_sig_params()
[karo-tx-linux.git] / crypto / asymmetric_keys / x509_public_key.c
index 24f17e6c590488d66ca01ec1f0e6f93a3f013163..6451d1848a7d0e19b621157159c01abe130076cf 100644 (file)
@@ -65,23 +65,37 @@ __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.
+ * @id: The issuer & serialNumber to look for or NULL.
+ * @skid: The subjectKeyIdentifier to look for or NULL.
  * @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.
+ * Find a key in the given keyring by identifier.  The preferred identifier is
+ * the issuer + serialNumber and the fallback identifier is the
+ * subjectKeyIdentifier.  If both are given, the lookup is by the former, but
+ * the latter must also match.
  */
 struct key *x509_request_asymmetric_key(struct key *keyring,
-                                       const struct asymmetric_key_id *kid,
+                                       const struct asymmetric_key_id *id,
+                                       const struct asymmetric_key_id *skid,
                                        bool partial)
 {
-       key_ref_t key;
-       char *id, *p;
-
+       struct key *key;
+       key_ref_t ref;
+       const char *lookup;
+       char *req, *p;
+       int len;
+
+       if (id) {
+               lookup = id->data;
+               len = id->len;
+       } else {
+               lookup = skid->data;
+               len = skid->len;
+       }
+       
        /* Construct an identifier "id:<keyid>". */
-       p = id = kmalloc(2 + 1 + kid->len * 2 + 1, GFP_KERNEL);
-       if (!id)
+       p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
+       if (!req)
                return ERR_PTR(-ENOMEM);
 
        if (partial) {
@@ -92,32 +106,48 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
                *p++ = 'x';
        }
        *p++ = ':';
-       p = bin2hex(p, kid->data, kid->len);
+       p = bin2hex(p, lookup, len);
        *p = 0;
 
-       pr_debug("Look up: \"%s\"\n", id);
+       pr_debug("Look up: \"%s\"\n", req);
 
-       key = keyring_search(make_key_ref(keyring, 1),
-                            &key_type_asymmetric, id);
-       if (IS_ERR(key))
-               pr_debug("Request for key '%s' err %ld\n", id, PTR_ERR(key));
-       kfree(id);
+       ref = keyring_search(make_key_ref(keyring, 1),
+                            &key_type_asymmetric, req);
+       if (IS_ERR(ref))
+               pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
+       kfree(req);
 
-       if (IS_ERR(key)) {
-               switch (PTR_ERR(key)) {
+       if (IS_ERR(ref)) {
+               switch (PTR_ERR(ref)) {
                        /* Hide some search errors */
                case -EACCES:
                case -ENOTDIR:
                case -EAGAIN:
                        return ERR_PTR(-ENOKEY);
                default:
-                       return ERR_CAST(key);
+                       return ERR_CAST(ref);
+               }
+       }
+
+       key = key_ref_to_ptr(ref);
+       if (id && skid) {
+               const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+               if (!kids->id[1]) {
+                       pr_debug("issuer+serial match, but expected SKID missing\n");
+                       goto reject;
+               }
+               if (!asymmetric_key_id_same(skid, kids->id[1])) {
+                       pr_debug("issuer+serial match, but SKID does not\n");
+                       goto reject;
                }
        }
+       
+       pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
+       return key;
 
-       pr_devel("<==%s() = 0 [%x]\n", __func__,
-                key_serial(key_ref_to_ptr(key)));
-       return key_ref_to_ptr(key);
+reject:
+       key_put(key);
+       return ERR_PTR(-EKEYREJECTED);
 }
 EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
 
@@ -164,14 +194,15 @@ int x509_get_sig_params(struct x509_certificate *cert)
         * digest storage space.
         */
        ret = -ENOMEM;
-       digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
+       digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
+                        GFP_KERNEL);
        if (!digest)
                goto error;
 
        cert->sig.digest = digest;
        cert->sig.digest_size = digest_size;
 
-       desc = digest + digest_size;
+       desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
        desc->tfm = tfm;
        desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
@@ -227,10 +258,11 @@ static int x509_validate_trust(struct x509_certificate *cert,
        if (!trust_keyring)
                return -EOPNOTSUPP;
 
-       if (ca_keyid && !asymmetric_key_id_partial(cert->authority, ca_keyid))
+       if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
                return -EPERM;
 
-       key = x509_request_asymmetric_key(trust_keyring, cert->authority,
+       key = x509_request_asymmetric_key(trust_keyring,
+                                         cert->akid_id, cert->akid_skid,
                                          false);
        if (!IS_ERR(key))  {
                if (!use_builtin_keys
@@ -271,14 +303,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
        }
 
        pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
-       pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
-                cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
-                cert->valid_from.tm_mday, cert->valid_from.tm_hour,
-                cert->valid_from.tm_min,  cert->valid_from.tm_sec);
-       pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
-                cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
-                cert->valid_to.tm_mday, cert->valid_to.tm_hour,
-                cert->valid_to.tm_min,  cert->valid_to.tm_sec);
+       pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
        pr_devel("Cert Signature: %s + %s\n",
                 pkey_algo_name[cert->sig.pkey_algo],
                 hash_algo_name[cert->sig.pkey_hash_algo]);
@@ -287,8 +312,9 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
        cert->pub->id_type = PKEY_ID_X509;
 
        /* Check the signature on the key if it appears to be self-signed */
-       if (!cert->authority ||
-           asymmetric_key_id_same(cert->skid, cert->authority)) {
+       if ((!cert->akid_skid && !cert->akid_id) ||
+           asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
+           asymmetric_key_id_same(cert->id, cert->akid_id)) {
                ret = x509_check_signature(cert->pub, cert); /* self-signed */
                if (ret < 0)
                        goto error_free_cert;