Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *  pkey uv specific code
  4 *
  5 *  Copyright IBM Corp. 2024
  6 */
  7
  8#define KMSG_COMPONENT "pkey"
  9#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
 10
 11#include <linux/cpufeature.h>
 12#include <linux/init.h>
 13#include <linux/module.h>
 14#include <asm/uv.h>
 15
 16#include "zcrypt_ccamisc.h"
 17#include "pkey_base.h"
 18
 19MODULE_LICENSE("GPL");
 20MODULE_AUTHOR("IBM Corporation");
 21MODULE_DESCRIPTION("s390 protected key UV handler");
 22
 23/*
 24 * UV secret token struct and defines.
 25 */
 26
 27#define TOKVER_UV_SECRET 0x09
 28
 29struct uvsecrettoken {
 30	u8  type;		/* 0x00 = TOKTYPE_NON_CCA */
 31	u8  res0[3];
 32	u8  version;		/* 0x09 = TOKVER_UV_SECRET */
 33	u8  res1[3];
 34	u16 secret_type;	/* one of enum uv_secret_types from uv.h */
 35	u16 secret_len;		/* length in bytes of the secret */
 36	u8  secret_id[UV_SECRET_ID_LEN]; /* the secret id for this secret */
 37} __packed;
 38
 39/*
 40 * Check key blob for known and supported UV key.
 41 */
 42static bool is_uv_key(const u8 *key, u32 keylen)
 43{
 44	struct uvsecrettoken *t = (struct uvsecrettoken *)key;
 45
 46	if (keylen < sizeof(*t))
 47		return false;
 48
 49	switch (t->type) {
 50	case TOKTYPE_NON_CCA:
 51		switch (t->version) {
 52		case TOKVER_UV_SECRET:
 53			switch (t->secret_type) {
 54			case UV_SECRET_AES_128:
 55			case UV_SECRET_AES_192:
 56			case UV_SECRET_AES_256:
 57			case UV_SECRET_AES_XTS_128:
 58			case UV_SECRET_AES_XTS_256:
 59			case UV_SECRET_HMAC_SHA_256:
 60			case UV_SECRET_HMAC_SHA_512:
 61			case UV_SECRET_ECDSA_P256:
 62			case UV_SECRET_ECDSA_P384:
 63			case UV_SECRET_ECDSA_P521:
 64			case UV_SECRET_ECDSA_ED25519:
 65			case UV_SECRET_ECDSA_ED448:
 66				return true;
 67			default:
 68				return false;
 69			}
 70		default:
 71			return false;
 72		}
 73	default:
 74		return false;
 75	}
 76}
 77
 78static bool is_uv_keytype(enum pkey_key_type keytype)
 79{
 80	switch (keytype) {
 81	case PKEY_TYPE_UVSECRET:
 82		return true;
 83	default:
 84		return false;
 85	}
 86}
 87
 88static int retrieve_secret(const u8 secret_id[UV_SECRET_ID_LEN],
 89			   u16 *secret_type, u8 *buf, u32 *buflen)
 90{
 91	struct uv_secret_list_item_hdr secret_meta_data;
 92	int rc;
 93
 94	rc = uv_get_secret_metadata(secret_id, &secret_meta_data);
 95	if (rc)
 96		return rc;
 97
 98	if (*buflen < secret_meta_data.length)
 99		return -EINVAL;
100
101	rc = uv_retrieve_secret(secret_meta_data.index,
102				buf, secret_meta_data.length);
103	if (rc)
104		return rc;
105
106	*secret_type = secret_meta_data.type;
107	*buflen = secret_meta_data.length;
108
109	return 0;
110}
111
112static int uv_get_size_and_type(u16 secret_type, u32 *pkeysize, u32 *pkeytype)
113{
114	int rc = 0;
115
116	switch (secret_type) {
117	case UV_SECRET_AES_128:
118		*pkeysize = 16 + AES_WK_VP_SIZE;
119		*pkeytype = PKEY_KEYTYPE_AES_128;
120		break;
121	case UV_SECRET_AES_192:
122		*pkeysize = 24 + AES_WK_VP_SIZE;
123		*pkeytype = PKEY_KEYTYPE_AES_192;
124		break;
125	case UV_SECRET_AES_256:
126		*pkeysize = 32 + AES_WK_VP_SIZE;
127		*pkeytype = PKEY_KEYTYPE_AES_256;
128		break;
129	case UV_SECRET_AES_XTS_128:
130		*pkeysize = 16 + 16 + AES_WK_VP_SIZE;
131		*pkeytype = PKEY_KEYTYPE_AES_XTS_128;
132		break;
133	case UV_SECRET_AES_XTS_256:
134		*pkeysize = 32 + 32 + AES_WK_VP_SIZE;
135		*pkeytype = PKEY_KEYTYPE_AES_XTS_256;
136		break;
137	case UV_SECRET_HMAC_SHA_256:
138		*pkeysize = 64 + AES_WK_VP_SIZE;
139		*pkeytype = PKEY_KEYTYPE_HMAC_512;
140		break;
141	case UV_SECRET_HMAC_SHA_512:
142		*pkeysize = 128 + AES_WK_VP_SIZE;
143		*pkeytype = PKEY_KEYTYPE_HMAC_1024;
144		break;
145	case UV_SECRET_ECDSA_P256:
146		*pkeysize = 32 + AES_WK_VP_SIZE;
147		*pkeytype = PKEY_KEYTYPE_ECC_P256;
148		break;
149	case UV_SECRET_ECDSA_P384:
150		*pkeysize = 48 + AES_WK_VP_SIZE;
151		*pkeytype = PKEY_KEYTYPE_ECC_P384;
152		break;
153	case UV_SECRET_ECDSA_P521:
154		*pkeysize = 80 + AES_WK_VP_SIZE;
155		*pkeytype = PKEY_KEYTYPE_ECC_P521;
156		break;
157	case UV_SECRET_ECDSA_ED25519:
158		*pkeysize = 32 + AES_WK_VP_SIZE;
159		*pkeytype = PKEY_KEYTYPE_ECC_ED25519;
160		break;
161	case UV_SECRET_ECDSA_ED448:
162		*pkeysize = 64 + AES_WK_VP_SIZE;
163		*pkeytype = PKEY_KEYTYPE_ECC_ED448;
164		break;
165	default:
166		rc = -EINVAL;
167	}
168
169	return rc;
170}
171
172static int uv_key2protkey(const struct pkey_apqn *_apqns __always_unused,
173			  size_t _nr_apqns __always_unused,
174			  const u8 *key, u32 keylen,
175			  u8 *protkey, u32 *protkeylen, u32 *keyinfo)
176{
177	struct uvsecrettoken *t = (struct uvsecrettoken *)key;
178	u32 pkeysize, pkeytype;
179	u16 secret_type;
180	int rc;
181
182	rc = uv_get_size_and_type(t->secret_type, &pkeysize, &pkeytype);
183	if (rc)
184		goto out;
185
186	if (*protkeylen < pkeysize) {
187		PKEY_DBF_ERR("%s prot key buffer size too small: %u < %u\n",
188			     __func__, *protkeylen, pkeysize);
189		rc = -EINVAL;
190		goto out;
191	}
192
193	rc = retrieve_secret(t->secret_id, &secret_type, protkey, protkeylen);
194	if (rc) {
195		PKEY_DBF_ERR("%s retrieve_secret() failed with %d\n",
196			     __func__, rc);
197		goto out;
198	}
199	if (secret_type != t->secret_type) {
200		PKEY_DBF_ERR("%s retrieved secret type %u != expected type %u\n",
201			     __func__, secret_type, t->secret_type);
202		rc = -EINVAL;
203		goto out;
204	}
205
206	if (keyinfo)
207		*keyinfo = pkeytype;
208
209out:
210	pr_debug("rc=%d\n", rc);
211	return rc;
212}
213
214static int uv_verifykey(const u8 *key, u32 keylen,
215			u16 *_card __always_unused,
216			u16 *_dom __always_unused,
217			u32 *keytype, u32 *keybitsize, u32 *flags)
218{
219	struct uvsecrettoken *t = (struct uvsecrettoken *)key;
220	struct uv_secret_list_item_hdr secret_meta_data;
221	u32 pkeysize, pkeytype, bitsize;
222	int rc;
223
224	rc = uv_get_size_and_type(t->secret_type, &pkeysize, &pkeytype);
225	if (rc)
226		goto out;
227
228	rc = uv_get_secret_metadata(t->secret_id, &secret_meta_data);
229	if (rc)
230		goto out;
231
232	if (secret_meta_data.type != t->secret_type) {
233		rc = -EINVAL;
234		goto out;
235	}
236
237	/* set keytype; keybitsize and flags are not supported */
238	if (keytype)
239		*keytype = PKEY_TYPE_UVSECRET;
240	if (keybitsize) {
241		bitsize = 8 * pkey_keytype_to_size(pkeytype);
242		*keybitsize = bitsize ?: PKEY_SIZE_UNKNOWN;
243	}
244	if (flags)
245		*flags = pkeytype;
246
247out:
248	pr_debug("rc=%d\n", rc);
249	return rc;
250}
251
252static struct pkey_handler uv_handler = {
253	.module			 = THIS_MODULE,
254	.name			 = "PKEY UV handler",
255	.is_supported_key	 = is_uv_key,
256	.is_supported_keytype	 = is_uv_keytype,
257	.key_to_protkey		 = uv_key2protkey,
258	.verify_key		 = uv_verifykey,
259};
260
261/*
262 * Module init
263 */
264static int __init pkey_uv_init(void)
265{
266	if (!is_prot_virt_guest())
267		return -ENODEV;
268
269	if (!test_bit_inv(BIT_UVC_CMD_RETR_SECRET, uv_info.inst_calls_list))
270		return -ENODEV;
271
272	return pkey_handler_register(&uv_handler);
273}
274
275/*
276 * Module exit
277 */
278static void __exit pkey_uv_exit(void)
279{
280	pkey_handler_unregister(&uv_handler);
281}
282
283module_cpu_feature_match(S390_CPU_FEATURE_UV, pkey_uv_init);
284module_exit(pkey_uv_exit);