1/*
2 * Copyright (C) 2013 Intel Corporation
3 *
4 * Author:
5 * Dmitry Kasatkin <dmitry.kasatkin@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 2 of the License.
10 *
11 */
12
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15#include <linux/err.h>
16#include <linux/ratelimit.h>
17#include <linux/key-type.h>
18#include <crypto/public_key.h>
19#include <keys/asymmetric-type.h>
20
21#include "integrity.h"
22
23/*
24 * Request an asymmetric key.
25 */
26static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
27{
28	struct key *key;
29	char name[12];
30
31	sprintf(name, "id:%08x", keyid);
32
33	pr_debug("key search: \"%s\"\n", name);
34
35	if (keyring) {
36		/* search in specific keyring */
37		key_ref_t kref;
38		kref = keyring_search(make_key_ref(keyring, 1),
39				      &key_type_asymmetric, name);
40		if (IS_ERR(kref))
41			key = ERR_CAST(kref);
42		else
43			key = key_ref_to_ptr(kref);
44	} else {
45		key = request_key(&key_type_asymmetric, name, NULL);
46	}
47
48	if (IS_ERR(key)) {
49		pr_err_ratelimited("Request for unknown key '%s' err %ld\n",
50				   name, PTR_ERR(key));
51		switch (PTR_ERR(key)) {
52			/* Hide some search errors */
53		case -EACCES:
54		case -ENOTDIR:
55		case -EAGAIN:
56			return ERR_PTR(-ENOKEY);
57		default:
58			return key;
59		}
60	}
61
62	pr_debug("%s() = 0 [%x]\n", __func__, key_serial(key));
63
64	return key;
65}
66
67int asymmetric_verify(struct key *keyring, const char *sig,
68		      int siglen, const char *data, int datalen)
69{
70	struct public_key_signature pks;
71	struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
72	struct key *key;
73	int ret = -ENOMEM;
74
75	if (siglen <= sizeof(*hdr))
76		return -EBADMSG;
77
78	siglen -= sizeof(*hdr);
79
80	if (siglen != __be16_to_cpu(hdr->sig_size))
81		return -EBADMSG;
82
83	if (hdr->hash_algo >= PKEY_HASH__LAST)
84		return -ENOPKG;
85
86	key = request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
87	if (IS_ERR(key))
88		return PTR_ERR(key);
89
90	memset(&pks, 0, sizeof(pks));
91
92	pks.pkey_hash_algo = hdr->hash_algo;
93	pks.digest = (u8 *)data;
94	pks.digest_size = datalen;
95	pks.nr_mpi = 1;
96	pks.rsa.s = mpi_read_raw_data(hdr->sig, siglen);
97
98	if (pks.rsa.s)
99		ret = verify_signature(key, &pks);
100
101	mpi_free(pks.rsa.s);
102	key_put(key);
103	pr_debug("%s() = %d\n", __func__, ret);
104	return ret;
105}
106