1b4d0d230SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2a9681bf3SDavid Howells /* In-software asymmetric public-key crypto subtype
3a9681bf3SDavid Howells *
40efaaa86SMauro Carvalho Chehab * See Documentation/crypto/asymmetric-keys.rst
5a9681bf3SDavid Howells *
6a9681bf3SDavid Howells * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
7a9681bf3SDavid Howells * Written by David Howells (dhowells@redhat.com)
8a9681bf3SDavid Howells */
9a9681bf3SDavid Howells
10a9681bf3SDavid Howells #define pr_fmt(fmt) "PKEY: "fmt
11d43de6c7SDavid Howells #include <crypto/akcipher.h>
1263ba4d67SHerbert Xu #include <crypto/public_key.h>
1363ba4d67SHerbert Xu #include <crypto/sig.h>
1463ba4d67SHerbert Xu #include <keys/asymmetric-subtype.h>
1563ba4d67SHerbert Xu #include <linux/asn1.h>
1663ba4d67SHerbert Xu #include <linux/err.h>
1763ba4d67SHerbert Xu #include <linux/kernel.h>
1863ba4d67SHerbert Xu #include <linux/module.h>
1963ba4d67SHerbert Xu #include <linux/seq_file.h>
2063ba4d67SHerbert Xu #include <linux/slab.h>
2163ba4d67SHerbert Xu #include <linux/string.h>
22a9681bf3SDavid Howells
231e684d38SDavid Howells MODULE_DESCRIPTION("In-software asymmetric public-key subtype");
241e684d38SDavid Howells MODULE_AUTHOR("Red Hat, Inc.");
25a9681bf3SDavid Howells MODULE_LICENSE("GPL");
26a9681bf3SDavid Howells
27a9681bf3SDavid Howells /*
28a9681bf3SDavid Howells * Provide a part of a description of the key for /proc/keys.
29a9681bf3SDavid Howells */
public_key_describe(const struct key * asymmetric_key,struct seq_file * m)30a9681bf3SDavid Howells static void public_key_describe(const struct key *asymmetric_key,
31a9681bf3SDavid Howells struct seq_file *m)
32a9681bf3SDavid Howells {
33146aa8b1SDavid Howells struct public_key *key = asymmetric_key->payload.data[asym_crypto];
34a9681bf3SDavid Howells
35a9681bf3SDavid Howells if (key)
364e8ae72aSDavid Howells seq_printf(m, "%s.%s", key->id_type, key->pkey_algo);
37a9681bf3SDavid Howells }
38a9681bf3SDavid Howells
39a9681bf3SDavid Howells /*
40a9681bf3SDavid Howells * Destroy a public key algorithm key.
41a9681bf3SDavid Howells */
public_key_free(struct public_key * key)423b764563SDavid Howells void public_key_free(struct public_key *key)
43a9681bf3SDavid Howells {
443b764563SDavid Howells if (key) {
459f3fa6bcSMahmoud Adam kfree_sensitive(key->key);
46f1774cb8SVitaly Chikunov kfree(key->params);
47a9681bf3SDavid Howells kfree(key);
48a9681bf3SDavid Howells }
493b764563SDavid Howells }
503b764563SDavid Howells EXPORT_SYMBOL_GPL(public_key_free);
513b764563SDavid Howells
523b764563SDavid Howells /*
533b764563SDavid Howells * Destroy a public key algorithm key.
543b764563SDavid Howells */
public_key_destroy(void * payload0,void * payload3)553b764563SDavid Howells static void public_key_destroy(void *payload0, void *payload3)
563b764563SDavid Howells {
573b764563SDavid Howells public_key_free(payload0);
583b764563SDavid Howells public_key_signature_free(payload3);
593b764563SDavid Howells }
60a9681bf3SDavid Howells
61a9681bf3SDavid Howells /*
62590bfb57SEric Biggers * Given a public_key, and an encoding and hash_algo to be used for signing
63590bfb57SEric Biggers * and/or verification with that key, determine the name of the corresponding
64590bfb57SEric Biggers * akcipher algorithm. Also check that encoding and hash_algo are allowed.
6582f94f24SDavid Howells */
66590bfb57SEric Biggers static int
software_key_determine_akcipher(const struct public_key * pkey,const char * encoding,const char * hash_algo,char alg_name[CRYPTO_MAX_ALG_NAME],bool * sig,enum kernel_pkey_operation op)67590bfb57SEric Biggers software_key_determine_akcipher(const struct public_key *pkey,
68590bfb57SEric Biggers const char *encoding, const char *hash_algo,
6963ba4d67SHerbert Xu char alg_name[CRYPTO_MAX_ALG_NAME], bool *sig,
7063ba4d67SHerbert Xu enum kernel_pkey_operation op)
7182f94f24SDavid Howells {
7282f94f24SDavid Howells int n;
7382f94f24SDavid Howells
7463ba4d67SHerbert Xu *sig = true;
7563ba4d67SHerbert Xu
76590bfb57SEric Biggers if (!encoding)
77590bfb57SEric Biggers return -EINVAL;
78590bfb57SEric Biggers
79590bfb57SEric Biggers if (strcmp(pkey->pkey_algo, "rsa") == 0) {
80590bfb57SEric Biggers /*
81590bfb57SEric Biggers * RSA signatures usually use EMSA-PKCS1-1_5 [RFC3447 sec 8.2].
8282f94f24SDavid Howells */
83590bfb57SEric Biggers if (strcmp(encoding, "pkcs1") == 0) {
84*b1195035SHerbert Xu *sig = op == kernel_pkey_sign ||
85*b1195035SHerbert Xu op == kernel_pkey_verify;
8663ba4d67SHerbert Xu if (!hash_algo) {
8782f94f24SDavid Howells n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
8882f94f24SDavid Howells "pkcs1pad(%s)",
8982f94f24SDavid Howells pkey->pkey_algo);
9063ba4d67SHerbert Xu } else {
9182f94f24SDavid Howells n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
9282f94f24SDavid Howells "pkcs1pad(%s,%s)",
9382f94f24SDavid Howells pkey->pkey_algo, hash_algo);
9463ba4d67SHerbert Xu }
9582f94f24SDavid Howells return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
9682f94f24SDavid Howells }
97590bfb57SEric Biggers if (strcmp(encoding, "raw") != 0)
98590bfb57SEric Biggers return -EINVAL;
99590bfb57SEric Biggers /*
100590bfb57SEric Biggers * Raw RSA cannot differentiate between different hash
101590bfb57SEric Biggers * algorithms.
102590bfb57SEric Biggers */
103590bfb57SEric Biggers if (hash_algo)
104590bfb57SEric Biggers return -EINVAL;
10563ba4d67SHerbert Xu *sig = false;
106590bfb57SEric Biggers } else if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) {
107590bfb57SEric Biggers if (strcmp(encoding, "x962") != 0)
108590bfb57SEric Biggers return -EINVAL;
109590bfb57SEric Biggers /*
110590bfb57SEric Biggers * ECDSA signatures are taken over a raw hash, so they don't
111590bfb57SEric Biggers * differentiate between different hash algorithms. That means
112590bfb57SEric Biggers * that the verifier should hard-code a specific hash algorithm.
113590bfb57SEric Biggers * Unfortunately, in practice ECDSA is used with multiple SHAs,
114590bfb57SEric Biggers * so we have to allow all of them and not just one.
115590bfb57SEric Biggers */
116590bfb57SEric Biggers if (!hash_algo)
117590bfb57SEric Biggers return -EINVAL;
118590bfb57SEric Biggers if (strcmp(hash_algo, "sha1") != 0 &&
119590bfb57SEric Biggers strcmp(hash_algo, "sha224") != 0 &&
120590bfb57SEric Biggers strcmp(hash_algo, "sha256") != 0 &&
121590bfb57SEric Biggers strcmp(hash_algo, "sha384") != 0 &&
122590bfb57SEric Biggers strcmp(hash_algo, "sha512") != 0)
123590bfb57SEric Biggers return -EINVAL;
124590bfb57SEric Biggers } else if (strcmp(pkey->pkey_algo, "sm2") == 0) {
125590bfb57SEric Biggers if (strcmp(encoding, "raw") != 0)
126590bfb57SEric Biggers return -EINVAL;
127590bfb57SEric Biggers if (!hash_algo)
128590bfb57SEric Biggers return -EINVAL;
129590bfb57SEric Biggers if (strcmp(hash_algo, "sm3") != 0)
130590bfb57SEric Biggers return -EINVAL;
131590bfb57SEric Biggers } else if (strcmp(pkey->pkey_algo, "ecrdsa") == 0) {
132590bfb57SEric Biggers if (strcmp(encoding, "raw") != 0)
133590bfb57SEric Biggers return -EINVAL;
134590bfb57SEric Biggers if (!hash_algo)
135590bfb57SEric Biggers return -EINVAL;
136590bfb57SEric Biggers if (strcmp(hash_algo, "streebog256") != 0 &&
137590bfb57SEric Biggers strcmp(hash_algo, "streebog512") != 0)
138590bfb57SEric Biggers return -EINVAL;
139590bfb57SEric Biggers } else {
140590bfb57SEric Biggers /* Unknown public key algorithm */
14182f94f24SDavid Howells return -ENOPKG;
14282f94f24SDavid Howells }
143590bfb57SEric Biggers if (strscpy(alg_name, pkey->pkey_algo, CRYPTO_MAX_ALG_NAME) < 0)
144590bfb57SEric Biggers return -EINVAL;
145590bfb57SEric Biggers return 0;
146590bfb57SEric Biggers }
14782f94f24SDavid Howells
pkey_pack_u32(u8 * dst,u32 val)148f1774cb8SVitaly Chikunov static u8 *pkey_pack_u32(u8 *dst, u32 val)
149f1774cb8SVitaly Chikunov {
150f1774cb8SVitaly Chikunov memcpy(dst, &val, sizeof(val));
151f1774cb8SVitaly Chikunov return dst + sizeof(val);
152f1774cb8SVitaly Chikunov }
153f1774cb8SVitaly Chikunov
15482f94f24SDavid Howells /*
15582f94f24SDavid Howells * Query information about a key.
15682f94f24SDavid Howells */
software_key_query(const struct kernel_pkey_params * params,struct kernel_pkey_query * info)15782f94f24SDavid Howells static int software_key_query(const struct kernel_pkey_params *params,
15882f94f24SDavid Howells struct kernel_pkey_query *info)
15982f94f24SDavid Howells {
16082f94f24SDavid Howells struct crypto_akcipher *tfm;
16182f94f24SDavid Howells struct public_key *pkey = params->key->payload.data[asym_crypto];
16282f94f24SDavid Howells char alg_name[CRYPTO_MAX_ALG_NAME];
16363ba4d67SHerbert Xu struct crypto_sig *sig;
164f1774cb8SVitaly Chikunov u8 *key, *ptr;
16582f94f24SDavid Howells int ret, len;
16663ba4d67SHerbert Xu bool issig;
16782f94f24SDavid Howells
168590bfb57SEric Biggers ret = software_key_determine_akcipher(pkey, params->encoding,
16963ba4d67SHerbert Xu params->hash_algo, alg_name,
17063ba4d67SHerbert Xu &issig, kernel_pkey_sign);
17182f94f24SDavid Howells if (ret < 0)
17282f94f24SDavid Howells return ret;
17382f94f24SDavid Howells
174f1774cb8SVitaly Chikunov key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
175f1774cb8SVitaly Chikunov GFP_KERNEL);
176f1774cb8SVitaly Chikunov if (!key)
17763ba4d67SHerbert Xu return -ENOMEM;
17863ba4d67SHerbert Xu
179f1774cb8SVitaly Chikunov memcpy(key, pkey->key, pkey->keylen);
180f1774cb8SVitaly Chikunov ptr = key + pkey->keylen;
181f1774cb8SVitaly Chikunov ptr = pkey_pack_u32(ptr, pkey->algo);
182f1774cb8SVitaly Chikunov ptr = pkey_pack_u32(ptr, pkey->paramlen);
183f1774cb8SVitaly Chikunov memcpy(ptr, pkey->params, pkey->paramlen);
184f1774cb8SVitaly Chikunov
18563ba4d67SHerbert Xu if (issig) {
18663ba4d67SHerbert Xu sig = crypto_alloc_sig(alg_name, 0, 0);
1879e9311e0SDan Carpenter if (IS_ERR(sig)) {
1889e9311e0SDan Carpenter ret = PTR_ERR(sig);
18963ba4d67SHerbert Xu goto error_free_key;
1909e9311e0SDan Carpenter }
19163ba4d67SHerbert Xu
19263ba4d67SHerbert Xu if (pkey->key_is_private)
19363ba4d67SHerbert Xu ret = crypto_sig_set_privkey(sig, key, pkey->keylen);
19463ba4d67SHerbert Xu else
19563ba4d67SHerbert Xu ret = crypto_sig_set_pubkey(sig, key, pkey->keylen);
19663ba4d67SHerbert Xu if (ret < 0)
19763ba4d67SHerbert Xu goto error_free_tfm;
19863ba4d67SHerbert Xu
19963ba4d67SHerbert Xu len = crypto_sig_maxsize(sig);
20063ba4d67SHerbert Xu
20163ba4d67SHerbert Xu info->supported_ops = KEYCTL_SUPPORTS_VERIFY;
20263ba4d67SHerbert Xu if (pkey->key_is_private)
20363ba4d67SHerbert Xu info->supported_ops |= KEYCTL_SUPPORTS_SIGN;
20463ba4d67SHerbert Xu
20563ba4d67SHerbert Xu if (strcmp(params->encoding, "pkcs1") == 0) {
20663ba4d67SHerbert Xu info->supported_ops |= KEYCTL_SUPPORTS_ENCRYPT;
20763ba4d67SHerbert Xu if (pkey->key_is_private)
20863ba4d67SHerbert Xu info->supported_ops |= KEYCTL_SUPPORTS_DECRYPT;
20963ba4d67SHerbert Xu }
21063ba4d67SHerbert Xu } else {
21163ba4d67SHerbert Xu tfm = crypto_alloc_akcipher(alg_name, 0, 0);
2129e9311e0SDan Carpenter if (IS_ERR(tfm)) {
2139e9311e0SDan Carpenter ret = PTR_ERR(tfm);
21463ba4d67SHerbert Xu goto error_free_key;
2159e9311e0SDan Carpenter }
21663ba4d67SHerbert Xu
217f1774cb8SVitaly Chikunov if (pkey->key_is_private)
218f1774cb8SVitaly Chikunov ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
219f1774cb8SVitaly Chikunov else
220f1774cb8SVitaly Chikunov ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
221f1774cb8SVitaly Chikunov if (ret < 0)
22263ba4d67SHerbert Xu goto error_free_tfm;
22382f94f24SDavid Howells
22482f94f24SDavid Howells len = crypto_akcipher_maxsize(tfm);
22563ba4d67SHerbert Xu
22663ba4d67SHerbert Xu info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT;
22763ba4d67SHerbert Xu if (pkey->key_is_private)
22863ba4d67SHerbert Xu info->supported_ops |= KEYCTL_SUPPORTS_DECRYPT;
22963ba4d67SHerbert Xu }
23063ba4d67SHerbert Xu
23182f94f24SDavid Howells info->key_size = len * 8;
23210de7b54SDenis Kenzior
23310de7b54SDenis Kenzior if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) {
23410de7b54SDenis Kenzior /*
23510de7b54SDenis Kenzior * ECDSA key sizes are much smaller than RSA, and thus could
23610de7b54SDenis Kenzior * operate on (hashed) inputs that are larger than key size.
23710de7b54SDenis Kenzior * For example SHA384-hashed input used with secp256r1
23810de7b54SDenis Kenzior * based keys. Set max_data_size to be at least as large as
23910de7b54SDenis Kenzior * the largest supported hash size (SHA512)
24010de7b54SDenis Kenzior */
24110de7b54SDenis Kenzior info->max_data_size = 64;
24210de7b54SDenis Kenzior
24310de7b54SDenis Kenzior /*
24410de7b54SDenis Kenzior * Verify takes ECDSA-Sig (described in RFC 5480) as input,
24510de7b54SDenis Kenzior * which is actually 2 'key_size'-bit integers encoded in
24610de7b54SDenis Kenzior * ASN.1. Account for the ASN.1 encoding overhead here.
24710de7b54SDenis Kenzior */
24810de7b54SDenis Kenzior info->max_sig_size = 2 * (len + 3) + 2;
24910de7b54SDenis Kenzior } else {
25082f94f24SDavid Howells info->max_data_size = len;
25182f94f24SDavid Howells info->max_sig_size = len;
25210de7b54SDenis Kenzior }
25310de7b54SDenis Kenzior
25482f94f24SDavid Howells info->max_enc_size = len;
25582f94f24SDavid Howells info->max_dec_size = len;
25663ba4d67SHerbert Xu
25782f94f24SDavid Howells ret = 0;
25882f94f24SDavid Howells
25963ba4d67SHerbert Xu error_free_tfm:
26063ba4d67SHerbert Xu if (issig)
26163ba4d67SHerbert Xu crypto_free_sig(sig);
26263ba4d67SHerbert Xu else
26363ba4d67SHerbert Xu crypto_free_akcipher(tfm);
264f1774cb8SVitaly Chikunov error_free_key:
2659f3fa6bcSMahmoud Adam kfree_sensitive(key);
26682f94f24SDavid Howells pr_devel("<==%s() = %d\n", __func__, ret);
26782f94f24SDavid Howells return ret;
26882f94f24SDavid Howells }
26982f94f24SDavid Howells
27082f94f24SDavid Howells /*
271c08fed73SDavid Howells * Do encryption, decryption and signing ops.
272c08fed73SDavid Howells */
software_key_eds_op(struct kernel_pkey_params * params,const void * in,void * out)273c08fed73SDavid Howells static int software_key_eds_op(struct kernel_pkey_params *params,
274c08fed73SDavid Howells const void *in, void *out)
275c08fed73SDavid Howells {
276c08fed73SDavid Howells const struct public_key *pkey = params->key->payload.data[asym_crypto];
277c08fed73SDavid Howells char alg_name[CRYPTO_MAX_ALG_NAME];
27863ba4d67SHerbert Xu struct crypto_akcipher *tfm;
27963ba4d67SHerbert Xu struct crypto_sig *sig;
280f1774cb8SVitaly Chikunov char *key, *ptr;
28163ba4d67SHerbert Xu bool issig;
28263ba4d67SHerbert Xu int ksz;
283c08fed73SDavid Howells int ret;
284c08fed73SDavid Howells
285c08fed73SDavid Howells pr_devel("==>%s()\n", __func__);
286c08fed73SDavid Howells
287590bfb57SEric Biggers ret = software_key_determine_akcipher(pkey, params->encoding,
28863ba4d67SHerbert Xu params->hash_algo, alg_name,
28963ba4d67SHerbert Xu &issig, params->op);
290c08fed73SDavid Howells if (ret < 0)
291c08fed73SDavid Howells return ret;
292c08fed73SDavid Howells
293f1774cb8SVitaly Chikunov key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
294f1774cb8SVitaly Chikunov GFP_KERNEL);
295f1774cb8SVitaly Chikunov if (!key)
29663ba4d67SHerbert Xu return -ENOMEM;
297c08fed73SDavid Howells
298f1774cb8SVitaly Chikunov memcpy(key, pkey->key, pkey->keylen);
299f1774cb8SVitaly Chikunov ptr = key + pkey->keylen;
300f1774cb8SVitaly Chikunov ptr = pkey_pack_u32(ptr, pkey->algo);
301f1774cb8SVitaly Chikunov ptr = pkey_pack_u32(ptr, pkey->paramlen);
302f1774cb8SVitaly Chikunov memcpy(ptr, pkey->params, pkey->paramlen);
303f1774cb8SVitaly Chikunov
30463ba4d67SHerbert Xu if (issig) {
30563ba4d67SHerbert Xu sig = crypto_alloc_sig(alg_name, 0, 0);
3069e9311e0SDan Carpenter if (IS_ERR(sig)) {
3079e9311e0SDan Carpenter ret = PTR_ERR(sig);
30863ba4d67SHerbert Xu goto error_free_key;
3099e9311e0SDan Carpenter }
31063ba4d67SHerbert Xu
31163ba4d67SHerbert Xu if (pkey->key_is_private)
31263ba4d67SHerbert Xu ret = crypto_sig_set_privkey(sig, key, pkey->keylen);
31363ba4d67SHerbert Xu else
31463ba4d67SHerbert Xu ret = crypto_sig_set_pubkey(sig, key, pkey->keylen);
31563ba4d67SHerbert Xu if (ret)
31663ba4d67SHerbert Xu goto error_free_tfm;
31763ba4d67SHerbert Xu
31863ba4d67SHerbert Xu ksz = crypto_sig_maxsize(sig);
31963ba4d67SHerbert Xu } else {
32063ba4d67SHerbert Xu tfm = crypto_alloc_akcipher(alg_name, 0, 0);
3219e9311e0SDan Carpenter if (IS_ERR(tfm)) {
3229e9311e0SDan Carpenter ret = PTR_ERR(tfm);
32363ba4d67SHerbert Xu goto error_free_key;
3249e9311e0SDan Carpenter }
32563ba4d67SHerbert Xu
326f1774cb8SVitaly Chikunov if (pkey->key_is_private)
327f1774cb8SVitaly Chikunov ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
328f1774cb8SVitaly Chikunov else
329f1774cb8SVitaly Chikunov ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
330f1774cb8SVitaly Chikunov if (ret)
33163ba4d67SHerbert Xu goto error_free_tfm;
332f1774cb8SVitaly Chikunov
33363ba4d67SHerbert Xu ksz = crypto_akcipher_maxsize(tfm);
33463ba4d67SHerbert Xu }
33563ba4d67SHerbert Xu
33663ba4d67SHerbert Xu ret = -EINVAL;
337c08fed73SDavid Howells
338c08fed73SDavid Howells /* Perform the encryption calculation. */
339c08fed73SDavid Howells switch (params->op) {
340c08fed73SDavid Howells case kernel_pkey_encrypt:
34163ba4d67SHerbert Xu if (issig)
34263ba4d67SHerbert Xu break;
34363ba4d67SHerbert Xu ret = crypto_akcipher_sync_encrypt(tfm, in, params->in_len,
34463ba4d67SHerbert Xu out, params->out_len);
345c08fed73SDavid Howells break;
346c08fed73SDavid Howells case kernel_pkey_decrypt:
34763ba4d67SHerbert Xu if (issig)
34863ba4d67SHerbert Xu break;
34963ba4d67SHerbert Xu ret = crypto_akcipher_sync_decrypt(tfm, in, params->in_len,
35063ba4d67SHerbert Xu out, params->out_len);
351c08fed73SDavid Howells break;
352c08fed73SDavid Howells case kernel_pkey_sign:
35363ba4d67SHerbert Xu if (!issig)
35463ba4d67SHerbert Xu break;
35563ba4d67SHerbert Xu ret = crypto_sig_sign(sig, in, params->in_len,
35663ba4d67SHerbert Xu out, params->out_len);
357c08fed73SDavid Howells break;
358c08fed73SDavid Howells default:
359c08fed73SDavid Howells BUG();
360c08fed73SDavid Howells }
361c08fed73SDavid Howells
362c08fed73SDavid Howells if (ret == 0)
36363ba4d67SHerbert Xu ret = ksz;
364c08fed73SDavid Howells
36563ba4d67SHerbert Xu error_free_tfm:
36663ba4d67SHerbert Xu if (issig)
36763ba4d67SHerbert Xu crypto_free_sig(sig);
36863ba4d67SHerbert Xu else
36963ba4d67SHerbert Xu crypto_free_akcipher(tfm);
370f1774cb8SVitaly Chikunov error_free_key:
3719f3fa6bcSMahmoud Adam kfree_sensitive(key);
372c08fed73SDavid Howells pr_devel("<==%s() = %d\n", __func__, ret);
373c08fed73SDavid Howells return ret;
374c08fed73SDavid Howells }
375c08fed73SDavid Howells
376c08fed73SDavid Howells /*
377a9681bf3SDavid Howells * Verify a signature using a public key.
378a9681bf3SDavid Howells */
public_key_verify_signature(const struct public_key * pkey,const struct public_key_signature * sig)379db6c43bdSTadeusz Struk int public_key_verify_signature(const struct public_key *pkey,
380a9681bf3SDavid Howells const struct public_key_signature *sig)
381a9681bf3SDavid Howells {
38282f94f24SDavid Howells char alg_name[CRYPTO_MAX_ALG_NAME];
38363ba4d67SHerbert Xu struct crypto_sig *tfm;
384f1774cb8SVitaly Chikunov char *key, *ptr;
38563ba4d67SHerbert Xu bool issig;
38672f9a07bSEric Biggers int ret;
387d43de6c7SDavid Howells
388d43de6c7SDavid Howells pr_devel("==>%s()\n", __func__);
389d43de6c7SDavid Howells
390db6c43bdSTadeusz Struk BUG_ON(!pkey);
3913d167d68SDavid Howells BUG_ON(!sig);
392db6c43bdSTadeusz Struk BUG_ON(!sig->s);
3933d167d68SDavid Howells
3942abc9c24SEric Biggers /*
3952abc9c24SEric Biggers * If the signature specifies a public key algorithm, it *must* match
3962abc9c24SEric Biggers * the key's actual public key algorithm.
3972abc9c24SEric Biggers *
3982abc9c24SEric Biggers * Small exception: ECDSA signatures don't specify the curve, but ECDSA
3992abc9c24SEric Biggers * keys do. So the strings can mismatch slightly in that case:
4002abc9c24SEric Biggers * "ecdsa-nist-*" for the key, but "ecdsa" for the signature.
4012abc9c24SEric Biggers */
4022abc9c24SEric Biggers if (sig->pkey_algo) {
4032abc9c24SEric Biggers if (strcmp(pkey->pkey_algo, sig->pkey_algo) != 0 &&
4042abc9c24SEric Biggers (strncmp(pkey->pkey_algo, "ecdsa-", 6) != 0 ||
4052abc9c24SEric Biggers strcmp(sig->pkey_algo, "ecdsa") != 0))
4062abc9c24SEric Biggers return -EKEYREJECTED;
4072abc9c24SEric Biggers }
4082abc9c24SEric Biggers
409590bfb57SEric Biggers ret = software_key_determine_akcipher(pkey, sig->encoding,
41063ba4d67SHerbert Xu sig->hash_algo, alg_name,
41163ba4d67SHerbert Xu &issig, kernel_pkey_verify);
41282f94f24SDavid Howells if (ret < 0)
41382f94f24SDavid Howells return ret;
414db6c43bdSTadeusz Struk
41563ba4d67SHerbert Xu tfm = crypto_alloc_sig(alg_name, 0, 0);
416d43de6c7SDavid Howells if (IS_ERR(tfm))
417d43de6c7SDavid Howells return PTR_ERR(tfm);
4183d167d68SDavid Howells
419f1774cb8SVitaly Chikunov key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
420f1774cb8SVitaly Chikunov GFP_KERNEL);
4219e9311e0SDan Carpenter if (!key) {
4229e9311e0SDan Carpenter ret = -ENOMEM;
42363ba4d67SHerbert Xu goto error_free_tfm;
4249e9311e0SDan Carpenter }
425d43de6c7SDavid Howells
426f1774cb8SVitaly Chikunov memcpy(key, pkey->key, pkey->keylen);
427f1774cb8SVitaly Chikunov ptr = key + pkey->keylen;
428f1774cb8SVitaly Chikunov ptr = pkey_pack_u32(ptr, pkey->algo);
429f1774cb8SVitaly Chikunov ptr = pkey_pack_u32(ptr, pkey->paramlen);
430f1774cb8SVitaly Chikunov memcpy(ptr, pkey->params, pkey->paramlen);
431f1774cb8SVitaly Chikunov
432f1774cb8SVitaly Chikunov if (pkey->key_is_private)
43363ba4d67SHerbert Xu ret = crypto_sig_set_privkey(tfm, key, pkey->keylen);
434f1774cb8SVitaly Chikunov else
43563ba4d67SHerbert Xu ret = crypto_sig_set_pubkey(tfm, key, pkey->keylen);
436f1774cb8SVitaly Chikunov if (ret)
437f1774cb8SVitaly Chikunov goto error_free_key;
438f1774cb8SVitaly Chikunov
43963ba4d67SHerbert Xu ret = crypto_sig_verify(tfm, sig->s, sig->s_size,
44063ba4d67SHerbert Xu sig->digest, sig->digest_size);
441d43de6c7SDavid Howells
442f1774cb8SVitaly Chikunov error_free_key:
4439f3fa6bcSMahmoud Adam kfree_sensitive(key);
444d43de6c7SDavid Howells error_free_tfm:
44563ba4d67SHerbert Xu crypto_free_sig(tfm);
446d43de6c7SDavid Howells pr_devel("<==%s() = %d\n", __func__, ret);
44772f9a07bSEric Biggers if (WARN_ON_ONCE(ret > 0))
44872f9a07bSEric Biggers ret = -EINVAL;
449d43de6c7SDavid Howells return ret;
4503d167d68SDavid Howells }
4513d167d68SDavid Howells EXPORT_SYMBOL_GPL(public_key_verify_signature);
4523d167d68SDavid Howells
public_key_verify_signature_2(const struct key * key,const struct public_key_signature * sig)4533d167d68SDavid Howells static int public_key_verify_signature_2(const struct key *key,
4543d167d68SDavid Howells const struct public_key_signature *sig)
4553d167d68SDavid Howells {
456146aa8b1SDavid Howells const struct public_key *pk = key->payload.data[asym_crypto];
4573d167d68SDavid Howells return public_key_verify_signature(pk, sig);
458a9681bf3SDavid Howells }
459a9681bf3SDavid Howells
460a9681bf3SDavid Howells /*
461a9681bf3SDavid Howells * Public key algorithm asymmetric key subtype
462a9681bf3SDavid Howells */
463a9681bf3SDavid Howells struct asymmetric_key_subtype public_key_subtype = {
464a9681bf3SDavid Howells .owner = THIS_MODULE,
465a9681bf3SDavid Howells .name = "public_key",
466876c6e3eSDavid Howells .name_len = sizeof("public_key") - 1,
467a9681bf3SDavid Howells .describe = public_key_describe,
468a9681bf3SDavid Howells .destroy = public_key_destroy,
46982f94f24SDavid Howells .query = software_key_query,
470c08fed73SDavid Howells .eds_op = software_key_eds_op,
4713d167d68SDavid Howells .verify_signature = public_key_verify_signature_2,
472a9681bf3SDavid Howells };
473a9681bf3SDavid Howells EXPORT_SYMBOL_GPL(public_key_subtype);
474