| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * pkey uv specific code
- *
- * Copyright IBM Corp. 2024
- */
- #define pr_fmt(fmt) "pkey: " fmt
- #include <linux/cpufeature.h>
- #include <linux/init.h>
- #include <linux/module.h>
- #include <asm/uv.h>
- #include "zcrypt_ccamisc.h"
- #include "pkey_base.h"
- MODULE_LICENSE("GPL");
- MODULE_AUTHOR("IBM Corporation");
- MODULE_DESCRIPTION("s390 protected key UV handler");
- /*
- * One pre-allocated uv_secret_list for use with uv_find_secret()
- */
- static struct uv_secret_list *uv_list;
- static DEFINE_MUTEX(uv_list_mutex);
- /*
- * UV secret token struct and defines.
- */
- #define TOKVER_UV_SECRET 0x09
- struct uvsecrettoken {
- u8 type; /* 0x00 = TOKTYPE_NON_CCA */
- u8 res0[3];
- u8 version; /* 0x09 = TOKVER_UV_SECRET */
- u8 res1[3];
- u16 secret_type; /* one of enum uv_secret_types from uv.h */
- u16 secret_len; /* length in bytes of the secret */
- u8 secret_id[UV_SECRET_ID_LEN]; /* the secret id for this secret */
- } __packed;
- /*
- * Check key blob for known and supported UV key.
- */
- static bool is_uv_key(const u8 *key, u32 keylen)
- {
- struct uvsecrettoken *t = (struct uvsecrettoken *)key;
- if (keylen < sizeof(*t))
- return false;
- switch (t->type) {
- case TOKTYPE_NON_CCA:
- switch (t->version) {
- case TOKVER_UV_SECRET:
- switch (t->secret_type) {
- case UV_SECRET_AES_128:
- case UV_SECRET_AES_192:
- case UV_SECRET_AES_256:
- case UV_SECRET_AES_XTS_128:
- case UV_SECRET_AES_XTS_256:
- case UV_SECRET_HMAC_SHA_256:
- case UV_SECRET_HMAC_SHA_512:
- case UV_SECRET_ECDSA_P256:
- case UV_SECRET_ECDSA_P384:
- case UV_SECRET_ECDSA_P521:
- case UV_SECRET_ECDSA_ED25519:
- case UV_SECRET_ECDSA_ED448:
- return true;
- default:
- return false;
- }
- default:
- return false;
- }
- default:
- return false;
- }
- }
- static bool is_uv_keytype(enum pkey_key_type keytype)
- {
- switch (keytype) {
- case PKEY_TYPE_UVSECRET:
- return true;
- default:
- return false;
- }
- }
- static int get_secret_metadata(const u8 secret_id[UV_SECRET_ID_LEN],
- struct uv_secret_list_item_hdr *secret)
- {
- int rc;
- mutex_lock(&uv_list_mutex);
- memset(uv_list, 0, sizeof(*uv_list));
- rc = uv_find_secret(secret_id, uv_list, secret);
- mutex_unlock(&uv_list_mutex);
- return rc;
- }
- static int retrieve_secret(const u8 secret_id[UV_SECRET_ID_LEN],
- u16 *secret_type, u8 *buf, u32 *buflen)
- {
- struct uv_secret_list_item_hdr secret_meta_data;
- int rc;
- rc = get_secret_metadata(secret_id, &secret_meta_data);
- if (rc)
- return rc;
- if (*buflen < secret_meta_data.length)
- return -EINVAL;
- rc = uv_retrieve_secret(secret_meta_data.index,
- buf, secret_meta_data.length);
- if (rc)
- return rc;
- *secret_type = secret_meta_data.type;
- *buflen = secret_meta_data.length;
- return 0;
- }
- static int uv_get_size_and_type(u16 secret_type, u32 *pkeysize, u32 *pkeytype)
- {
- int rc = 0;
- switch (secret_type) {
- case UV_SECRET_AES_128:
- *pkeysize = 16 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_AES_128;
- break;
- case UV_SECRET_AES_192:
- *pkeysize = 24 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_AES_192;
- break;
- case UV_SECRET_AES_256:
- *pkeysize = 32 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_AES_256;
- break;
- case UV_SECRET_AES_XTS_128:
- *pkeysize = 16 + 16 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_AES_XTS_128;
- break;
- case UV_SECRET_AES_XTS_256:
- *pkeysize = 32 + 32 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_AES_XTS_256;
- break;
- case UV_SECRET_HMAC_SHA_256:
- *pkeysize = 64 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_HMAC_512;
- break;
- case UV_SECRET_HMAC_SHA_512:
- *pkeysize = 128 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_HMAC_1024;
- break;
- case UV_SECRET_ECDSA_P256:
- *pkeysize = 32 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_ECC_P256;
- break;
- case UV_SECRET_ECDSA_P384:
- *pkeysize = 48 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_ECC_P384;
- break;
- case UV_SECRET_ECDSA_P521:
- *pkeysize = 80 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_ECC_P521;
- break;
- case UV_SECRET_ECDSA_ED25519:
- *pkeysize = 32 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_ECC_ED25519;
- break;
- case UV_SECRET_ECDSA_ED448:
- *pkeysize = 64 + AES_WK_VP_SIZE;
- *pkeytype = PKEY_KEYTYPE_ECC_ED448;
- break;
- default:
- rc = -EINVAL;
- }
- return rc;
- }
- static int uv_key2protkey(const struct pkey_apqn *_apqns __always_unused,
- size_t _nr_apqns __always_unused,
- const u8 *key, u32 keylen,
- u8 *protkey, u32 *protkeylen, u32 *keyinfo,
- u32 _xflags __always_unused)
- {
- struct uvsecrettoken *t = (struct uvsecrettoken *)key;
- u32 pkeysize, pkeytype;
- u16 secret_type;
- int rc;
- rc = uv_get_size_and_type(t->secret_type, &pkeysize, &pkeytype);
- if (rc)
- goto out;
- if (*protkeylen < pkeysize) {
- PKEY_DBF_ERR("%s prot key buffer size too small: %u < %u\n",
- __func__, *protkeylen, pkeysize);
- rc = -EINVAL;
- goto out;
- }
- rc = retrieve_secret(t->secret_id, &secret_type, protkey, protkeylen);
- if (rc) {
- PKEY_DBF_ERR("%s retrieve_secret() failed with %d\n",
- __func__, rc);
- goto out;
- }
- if (secret_type != t->secret_type) {
- PKEY_DBF_ERR("%s retrieved secret type %u != expected type %u\n",
- __func__, secret_type, t->secret_type);
- rc = -EINVAL;
- goto out;
- }
- if (keyinfo)
- *keyinfo = pkeytype;
- out:
- pr_debug("rc=%d\n", rc);
- return rc;
- }
- static int uv_verifykey(const u8 *key, u32 keylen,
- u16 *_card __always_unused,
- u16 *_dom __always_unused,
- u32 *keytype, u32 *keybitsize, u32 *flags,
- u32 xflags __always_unused)
- {
- struct uvsecrettoken *t = (struct uvsecrettoken *)key;
- struct uv_secret_list_item_hdr secret_meta_data;
- u32 pkeysize, pkeytype, bitsize;
- int rc;
- rc = uv_get_size_and_type(t->secret_type, &pkeysize, &pkeytype);
- if (rc)
- goto out;
- rc = get_secret_metadata(t->secret_id, &secret_meta_data);
- if (rc)
- goto out;
- if (secret_meta_data.type != t->secret_type) {
- rc = -EINVAL;
- goto out;
- }
- /* set keytype; keybitsize and flags are not supported */
- if (keytype)
- *keytype = PKEY_TYPE_UVSECRET;
- if (keybitsize) {
- bitsize = 8 * pkey_keytype_to_size(pkeytype);
- *keybitsize = bitsize ?: PKEY_SIZE_UNKNOWN;
- }
- if (flags)
- *flags = pkeytype;
- out:
- pr_debug("rc=%d\n", rc);
- return rc;
- }
- static struct pkey_handler uv_handler = {
- .module = THIS_MODULE,
- .name = "PKEY UV handler",
- .is_supported_key = is_uv_key,
- .is_supported_keytype = is_uv_keytype,
- .key_to_protkey = uv_key2protkey,
- .verify_key = uv_verifykey,
- };
- /*
- * Module init
- */
- static int __init pkey_uv_init(void)
- {
- int rc;
- if (!is_prot_virt_guest())
- return -ENODEV;
- if (!test_bit_inv(BIT_UVC_CMD_RETR_SECRET, uv_info.inst_calls_list))
- return -ENODEV;
- uv_list = kmalloc_obj(*uv_list);
- if (!uv_list)
- return -ENOMEM;
- rc = pkey_handler_register(&uv_handler);
- if (rc)
- kfree(uv_list);
- return rc;
- }
- /*
- * Module exit
- */
- static void __exit pkey_uv_exit(void)
- {
- pkey_handler_unregister(&uv_handler);
- mutex_lock(&uv_list_mutex);
- kvfree(uv_list);
- mutex_unlock(&uv_list_mutex);
- }
- module_cpu_feature_match(S390_CPU_FEATURE_UV, pkey_uv_init);
- module_exit(pkey_uv_exit);
|