18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* In-software asymmetric public-key crypto subtype 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * See Documentation/crypto/asymmetric-keys.rst 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 78c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "PKEY: "fmt 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/export.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 168c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 178c2ecf20Sopenharmony_ci#include <linux/asn1.h> 188c2ecf20Sopenharmony_ci#include <keys/asymmetric-subtype.h> 198c2ecf20Sopenharmony_ci#include <crypto/public_key.h> 208c2ecf20Sopenharmony_ci#include <crypto/akcipher.h> 218c2ecf20Sopenharmony_ci#include <crypto/sm2.h> 228c2ecf20Sopenharmony_ci#include <crypto/sm3_base.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("In-software asymmetric public-key subtype"); 258c2ecf20Sopenharmony_ciMODULE_AUTHOR("Red Hat, Inc."); 268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Provide a part of a description of the key for /proc/keys. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_cistatic void public_key_describe(const struct key *asymmetric_key, 328c2ecf20Sopenharmony_ci struct seq_file *m) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct public_key *key = asymmetric_key->payload.data[asym_crypto]; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (key) 378c2ecf20Sopenharmony_ci seq_printf(m, "%s.%s", key->id_type, key->pkey_algo); 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * Destroy a public key algorithm key. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_civoid public_key_free(struct public_key *key) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci if (key) { 468c2ecf20Sopenharmony_ci kfree(key->key); 478c2ecf20Sopenharmony_ci kfree(key->params); 488c2ecf20Sopenharmony_ci kfree(key); 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(public_key_free); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* 548c2ecf20Sopenharmony_ci * Destroy a public key algorithm key. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistatic void public_key_destroy(void *payload0, void *payload3) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci public_key_free(payload0); 598c2ecf20Sopenharmony_ci public_key_signature_free(payload3); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci/* 638c2ecf20Sopenharmony_ci * Given a public_key, and an encoding and hash_algo to be used for signing 648c2ecf20Sopenharmony_ci * and/or verification with that key, determine the name of the corresponding 658c2ecf20Sopenharmony_ci * akcipher algorithm. Also check that encoding and hash_algo are allowed. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistatic int 688c2ecf20Sopenharmony_cisoftware_key_determine_akcipher(const struct public_key *pkey, 698c2ecf20Sopenharmony_ci const char *encoding, const char *hash_algo, 708c2ecf20Sopenharmony_ci char alg_name[CRYPTO_MAX_ALG_NAME]) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int n; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (!encoding) 758c2ecf20Sopenharmony_ci return -EINVAL; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (strcmp(pkey->pkey_algo, "rsa") == 0) { 788c2ecf20Sopenharmony_ci /* 798c2ecf20Sopenharmony_ci * RSA signatures usually use EMSA-PKCS1-1_5 [RFC3447 sec 8.2]. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci if (strcmp(encoding, "pkcs1") == 0) { 828c2ecf20Sopenharmony_ci if (!hash_algo) 838c2ecf20Sopenharmony_ci n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, 848c2ecf20Sopenharmony_ci "pkcs1pad(%s)", 858c2ecf20Sopenharmony_ci pkey->pkey_algo); 868c2ecf20Sopenharmony_ci else 878c2ecf20Sopenharmony_ci n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, 888c2ecf20Sopenharmony_ci "pkcs1pad(%s,%s)", 898c2ecf20Sopenharmony_ci pkey->pkey_algo, hash_algo); 908c2ecf20Sopenharmony_ci return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci if (strcmp(encoding, "raw") != 0) 938c2ecf20Sopenharmony_ci return -EINVAL; 948c2ecf20Sopenharmony_ci /* 958c2ecf20Sopenharmony_ci * Raw RSA cannot differentiate between different hash 968c2ecf20Sopenharmony_ci * algorithms. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci if (hash_algo) 998c2ecf20Sopenharmony_ci return -EINVAL; 1008c2ecf20Sopenharmony_ci } else if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { 1018c2ecf20Sopenharmony_ci if (strcmp(encoding, "x962") != 0) 1028c2ecf20Sopenharmony_ci return -EINVAL; 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * ECDSA signatures are taken over a raw hash, so they don't 1058c2ecf20Sopenharmony_ci * differentiate between different hash algorithms. That means 1068c2ecf20Sopenharmony_ci * that the verifier should hard-code a specific hash algorithm. 1078c2ecf20Sopenharmony_ci * Unfortunately, in practice ECDSA is used with multiple SHAs, 1088c2ecf20Sopenharmony_ci * so we have to allow all of them and not just one. 1098c2ecf20Sopenharmony_ci */ 1108c2ecf20Sopenharmony_ci if (!hash_algo) 1118c2ecf20Sopenharmony_ci return -EINVAL; 1128c2ecf20Sopenharmony_ci if (strcmp(hash_algo, "sha1") != 0 && 1138c2ecf20Sopenharmony_ci strcmp(hash_algo, "sha224") != 0 && 1148c2ecf20Sopenharmony_ci strcmp(hash_algo, "sha256") != 0 && 1158c2ecf20Sopenharmony_ci strcmp(hash_algo, "sha384") != 0 && 1168c2ecf20Sopenharmony_ci strcmp(hash_algo, "sha512") != 0) 1178c2ecf20Sopenharmony_ci return -EINVAL; 1188c2ecf20Sopenharmony_ci } else if (strcmp(pkey->pkey_algo, "sm2") == 0) { 1198c2ecf20Sopenharmony_ci if (strcmp(encoding, "raw") != 0) 1208c2ecf20Sopenharmony_ci return -EINVAL; 1218c2ecf20Sopenharmony_ci if (!hash_algo) 1228c2ecf20Sopenharmony_ci return -EINVAL; 1238c2ecf20Sopenharmony_ci if (strcmp(hash_algo, "sm3") != 0) 1248c2ecf20Sopenharmony_ci return -EINVAL; 1258c2ecf20Sopenharmony_ci } else if (strcmp(pkey->pkey_algo, "ecrdsa") == 0) { 1268c2ecf20Sopenharmony_ci if (strcmp(encoding, "raw") != 0) 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci if (!hash_algo) 1298c2ecf20Sopenharmony_ci return -EINVAL; 1308c2ecf20Sopenharmony_ci if (strcmp(hash_algo, "streebog256") != 0 && 1318c2ecf20Sopenharmony_ci strcmp(hash_algo, "streebog512") != 0) 1328c2ecf20Sopenharmony_ci return -EINVAL; 1338c2ecf20Sopenharmony_ci } else { 1348c2ecf20Sopenharmony_ci /* Unknown public key algorithm */ 1358c2ecf20Sopenharmony_ci return -ENOPKG; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci if (strscpy(alg_name, pkey->pkey_algo, CRYPTO_MAX_ALG_NAME) < 0) 1388c2ecf20Sopenharmony_ci return -EINVAL; 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic u8 *pkey_pack_u32(u8 *dst, u32 val) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci memcpy(dst, &val, sizeof(val)); 1458c2ecf20Sopenharmony_ci return dst + sizeof(val); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/* 1498c2ecf20Sopenharmony_ci * Query information about a key. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_cistatic int software_key_query(const struct kernel_pkey_params *params, 1528c2ecf20Sopenharmony_ci struct kernel_pkey_query *info) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci struct crypto_akcipher *tfm; 1558c2ecf20Sopenharmony_ci struct public_key *pkey = params->key->payload.data[asym_crypto]; 1568c2ecf20Sopenharmony_ci char alg_name[CRYPTO_MAX_ALG_NAME]; 1578c2ecf20Sopenharmony_ci u8 *key, *ptr; 1588c2ecf20Sopenharmony_ci int ret, len; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ret = software_key_determine_akcipher(pkey, params->encoding, 1618c2ecf20Sopenharmony_ci params->hash_algo, alg_name); 1628c2ecf20Sopenharmony_ci if (ret < 0) 1638c2ecf20Sopenharmony_ci return ret; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci tfm = crypto_alloc_akcipher(alg_name, 0, 0); 1668c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 1678c2ecf20Sopenharmony_ci return PTR_ERR(tfm); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci ret = -ENOMEM; 1708c2ecf20Sopenharmony_ci key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, 1718c2ecf20Sopenharmony_ci GFP_KERNEL); 1728c2ecf20Sopenharmony_ci if (!key) 1738c2ecf20Sopenharmony_ci goto error_free_tfm; 1748c2ecf20Sopenharmony_ci memcpy(key, pkey->key, pkey->keylen); 1758c2ecf20Sopenharmony_ci ptr = key + pkey->keylen; 1768c2ecf20Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->algo); 1778c2ecf20Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->paramlen); 1788c2ecf20Sopenharmony_ci memcpy(ptr, pkey->params, pkey->paramlen); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (pkey->key_is_private) 1818c2ecf20Sopenharmony_ci ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); 1828c2ecf20Sopenharmony_ci else 1838c2ecf20Sopenharmony_ci ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); 1848c2ecf20Sopenharmony_ci if (ret < 0) 1858c2ecf20Sopenharmony_ci goto error_free_key; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci len = crypto_akcipher_maxsize(tfm); 1888c2ecf20Sopenharmony_ci info->key_size = len * 8; 1898c2ecf20Sopenharmony_ci info->max_data_size = len; 1908c2ecf20Sopenharmony_ci info->max_sig_size = len; 1918c2ecf20Sopenharmony_ci info->max_enc_size = len; 1928c2ecf20Sopenharmony_ci info->max_dec_size = len; 1938c2ecf20Sopenharmony_ci info->supported_ops = (KEYCTL_SUPPORTS_ENCRYPT | 1948c2ecf20Sopenharmony_ci KEYCTL_SUPPORTS_VERIFY); 1958c2ecf20Sopenharmony_ci if (pkey->key_is_private) 1968c2ecf20Sopenharmony_ci info->supported_ops |= (KEYCTL_SUPPORTS_DECRYPT | 1978c2ecf20Sopenharmony_ci KEYCTL_SUPPORTS_SIGN); 1988c2ecf20Sopenharmony_ci ret = 0; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cierror_free_key: 2018c2ecf20Sopenharmony_ci kfree(key); 2028c2ecf20Sopenharmony_cierror_free_tfm: 2038c2ecf20Sopenharmony_ci crypto_free_akcipher(tfm); 2048c2ecf20Sopenharmony_ci pr_devel("<==%s() = %d\n", __func__, ret); 2058c2ecf20Sopenharmony_ci return ret; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci/* 2098c2ecf20Sopenharmony_ci * Do encryption, decryption and signing ops. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_cistatic int software_key_eds_op(struct kernel_pkey_params *params, 2128c2ecf20Sopenharmony_ci const void *in, void *out) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci const struct public_key *pkey = params->key->payload.data[asym_crypto]; 2158c2ecf20Sopenharmony_ci struct akcipher_request *req; 2168c2ecf20Sopenharmony_ci struct crypto_akcipher *tfm; 2178c2ecf20Sopenharmony_ci struct crypto_wait cwait; 2188c2ecf20Sopenharmony_ci struct scatterlist in_sg, out_sg; 2198c2ecf20Sopenharmony_ci char alg_name[CRYPTO_MAX_ALG_NAME]; 2208c2ecf20Sopenharmony_ci char *key, *ptr; 2218c2ecf20Sopenharmony_ci int ret; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci pr_devel("==>%s()\n", __func__); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci ret = software_key_determine_akcipher(pkey, params->encoding, 2268c2ecf20Sopenharmony_ci params->hash_algo, alg_name); 2278c2ecf20Sopenharmony_ci if (ret < 0) 2288c2ecf20Sopenharmony_ci return ret; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci tfm = crypto_alloc_akcipher(alg_name, 0, 0); 2318c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 2328c2ecf20Sopenharmony_ci return PTR_ERR(tfm); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ret = -ENOMEM; 2358c2ecf20Sopenharmony_ci req = akcipher_request_alloc(tfm, GFP_KERNEL); 2368c2ecf20Sopenharmony_ci if (!req) 2378c2ecf20Sopenharmony_ci goto error_free_tfm; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, 2408c2ecf20Sopenharmony_ci GFP_KERNEL); 2418c2ecf20Sopenharmony_ci if (!key) 2428c2ecf20Sopenharmony_ci goto error_free_req; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci memcpy(key, pkey->key, pkey->keylen); 2458c2ecf20Sopenharmony_ci ptr = key + pkey->keylen; 2468c2ecf20Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->algo); 2478c2ecf20Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->paramlen); 2488c2ecf20Sopenharmony_ci memcpy(ptr, pkey->params, pkey->paramlen); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (pkey->key_is_private) 2518c2ecf20Sopenharmony_ci ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); 2528c2ecf20Sopenharmony_ci else 2538c2ecf20Sopenharmony_ci ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); 2548c2ecf20Sopenharmony_ci if (ret) 2558c2ecf20Sopenharmony_ci goto error_free_key; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci sg_init_one(&in_sg, in, params->in_len); 2588c2ecf20Sopenharmony_ci sg_init_one(&out_sg, out, params->out_len); 2598c2ecf20Sopenharmony_ci akcipher_request_set_crypt(req, &in_sg, &out_sg, params->in_len, 2608c2ecf20Sopenharmony_ci params->out_len); 2618c2ecf20Sopenharmony_ci crypto_init_wait(&cwait); 2628c2ecf20Sopenharmony_ci akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | 2638c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP, 2648c2ecf20Sopenharmony_ci crypto_req_done, &cwait); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* Perform the encryption calculation. */ 2678c2ecf20Sopenharmony_ci switch (params->op) { 2688c2ecf20Sopenharmony_ci case kernel_pkey_encrypt: 2698c2ecf20Sopenharmony_ci ret = crypto_akcipher_encrypt(req); 2708c2ecf20Sopenharmony_ci break; 2718c2ecf20Sopenharmony_ci case kernel_pkey_decrypt: 2728c2ecf20Sopenharmony_ci ret = crypto_akcipher_decrypt(req); 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci case kernel_pkey_sign: 2758c2ecf20Sopenharmony_ci ret = crypto_akcipher_sign(req); 2768c2ecf20Sopenharmony_ci break; 2778c2ecf20Sopenharmony_ci default: 2788c2ecf20Sopenharmony_ci BUG(); 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ret = crypto_wait_req(ret, &cwait); 2828c2ecf20Sopenharmony_ci if (ret == 0) 2838c2ecf20Sopenharmony_ci ret = req->dst_len; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cierror_free_key: 2868c2ecf20Sopenharmony_ci kfree(key); 2878c2ecf20Sopenharmony_cierror_free_req: 2888c2ecf20Sopenharmony_ci akcipher_request_free(req); 2898c2ecf20Sopenharmony_cierror_free_tfm: 2908c2ecf20Sopenharmony_ci crypto_free_akcipher(tfm); 2918c2ecf20Sopenharmony_ci pr_devel("<==%s() = %d\n", __func__, ret); 2928c2ecf20Sopenharmony_ci return ret; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci#if IS_REACHABLE(CONFIG_CRYPTO_SM2) 2968c2ecf20Sopenharmony_cistatic int cert_sig_digest_update(const struct public_key_signature *sig, 2978c2ecf20Sopenharmony_ci struct crypto_akcipher *tfm_pkey) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct crypto_shash *tfm; 3008c2ecf20Sopenharmony_ci struct shash_desc *desc; 3018c2ecf20Sopenharmony_ci size_t desc_size; 3028c2ecf20Sopenharmony_ci unsigned char dgst[SM3_DIGEST_SIZE]; 3038c2ecf20Sopenharmony_ci int ret; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci BUG_ON(!sig->data); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* SM2 signatures always use the SM3 hash algorithm */ 3088c2ecf20Sopenharmony_ci if (!sig->hash_algo || strcmp(sig->hash_algo, "sm3") != 0) 3098c2ecf20Sopenharmony_ci return -EINVAL; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci ret = sm2_compute_z_digest(tfm_pkey, SM2_DEFAULT_USERID, 3128c2ecf20Sopenharmony_ci SM2_DEFAULT_USERID_LEN, dgst); 3138c2ecf20Sopenharmony_ci if (ret) 3148c2ecf20Sopenharmony_ci return ret; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); 3178c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 3188c2ecf20Sopenharmony_ci return PTR_ERR(tfm); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); 3218c2ecf20Sopenharmony_ci desc = kzalloc(desc_size, GFP_KERNEL); 3228c2ecf20Sopenharmony_ci if (!desc) { 3238c2ecf20Sopenharmony_ci ret = -ENOMEM; 3248c2ecf20Sopenharmony_ci goto error_free_tfm; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci desc->tfm = tfm; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci ret = crypto_shash_init(desc); 3308c2ecf20Sopenharmony_ci if (ret < 0) 3318c2ecf20Sopenharmony_ci goto error_free_desc; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci ret = crypto_shash_update(desc, dgst, SM3_DIGEST_SIZE); 3348c2ecf20Sopenharmony_ci if (ret < 0) 3358c2ecf20Sopenharmony_ci goto error_free_desc; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci ret = crypto_shash_finup(desc, sig->data, sig->data_size, sig->digest); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cierror_free_desc: 3408c2ecf20Sopenharmony_ci kfree(desc); 3418c2ecf20Sopenharmony_cierror_free_tfm: 3428c2ecf20Sopenharmony_ci crypto_free_shash(tfm); 3438c2ecf20Sopenharmony_ci return ret; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci#else 3468c2ecf20Sopenharmony_cistatic inline int cert_sig_digest_update( 3478c2ecf20Sopenharmony_ci const struct public_key_signature *sig, 3488c2ecf20Sopenharmony_ci struct crypto_akcipher *tfm_pkey) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci return -ENOTSUPP; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci#endif /* ! IS_REACHABLE(CONFIG_CRYPTO_SM2) */ 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/* 3558c2ecf20Sopenharmony_ci * Verify a signature using a public key. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ciint public_key_verify_signature(const struct public_key *pkey, 3588c2ecf20Sopenharmony_ci const struct public_key_signature *sig) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct crypto_wait cwait; 3618c2ecf20Sopenharmony_ci struct crypto_akcipher *tfm; 3628c2ecf20Sopenharmony_ci struct akcipher_request *req; 3638c2ecf20Sopenharmony_ci struct scatterlist src_sg; 3648c2ecf20Sopenharmony_ci char alg_name[CRYPTO_MAX_ALG_NAME]; 3658c2ecf20Sopenharmony_ci char *buf, *ptr; 3668c2ecf20Sopenharmony_ci size_t buf_len; 3678c2ecf20Sopenharmony_ci int ret; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci pr_devel("==>%s()\n", __func__); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci BUG_ON(!pkey); 3728c2ecf20Sopenharmony_ci BUG_ON(!sig); 3738c2ecf20Sopenharmony_ci BUG_ON(!sig->s); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* 3768c2ecf20Sopenharmony_ci * If the signature specifies a public key algorithm, it *must* match 3778c2ecf20Sopenharmony_ci * the key's actual public key algorithm. 3788c2ecf20Sopenharmony_ci * 3798c2ecf20Sopenharmony_ci * Small exception: ECDSA signatures don't specify the curve, but ECDSA 3808c2ecf20Sopenharmony_ci * keys do. So the strings can mismatch slightly in that case: 3818c2ecf20Sopenharmony_ci * "ecdsa-nist-*" for the key, but "ecdsa" for the signature. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ci if (sig->pkey_algo) { 3848c2ecf20Sopenharmony_ci if (strcmp(pkey->pkey_algo, sig->pkey_algo) != 0 && 3858c2ecf20Sopenharmony_ci (strncmp(pkey->pkey_algo, "ecdsa-", 6) != 0 || 3868c2ecf20Sopenharmony_ci strcmp(sig->pkey_algo, "ecdsa") != 0)) 3878c2ecf20Sopenharmony_ci return -EKEYREJECTED; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci ret = software_key_determine_akcipher(pkey, sig->encoding, 3918c2ecf20Sopenharmony_ci sig->hash_algo, alg_name); 3928c2ecf20Sopenharmony_ci if (ret < 0) 3938c2ecf20Sopenharmony_ci return ret; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci tfm = crypto_alloc_akcipher(alg_name, 0, 0); 3968c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 3978c2ecf20Sopenharmony_ci return PTR_ERR(tfm); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci ret = -ENOMEM; 4008c2ecf20Sopenharmony_ci req = akcipher_request_alloc(tfm, GFP_KERNEL); 4018c2ecf20Sopenharmony_ci if (!req) 4028c2ecf20Sopenharmony_ci goto error_free_tfm; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci buf_len = max_t(size_t, pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, 4058c2ecf20Sopenharmony_ci sig->s_size + sig->digest_size); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci buf = kmalloc(buf_len, GFP_KERNEL); 4088c2ecf20Sopenharmony_ci if (!buf) 4098c2ecf20Sopenharmony_ci goto error_free_req; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci memcpy(buf, pkey->key, pkey->keylen); 4128c2ecf20Sopenharmony_ci ptr = buf + pkey->keylen; 4138c2ecf20Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->algo); 4148c2ecf20Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->paramlen); 4158c2ecf20Sopenharmony_ci memcpy(ptr, pkey->params, pkey->paramlen); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (pkey->key_is_private) 4188c2ecf20Sopenharmony_ci ret = crypto_akcipher_set_priv_key(tfm, buf, pkey->keylen); 4198c2ecf20Sopenharmony_ci else 4208c2ecf20Sopenharmony_ci ret = crypto_akcipher_set_pub_key(tfm, buf, pkey->keylen); 4218c2ecf20Sopenharmony_ci if (ret) 4228c2ecf20Sopenharmony_ci goto error_free_buf; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (strcmp(pkey->pkey_algo, "sm2") == 0 && sig->data_size) { 4258c2ecf20Sopenharmony_ci ret = cert_sig_digest_update(sig, tfm); 4268c2ecf20Sopenharmony_ci if (ret) 4278c2ecf20Sopenharmony_ci goto error_free_buf; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci memcpy(buf, sig->s, sig->s_size); 4318c2ecf20Sopenharmony_ci memcpy(buf + sig->s_size, sig->digest, sig->digest_size); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci sg_init_one(&src_sg, buf, sig->s_size + sig->digest_size); 4348c2ecf20Sopenharmony_ci akcipher_request_set_crypt(req, &src_sg, NULL, sig->s_size, 4358c2ecf20Sopenharmony_ci sig->digest_size); 4368c2ecf20Sopenharmony_ci crypto_init_wait(&cwait); 4378c2ecf20Sopenharmony_ci akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | 4388c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MAY_SLEEP, 4398c2ecf20Sopenharmony_ci crypto_req_done, &cwait); 4408c2ecf20Sopenharmony_ci ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cierror_free_buf: 4438c2ecf20Sopenharmony_ci kfree(buf); 4448c2ecf20Sopenharmony_cierror_free_req: 4458c2ecf20Sopenharmony_ci akcipher_request_free(req); 4468c2ecf20Sopenharmony_cierror_free_tfm: 4478c2ecf20Sopenharmony_ci crypto_free_akcipher(tfm); 4488c2ecf20Sopenharmony_ci pr_devel("<==%s() = %d\n", __func__, ret); 4498c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(ret > 0)) 4508c2ecf20Sopenharmony_ci ret = -EINVAL; 4518c2ecf20Sopenharmony_ci return ret; 4528c2ecf20Sopenharmony_ci} 4538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(public_key_verify_signature); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic int public_key_verify_signature_2(const struct key *key, 4568c2ecf20Sopenharmony_ci const struct public_key_signature *sig) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci const struct public_key *pk = key->payload.data[asym_crypto]; 4598c2ecf20Sopenharmony_ci return public_key_verify_signature(pk, sig); 4608c2ecf20Sopenharmony_ci} 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci/* 4638c2ecf20Sopenharmony_ci * Public key algorithm asymmetric key subtype 4648c2ecf20Sopenharmony_ci */ 4658c2ecf20Sopenharmony_cistruct asymmetric_key_subtype public_key_subtype = { 4668c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4678c2ecf20Sopenharmony_ci .name = "public_key", 4688c2ecf20Sopenharmony_ci .name_len = sizeof("public_key") - 1, 4698c2ecf20Sopenharmony_ci .describe = public_key_describe, 4708c2ecf20Sopenharmony_ci .destroy = public_key_destroy, 4718c2ecf20Sopenharmony_ci .query = software_key_query, 4728c2ecf20Sopenharmony_ci .eds_op = software_key_eds_op, 4738c2ecf20Sopenharmony_ci .verify_signature = public_key_verify_signature_2, 4748c2ecf20Sopenharmony_ci}; 4758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(public_key_subtype); 476