162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* In-software asymmetric public-key crypto subtype 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * See Documentation/crypto/asymmetric-keys.rst 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. 762306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define pr_fmt(fmt) "PKEY: "fmt 1162306a36Sopenharmony_ci#include <crypto/akcipher.h> 1262306a36Sopenharmony_ci#include <crypto/public_key.h> 1362306a36Sopenharmony_ci#include <crypto/sig.h> 1462306a36Sopenharmony_ci#include <keys/asymmetric-subtype.h> 1562306a36Sopenharmony_ci#include <linux/asn1.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/kernel.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/seq_file.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/string.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciMODULE_DESCRIPTION("In-software asymmetric public-key subtype"); 2462306a36Sopenharmony_ciMODULE_AUTHOR("Red Hat, Inc."); 2562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Provide a part of a description of the key for /proc/keys. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_cistatic void public_key_describe(const struct key *asymmetric_key, 3162306a36Sopenharmony_ci struct seq_file *m) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct public_key *key = asymmetric_key->payload.data[asym_crypto]; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (key) 3662306a36Sopenharmony_ci seq_printf(m, "%s.%s", key->id_type, key->pkey_algo); 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci/* 4062306a36Sopenharmony_ci * Destroy a public key algorithm key. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_civoid public_key_free(struct public_key *key) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci if (key) { 4562306a36Sopenharmony_ci kfree_sensitive(key->key); 4662306a36Sopenharmony_ci kfree(key->params); 4762306a36Sopenharmony_ci kfree(key); 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(public_key_free); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * Destroy a public key algorithm key. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistatic void public_key_destroy(void *payload0, void *payload3) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci public_key_free(payload0); 5862306a36Sopenharmony_ci public_key_signature_free(payload3); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci/* 6262306a36Sopenharmony_ci * Given a public_key, and an encoding and hash_algo to be used for signing 6362306a36Sopenharmony_ci * and/or verification with that key, determine the name of the corresponding 6462306a36Sopenharmony_ci * akcipher algorithm. Also check that encoding and hash_algo are allowed. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistatic int 6762306a36Sopenharmony_cisoftware_key_determine_akcipher(const struct public_key *pkey, 6862306a36Sopenharmony_ci const char *encoding, const char *hash_algo, 6962306a36Sopenharmony_ci char alg_name[CRYPTO_MAX_ALG_NAME], bool *sig, 7062306a36Sopenharmony_ci enum kernel_pkey_operation op) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci int n; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci *sig = true; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (!encoding) 7762306a36Sopenharmony_ci return -EINVAL; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (strcmp(pkey->pkey_algo, "rsa") == 0) { 8062306a36Sopenharmony_ci /* 8162306a36Sopenharmony_ci * RSA signatures usually use EMSA-PKCS1-1_5 [RFC3447 sec 8.2]. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci if (strcmp(encoding, "pkcs1") == 0) { 8462306a36Sopenharmony_ci *sig = op == kernel_pkey_sign || 8562306a36Sopenharmony_ci op == kernel_pkey_verify; 8662306a36Sopenharmony_ci if (!hash_algo) { 8762306a36Sopenharmony_ci n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, 8862306a36Sopenharmony_ci "pkcs1pad(%s)", 8962306a36Sopenharmony_ci pkey->pkey_algo); 9062306a36Sopenharmony_ci } else { 9162306a36Sopenharmony_ci n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME, 9262306a36Sopenharmony_ci "pkcs1pad(%s,%s)", 9362306a36Sopenharmony_ci pkey->pkey_algo, hash_algo); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci if (strcmp(encoding, "raw") != 0) 9862306a36Sopenharmony_ci return -EINVAL; 9962306a36Sopenharmony_ci /* 10062306a36Sopenharmony_ci * Raw RSA cannot differentiate between different hash 10162306a36Sopenharmony_ci * algorithms. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci if (hash_algo) 10462306a36Sopenharmony_ci return -EINVAL; 10562306a36Sopenharmony_ci *sig = false; 10662306a36Sopenharmony_ci } else if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { 10762306a36Sopenharmony_ci if (strcmp(encoding, "x962") != 0) 10862306a36Sopenharmony_ci return -EINVAL; 10962306a36Sopenharmony_ci /* 11062306a36Sopenharmony_ci * ECDSA signatures are taken over a raw hash, so they don't 11162306a36Sopenharmony_ci * differentiate between different hash algorithms. That means 11262306a36Sopenharmony_ci * that the verifier should hard-code a specific hash algorithm. 11362306a36Sopenharmony_ci * Unfortunately, in practice ECDSA is used with multiple SHAs, 11462306a36Sopenharmony_ci * so we have to allow all of them and not just one. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_ci if (!hash_algo) 11762306a36Sopenharmony_ci return -EINVAL; 11862306a36Sopenharmony_ci if (strcmp(hash_algo, "sha1") != 0 && 11962306a36Sopenharmony_ci strcmp(hash_algo, "sha224") != 0 && 12062306a36Sopenharmony_ci strcmp(hash_algo, "sha256") != 0 && 12162306a36Sopenharmony_ci strcmp(hash_algo, "sha384") != 0 && 12262306a36Sopenharmony_ci strcmp(hash_algo, "sha512") != 0) 12362306a36Sopenharmony_ci return -EINVAL; 12462306a36Sopenharmony_ci } else if (strcmp(pkey->pkey_algo, "sm2") == 0) { 12562306a36Sopenharmony_ci if (strcmp(encoding, "raw") != 0) 12662306a36Sopenharmony_ci return -EINVAL; 12762306a36Sopenharmony_ci if (!hash_algo) 12862306a36Sopenharmony_ci return -EINVAL; 12962306a36Sopenharmony_ci if (strcmp(hash_algo, "sm3") != 0) 13062306a36Sopenharmony_ci return -EINVAL; 13162306a36Sopenharmony_ci } else if (strcmp(pkey->pkey_algo, "ecrdsa") == 0) { 13262306a36Sopenharmony_ci if (strcmp(encoding, "raw") != 0) 13362306a36Sopenharmony_ci return -EINVAL; 13462306a36Sopenharmony_ci if (!hash_algo) 13562306a36Sopenharmony_ci return -EINVAL; 13662306a36Sopenharmony_ci if (strcmp(hash_algo, "streebog256") != 0 && 13762306a36Sopenharmony_ci strcmp(hash_algo, "streebog512") != 0) 13862306a36Sopenharmony_ci return -EINVAL; 13962306a36Sopenharmony_ci } else { 14062306a36Sopenharmony_ci /* Unknown public key algorithm */ 14162306a36Sopenharmony_ci return -ENOPKG; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci if (strscpy(alg_name, pkey->pkey_algo, CRYPTO_MAX_ALG_NAME) < 0) 14462306a36Sopenharmony_ci return -EINVAL; 14562306a36Sopenharmony_ci return 0; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic u8 *pkey_pack_u32(u8 *dst, u32 val) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci memcpy(dst, &val, sizeof(val)); 15162306a36Sopenharmony_ci return dst + sizeof(val); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* 15562306a36Sopenharmony_ci * Query information about a key. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistatic int software_key_query(const struct kernel_pkey_params *params, 15862306a36Sopenharmony_ci struct kernel_pkey_query *info) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct crypto_akcipher *tfm; 16162306a36Sopenharmony_ci struct public_key *pkey = params->key->payload.data[asym_crypto]; 16262306a36Sopenharmony_ci char alg_name[CRYPTO_MAX_ALG_NAME]; 16362306a36Sopenharmony_ci struct crypto_sig *sig; 16462306a36Sopenharmony_ci u8 *key, *ptr; 16562306a36Sopenharmony_ci int ret, len; 16662306a36Sopenharmony_ci bool issig; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci ret = software_key_determine_akcipher(pkey, params->encoding, 16962306a36Sopenharmony_ci params->hash_algo, alg_name, 17062306a36Sopenharmony_ci &issig, kernel_pkey_sign); 17162306a36Sopenharmony_ci if (ret < 0) 17262306a36Sopenharmony_ci return ret; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, 17562306a36Sopenharmony_ci GFP_KERNEL); 17662306a36Sopenharmony_ci if (!key) 17762306a36Sopenharmony_ci return -ENOMEM; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci memcpy(key, pkey->key, pkey->keylen); 18062306a36Sopenharmony_ci ptr = key + pkey->keylen; 18162306a36Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->algo); 18262306a36Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->paramlen); 18362306a36Sopenharmony_ci memcpy(ptr, pkey->params, pkey->paramlen); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (issig) { 18662306a36Sopenharmony_ci sig = crypto_alloc_sig(alg_name, 0, 0); 18762306a36Sopenharmony_ci if (IS_ERR(sig)) { 18862306a36Sopenharmony_ci ret = PTR_ERR(sig); 18962306a36Sopenharmony_ci goto error_free_key; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (pkey->key_is_private) 19362306a36Sopenharmony_ci ret = crypto_sig_set_privkey(sig, key, pkey->keylen); 19462306a36Sopenharmony_ci else 19562306a36Sopenharmony_ci ret = crypto_sig_set_pubkey(sig, key, pkey->keylen); 19662306a36Sopenharmony_ci if (ret < 0) 19762306a36Sopenharmony_ci goto error_free_tfm; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci len = crypto_sig_maxsize(sig); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci info->supported_ops = KEYCTL_SUPPORTS_VERIFY; 20262306a36Sopenharmony_ci if (pkey->key_is_private) 20362306a36Sopenharmony_ci info->supported_ops |= KEYCTL_SUPPORTS_SIGN; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (strcmp(params->encoding, "pkcs1") == 0) { 20662306a36Sopenharmony_ci info->supported_ops |= KEYCTL_SUPPORTS_ENCRYPT; 20762306a36Sopenharmony_ci if (pkey->key_is_private) 20862306a36Sopenharmony_ci info->supported_ops |= KEYCTL_SUPPORTS_DECRYPT; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci } else { 21162306a36Sopenharmony_ci tfm = crypto_alloc_akcipher(alg_name, 0, 0); 21262306a36Sopenharmony_ci if (IS_ERR(tfm)) { 21362306a36Sopenharmony_ci ret = PTR_ERR(tfm); 21462306a36Sopenharmony_ci goto error_free_key; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci if (pkey->key_is_private) 21862306a36Sopenharmony_ci ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); 21962306a36Sopenharmony_ci else 22062306a36Sopenharmony_ci ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); 22162306a36Sopenharmony_ci if (ret < 0) 22262306a36Sopenharmony_ci goto error_free_tfm; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci len = crypto_akcipher_maxsize(tfm); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT; 22762306a36Sopenharmony_ci if (pkey->key_is_private) 22862306a36Sopenharmony_ci info->supported_ops |= KEYCTL_SUPPORTS_DECRYPT; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci info->key_size = len * 8; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (strncmp(pkey->pkey_algo, "ecdsa", 5) == 0) { 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * ECDSA key sizes are much smaller than RSA, and thus could 23662306a36Sopenharmony_ci * operate on (hashed) inputs that are larger than key size. 23762306a36Sopenharmony_ci * For example SHA384-hashed input used with secp256r1 23862306a36Sopenharmony_ci * based keys. Set max_data_size to be at least as large as 23962306a36Sopenharmony_ci * the largest supported hash size (SHA512) 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ci info->max_data_size = 64; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* 24462306a36Sopenharmony_ci * Verify takes ECDSA-Sig (described in RFC 5480) as input, 24562306a36Sopenharmony_ci * which is actually 2 'key_size'-bit integers encoded in 24662306a36Sopenharmony_ci * ASN.1. Account for the ASN.1 encoding overhead here. 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_ci info->max_sig_size = 2 * (len + 3) + 2; 24962306a36Sopenharmony_ci } else { 25062306a36Sopenharmony_ci info->max_data_size = len; 25162306a36Sopenharmony_ci info->max_sig_size = len; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci info->max_enc_size = len; 25562306a36Sopenharmony_ci info->max_dec_size = len; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci ret = 0; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cierror_free_tfm: 26062306a36Sopenharmony_ci if (issig) 26162306a36Sopenharmony_ci crypto_free_sig(sig); 26262306a36Sopenharmony_ci else 26362306a36Sopenharmony_ci crypto_free_akcipher(tfm); 26462306a36Sopenharmony_cierror_free_key: 26562306a36Sopenharmony_ci kfree_sensitive(key); 26662306a36Sopenharmony_ci pr_devel("<==%s() = %d\n", __func__, ret); 26762306a36Sopenharmony_ci return ret; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci/* 27162306a36Sopenharmony_ci * Do encryption, decryption and signing ops. 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_cistatic int software_key_eds_op(struct kernel_pkey_params *params, 27462306a36Sopenharmony_ci const void *in, void *out) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci const struct public_key *pkey = params->key->payload.data[asym_crypto]; 27762306a36Sopenharmony_ci char alg_name[CRYPTO_MAX_ALG_NAME]; 27862306a36Sopenharmony_ci struct crypto_akcipher *tfm; 27962306a36Sopenharmony_ci struct crypto_sig *sig; 28062306a36Sopenharmony_ci char *key, *ptr; 28162306a36Sopenharmony_ci bool issig; 28262306a36Sopenharmony_ci int ksz; 28362306a36Sopenharmony_ci int ret; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci pr_devel("==>%s()\n", __func__); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci ret = software_key_determine_akcipher(pkey, params->encoding, 28862306a36Sopenharmony_ci params->hash_algo, alg_name, 28962306a36Sopenharmony_ci &issig, params->op); 29062306a36Sopenharmony_ci if (ret < 0) 29162306a36Sopenharmony_ci return ret; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, 29462306a36Sopenharmony_ci GFP_KERNEL); 29562306a36Sopenharmony_ci if (!key) 29662306a36Sopenharmony_ci return -ENOMEM; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci memcpy(key, pkey->key, pkey->keylen); 29962306a36Sopenharmony_ci ptr = key + pkey->keylen; 30062306a36Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->algo); 30162306a36Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->paramlen); 30262306a36Sopenharmony_ci memcpy(ptr, pkey->params, pkey->paramlen); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (issig) { 30562306a36Sopenharmony_ci sig = crypto_alloc_sig(alg_name, 0, 0); 30662306a36Sopenharmony_ci if (IS_ERR(sig)) { 30762306a36Sopenharmony_ci ret = PTR_ERR(sig); 30862306a36Sopenharmony_ci goto error_free_key; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (pkey->key_is_private) 31262306a36Sopenharmony_ci ret = crypto_sig_set_privkey(sig, key, pkey->keylen); 31362306a36Sopenharmony_ci else 31462306a36Sopenharmony_ci ret = crypto_sig_set_pubkey(sig, key, pkey->keylen); 31562306a36Sopenharmony_ci if (ret) 31662306a36Sopenharmony_ci goto error_free_tfm; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ksz = crypto_sig_maxsize(sig); 31962306a36Sopenharmony_ci } else { 32062306a36Sopenharmony_ci tfm = crypto_alloc_akcipher(alg_name, 0, 0); 32162306a36Sopenharmony_ci if (IS_ERR(tfm)) { 32262306a36Sopenharmony_ci ret = PTR_ERR(tfm); 32362306a36Sopenharmony_ci goto error_free_key; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (pkey->key_is_private) 32762306a36Sopenharmony_ci ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen); 32862306a36Sopenharmony_ci else 32962306a36Sopenharmony_ci ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen); 33062306a36Sopenharmony_ci if (ret) 33162306a36Sopenharmony_ci goto error_free_tfm; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci ksz = crypto_akcipher_maxsize(tfm); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci ret = -EINVAL; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Perform the encryption calculation. */ 33962306a36Sopenharmony_ci switch (params->op) { 34062306a36Sopenharmony_ci case kernel_pkey_encrypt: 34162306a36Sopenharmony_ci if (issig) 34262306a36Sopenharmony_ci break; 34362306a36Sopenharmony_ci ret = crypto_akcipher_sync_encrypt(tfm, in, params->in_len, 34462306a36Sopenharmony_ci out, params->out_len); 34562306a36Sopenharmony_ci break; 34662306a36Sopenharmony_ci case kernel_pkey_decrypt: 34762306a36Sopenharmony_ci if (issig) 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci ret = crypto_akcipher_sync_decrypt(tfm, in, params->in_len, 35062306a36Sopenharmony_ci out, params->out_len); 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci case kernel_pkey_sign: 35362306a36Sopenharmony_ci if (!issig) 35462306a36Sopenharmony_ci break; 35562306a36Sopenharmony_ci ret = crypto_sig_sign(sig, in, params->in_len, 35662306a36Sopenharmony_ci out, params->out_len); 35762306a36Sopenharmony_ci break; 35862306a36Sopenharmony_ci default: 35962306a36Sopenharmony_ci BUG(); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (ret == 0) 36362306a36Sopenharmony_ci ret = ksz; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cierror_free_tfm: 36662306a36Sopenharmony_ci if (issig) 36762306a36Sopenharmony_ci crypto_free_sig(sig); 36862306a36Sopenharmony_ci else 36962306a36Sopenharmony_ci crypto_free_akcipher(tfm); 37062306a36Sopenharmony_cierror_free_key: 37162306a36Sopenharmony_ci kfree_sensitive(key); 37262306a36Sopenharmony_ci pr_devel("<==%s() = %d\n", __func__, ret); 37362306a36Sopenharmony_ci return ret; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/* 37762306a36Sopenharmony_ci * Verify a signature using a public key. 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ciint public_key_verify_signature(const struct public_key *pkey, 38062306a36Sopenharmony_ci const struct public_key_signature *sig) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci char alg_name[CRYPTO_MAX_ALG_NAME]; 38362306a36Sopenharmony_ci struct crypto_sig *tfm; 38462306a36Sopenharmony_ci char *key, *ptr; 38562306a36Sopenharmony_ci bool issig; 38662306a36Sopenharmony_ci int ret; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci pr_devel("==>%s()\n", __func__); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci BUG_ON(!pkey); 39162306a36Sopenharmony_ci BUG_ON(!sig); 39262306a36Sopenharmony_ci BUG_ON(!sig->s); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* 39562306a36Sopenharmony_ci * If the signature specifies a public key algorithm, it *must* match 39662306a36Sopenharmony_ci * the key's actual public key algorithm. 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * Small exception: ECDSA signatures don't specify the curve, but ECDSA 39962306a36Sopenharmony_ci * keys do. So the strings can mismatch slightly in that case: 40062306a36Sopenharmony_ci * "ecdsa-nist-*" for the key, but "ecdsa" for the signature. 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci if (sig->pkey_algo) { 40362306a36Sopenharmony_ci if (strcmp(pkey->pkey_algo, sig->pkey_algo) != 0 && 40462306a36Sopenharmony_ci (strncmp(pkey->pkey_algo, "ecdsa-", 6) != 0 || 40562306a36Sopenharmony_ci strcmp(sig->pkey_algo, "ecdsa") != 0)) 40662306a36Sopenharmony_ci return -EKEYREJECTED; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ret = software_key_determine_akcipher(pkey, sig->encoding, 41062306a36Sopenharmony_ci sig->hash_algo, alg_name, 41162306a36Sopenharmony_ci &issig, kernel_pkey_verify); 41262306a36Sopenharmony_ci if (ret < 0) 41362306a36Sopenharmony_ci return ret; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci tfm = crypto_alloc_sig(alg_name, 0, 0); 41662306a36Sopenharmony_ci if (IS_ERR(tfm)) 41762306a36Sopenharmony_ci return PTR_ERR(tfm); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen, 42062306a36Sopenharmony_ci GFP_KERNEL); 42162306a36Sopenharmony_ci if (!key) { 42262306a36Sopenharmony_ci ret = -ENOMEM; 42362306a36Sopenharmony_ci goto error_free_tfm; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci memcpy(key, pkey->key, pkey->keylen); 42762306a36Sopenharmony_ci ptr = key + pkey->keylen; 42862306a36Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->algo); 42962306a36Sopenharmony_ci ptr = pkey_pack_u32(ptr, pkey->paramlen); 43062306a36Sopenharmony_ci memcpy(ptr, pkey->params, pkey->paramlen); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (pkey->key_is_private) 43362306a36Sopenharmony_ci ret = crypto_sig_set_privkey(tfm, key, pkey->keylen); 43462306a36Sopenharmony_ci else 43562306a36Sopenharmony_ci ret = crypto_sig_set_pubkey(tfm, key, pkey->keylen); 43662306a36Sopenharmony_ci if (ret) 43762306a36Sopenharmony_ci goto error_free_key; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci ret = crypto_sig_verify(tfm, sig->s, sig->s_size, 44062306a36Sopenharmony_ci sig->digest, sig->digest_size); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cierror_free_key: 44362306a36Sopenharmony_ci kfree_sensitive(key); 44462306a36Sopenharmony_cierror_free_tfm: 44562306a36Sopenharmony_ci crypto_free_sig(tfm); 44662306a36Sopenharmony_ci pr_devel("<==%s() = %d\n", __func__, ret); 44762306a36Sopenharmony_ci if (WARN_ON_ONCE(ret > 0)) 44862306a36Sopenharmony_ci ret = -EINVAL; 44962306a36Sopenharmony_ci return ret; 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(public_key_verify_signature); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int public_key_verify_signature_2(const struct key *key, 45462306a36Sopenharmony_ci const struct public_key_signature *sig) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci const struct public_key *pk = key->payload.data[asym_crypto]; 45762306a36Sopenharmony_ci return public_key_verify_signature(pk, sig); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* 46162306a36Sopenharmony_ci * Public key algorithm asymmetric key subtype 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_cistruct asymmetric_key_subtype public_key_subtype = { 46462306a36Sopenharmony_ci .owner = THIS_MODULE, 46562306a36Sopenharmony_ci .name = "public_key", 46662306a36Sopenharmony_ci .name_len = sizeof("public_key") - 1, 46762306a36Sopenharmony_ci .describe = public_key_describe, 46862306a36Sopenharmony_ci .destroy = public_key_destroy, 46962306a36Sopenharmony_ci .query = software_key_query, 47062306a36Sopenharmony_ci .eds_op = software_key_eds_op, 47162306a36Sopenharmony_ci .verify_signature = public_key_verify_signature_2, 47262306a36Sopenharmony_ci}; 47362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(public_key_subtype); 474