xref: /kvm-unit-tests/s390x/pv-attest.c (revision c315f52b88b967cfb4cd58f3b4e1987378c47f3b)
1*8348b72dSSteffen Eiden /* SPDX-License-Identifier: GPL-2.0-only */
2*8348b72dSSteffen Eiden /*
3*8348b72dSSteffen Eiden  * Retrieve Attestation Measurement Utravisor Call tests
4*8348b72dSSteffen Eiden  *
5*8348b72dSSteffen Eiden  * Copyright IBM Corp. 2022
6*8348b72dSSteffen Eiden  *
7*8348b72dSSteffen Eiden  * Authors:
8*8348b72dSSteffen Eiden  *  Steffen Eiden <seiden@linux.ibm.com>
9*8348b72dSSteffen Eiden  */
10*8348b72dSSteffen Eiden 
11*8348b72dSSteffen Eiden #include <libcflat.h>
12*8348b72dSSteffen Eiden #include <alloc_page.h>
13*8348b72dSSteffen Eiden #include <asm/page.h>
14*8348b72dSSteffen Eiden #include <asm/facility.h>
15*8348b72dSSteffen Eiden #include <asm/uv.h>
16*8348b72dSSteffen Eiden #include <sclp.h>
17*8348b72dSSteffen Eiden #include <uv.h>
18*8348b72dSSteffen Eiden 
19*8348b72dSSteffen Eiden #define ARCB_VERSION_NONE 0
20*8348b72dSSteffen Eiden #define ARCB_VERSION_1 0x100
21*8348b72dSSteffen Eiden #define ARCB_MEAS_NONE 0
22*8348b72dSSteffen Eiden #define ARCB_MEAS_HMAC_SHA512 1
23*8348b72dSSteffen Eiden #define MEASUREMENT_SIZE_HMAC_SHA512 64
24*8348b72dSSteffen Eiden #define PAF_PHKH_ATT (1ULL << 61)
25*8348b72dSSteffen Eiden #define ADDITIONAL_SIZE_PAF_PHKH_ATT 32
26*8348b72dSSteffen Eiden /* arcb with one key slot and no nonce */
27*8348b72dSSteffen Eiden struct uv_arcb_v1 {
28*8348b72dSSteffen Eiden 	uint64_t reserved0;		/* 0x0000 */
29*8348b72dSSteffen Eiden 	uint32_t req_ver;		/* 0x0008 */
30*8348b72dSSteffen Eiden 	uint32_t req_len;		/* 0x000c */
31*8348b72dSSteffen Eiden 	uint8_t  iv[12];		/* 0x0010 */
32*8348b72dSSteffen Eiden 	uint32_t reserved1c;		/* 0x001c */
33*8348b72dSSteffen Eiden 	uint8_t  reserved20[7];		/* 0x0020 */
34*8348b72dSSteffen Eiden 	uint8_t  nks;			/* 0x0027 */
35*8348b72dSSteffen Eiden 	int32_t reserved28;		/* 0x0028 */
36*8348b72dSSteffen Eiden 	uint32_t sea;			/* 0x002c */
37*8348b72dSSteffen Eiden 	uint64_t plaint_att_flags;	/* 0x0030 */
38*8348b72dSSteffen Eiden 	uint32_t meas_alg_id;		/* 0x0038 */
39*8348b72dSSteffen Eiden 	uint32_t reserved3c;		/* 0x003c */
40*8348b72dSSteffen Eiden 	uint8_t  cpk[160];		/* 0x0040 */
41*8348b72dSSteffen Eiden 	uint8_t  key_slot[80];		/* 0x00e0 */
42*8348b72dSSteffen Eiden 	uint8_t  meas_key[64];		/* 0x0130 */
43*8348b72dSSteffen Eiden 	uint8_t  tag[16];		/* 0x0170 */
44*8348b72dSSteffen Eiden } __attribute__((packed));
45*8348b72dSSteffen Eiden 
46*8348b72dSSteffen Eiden struct attest_request_v1 {
47*8348b72dSSteffen Eiden 	struct uv_arcb_v1 arcb;
48*8348b72dSSteffen Eiden 	uint8_t measurement[MEASUREMENT_SIZE_HMAC_SHA512];
49*8348b72dSSteffen Eiden 	uint8_t additional[ADDITIONAL_SIZE_PAF_PHKH_ATT];
50*8348b72dSSteffen Eiden };
51*8348b72dSSteffen Eiden 
test_attest_v1(uint64_t page)52*8348b72dSSteffen Eiden static void test_attest_v1(uint64_t page)
53*8348b72dSSteffen Eiden {
54*8348b72dSSteffen Eiden 	struct uv_cb_attest uvcb = {
55*8348b72dSSteffen Eiden 		.header.cmd = UVC_CMD_ATTESTATION,
56*8348b72dSSteffen Eiden 		.header.len = sizeof(uvcb),
57*8348b72dSSteffen Eiden 	};
58*8348b72dSSteffen Eiden 	const struct uv_cb_qui *uvcb_qui = uv_get_query_data();
59*8348b72dSSteffen Eiden 	struct attest_request_v1 *attest_req = (void *)page;
60*8348b72dSSteffen Eiden 	struct uv_arcb_v1 *arcb = &attest_req->arcb;
61*8348b72dSSteffen Eiden 	int cc;
62*8348b72dSSteffen Eiden 
63*8348b72dSSteffen Eiden 	report_prefix_push("v1");
64*8348b72dSSteffen Eiden 	if (!test_bit_inv(0, &uvcb_qui->supp_att_hdr_ver)) {
65*8348b72dSSteffen Eiden 		report_skip("Attestation version 1 not supported");
66*8348b72dSSteffen Eiden 		goto done;
67*8348b72dSSteffen Eiden 	}
68*8348b72dSSteffen Eiden 
69*8348b72dSSteffen Eiden 	memset((void *)page, 0, PAGE_SIZE);
70*8348b72dSSteffen Eiden 
71*8348b72dSSteffen Eiden 	/*
72*8348b72dSSteffen Eiden 	 * Create a minimal arcb/uvcb such that FW has everything to start
73*8348b72dSSteffen Eiden 	 * unsealing the request. However, this unsealing will fail as the
74*8348b72dSSteffen Eiden 	 * kvm-unit-test framework provides no cryptography functions that
75*8348b72dSSteffen Eiden 	 * would be needed to seal such requests.
76*8348b72dSSteffen Eiden 	 */
77*8348b72dSSteffen Eiden 	arcb->req_ver = ARCB_VERSION_1;
78*8348b72dSSteffen Eiden 	arcb->req_len = sizeof(*arcb);
79*8348b72dSSteffen Eiden 	arcb->nks = 1;
80*8348b72dSSteffen Eiden 	arcb->sea = sizeof(arcb->meas_key);
81*8348b72dSSteffen Eiden 	arcb->plaint_att_flags = PAF_PHKH_ATT;
82*8348b72dSSteffen Eiden 	arcb->meas_alg_id = ARCB_MEAS_HMAC_SHA512;
83*8348b72dSSteffen Eiden 	uvcb.arcb_addr = (uint64_t)&attest_req->arcb;
84*8348b72dSSteffen Eiden 	uvcb.measurement_address = (uint64_t)attest_req->measurement;
85*8348b72dSSteffen Eiden 	uvcb.measurement_length = sizeof(attest_req->measurement);
86*8348b72dSSteffen Eiden 	uvcb.add_data_address = (uint64_t)attest_req->additional;
87*8348b72dSSteffen Eiden 	uvcb.add_data_length = sizeof(attest_req->additional);
88*8348b72dSSteffen Eiden 
89*8348b72dSSteffen Eiden 	uvcb.continuation_token = 0xff;
90*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
91*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x101, "invalid continuation token");
92*8348b72dSSteffen Eiden 	uvcb.continuation_token = 0;
93*8348b72dSSteffen Eiden 
94*8348b72dSSteffen Eiden 	uvcb.user_data_length = sizeof(uvcb.user_data) + 1;
95*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
96*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x102, "invalid user data size");
97*8348b72dSSteffen Eiden 	uvcb.user_data_length = 0;
98*8348b72dSSteffen Eiden 
99*8348b72dSSteffen Eiden 	uvcb.arcb_addr = get_ram_size() + PAGE_SIZE;
100*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
101*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x103, "invalid address arcb");
102*8348b72dSSteffen Eiden 	uvcb.arcb_addr = page;
103*8348b72dSSteffen Eiden 
104*8348b72dSSteffen Eiden 	/* 0x104 - 0x105 need an unseal-able request */
105*8348b72dSSteffen Eiden 
106*8348b72dSSteffen Eiden 	arcb->req_ver = ARCB_VERSION_NONE;
107*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
108*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x106, "unsupported version");
109*8348b72dSSteffen Eiden 	arcb->req_ver = ARCB_VERSION_1;
110*8348b72dSSteffen Eiden 
111*8348b72dSSteffen Eiden 	arcb->req_len += 1;
112*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
113*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x107, "arcb too big");
114*8348b72dSSteffen Eiden 	arcb->req_len -= 1;
115*8348b72dSSteffen Eiden 
116*8348b72dSSteffen Eiden 	/*
117*8348b72dSSteffen Eiden 	 * The arcb needs to grow as well if number of key slots (nks)
118*8348b72dSSteffen Eiden 	 * is increased. However, this is not the case and there is no explicit
119*8348b72dSSteffen Eiden 	 * 'too many/less nks for that arcb size' error code -> expect 0x107
120*8348b72dSSteffen Eiden 	 */
121*8348b72dSSteffen Eiden 	arcb->nks = 2;
122*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
123*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x107, "too many nks for arcb");
124*8348b72dSSteffen Eiden 	arcb->nks = 1;
125*8348b72dSSteffen Eiden 
126*8348b72dSSteffen Eiden 	arcb->nks = 0;
127*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
128*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x108, "invalid num key slots");
129*8348b72dSSteffen Eiden 	arcb->nks = 1;
130*8348b72dSSteffen Eiden 
131*8348b72dSSteffen Eiden 	/*
132*8348b72dSSteffen Eiden 	 * Possible valid size (when using nonce).
133*8348b72dSSteffen Eiden 	 * However, req_len too small to host a nonce
134*8348b72dSSteffen Eiden 	 */
135*8348b72dSSteffen Eiden 	arcb->sea = 80;
136*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
137*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x109, "encrypted size too big");
138*8348b72dSSteffen Eiden 	arcb->sea = 17;
139*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
140*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x109, "encrypted size too small");
141*8348b72dSSteffen Eiden 	arcb->sea = 64;
142*8348b72dSSteffen Eiden 
143*8348b72dSSteffen Eiden 	arcb->plaint_att_flags = uvcb_qui->supp_paf ^ GENMASK_ULL(63, 0);
144*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
145*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x10a, "invalid flag");
146*8348b72dSSteffen Eiden 	arcb->plaint_att_flags = PAF_PHKH_ATT;
147*8348b72dSSteffen Eiden 
148*8348b72dSSteffen Eiden 	arcb->meas_alg_id = ARCB_MEAS_NONE;
149*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
150*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x10b, "invalid measurement algorithm");
151*8348b72dSSteffen Eiden 	arcb->meas_alg_id = ARCB_MEAS_HMAC_SHA512;
152*8348b72dSSteffen Eiden 
153*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
154*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x10c, "unable unseal");
155*8348b72dSSteffen Eiden 
156*8348b72dSSteffen Eiden 	uvcb.measurement_length = 0;
157*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
158*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x10d, "invalid measurement size");
159*8348b72dSSteffen Eiden 	uvcb.measurement_length = sizeof(attest_req->measurement);
160*8348b72dSSteffen Eiden 
161*8348b72dSSteffen Eiden 	uvcb.add_data_length = 0;
162*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
163*8348b72dSSteffen Eiden 	report(cc == 1 && uvcb.header.rc == 0x10e, "invalid additional size");
164*8348b72dSSteffen Eiden 	uvcb.add_data_length = sizeof(attest_req->additional);
165*8348b72dSSteffen Eiden 
166*8348b72dSSteffen Eiden done:
167*8348b72dSSteffen Eiden 	report_prefix_pop();
168*8348b72dSSteffen Eiden }
169*8348b72dSSteffen Eiden 
test_attest(uint64_t page)170*8348b72dSSteffen Eiden static void test_attest(uint64_t page)
171*8348b72dSSteffen Eiden {
172*8348b72dSSteffen Eiden 	struct uv_cb_attest uvcb = {
173*8348b72dSSteffen Eiden 		.header.cmd = UVC_CMD_ATTESTATION,
174*8348b72dSSteffen Eiden 		.header.len = sizeof(uvcb),
175*8348b72dSSteffen Eiden 	};
176*8348b72dSSteffen Eiden 	const struct uv_cb_qui *uvcb_qui = uv_get_query_data();
177*8348b72dSSteffen Eiden 	int cc;
178*8348b72dSSteffen Eiden 
179*8348b72dSSteffen Eiden 	/* Verify that the UV supports at least one header version */
180*8348b72dSSteffen Eiden 	report(uvcb_qui->supp_att_hdr_ver, "has hdr support");
181*8348b72dSSteffen Eiden 
182*8348b72dSSteffen Eiden 	memset((void *)page, 0, PAGE_SIZE);
183*8348b72dSSteffen Eiden 
184*8348b72dSSteffen Eiden 	uvcb.header.len -= 1;
185*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
186*8348b72dSSteffen Eiden 	report(cc && uvcb.header.rc == UVC_RC_INV_LEN, "uvcb too small");
187*8348b72dSSteffen Eiden 	uvcb.header.len += 1;
188*8348b72dSSteffen Eiden 
189*8348b72dSSteffen Eiden 	uvcb.header.len += 1;
190*8348b72dSSteffen Eiden 	cc = uv_call(0, (uint64_t)&uvcb);
191*8348b72dSSteffen Eiden 	report(cc && uvcb.header.rc == UVC_RC_INV_LEN, "uvcb too large");
192*8348b72dSSteffen Eiden 	uvcb.header.len -= 1;
193*8348b72dSSteffen Eiden }
194*8348b72dSSteffen Eiden 
main(void)195*8348b72dSSteffen Eiden int main(void)
196*8348b72dSSteffen Eiden {
197*8348b72dSSteffen Eiden 	bool has_uvc = test_facility(158);
198*8348b72dSSteffen Eiden 	uint64_t page;
199*8348b72dSSteffen Eiden 
200*8348b72dSSteffen Eiden 
201*8348b72dSSteffen Eiden 	report_prefix_push("attestation");
202*8348b72dSSteffen Eiden 	if (!has_uvc) {
203*8348b72dSSteffen Eiden 		report_skip("Ultravisor call facility is not available");
204*8348b72dSSteffen Eiden 		goto done;
205*8348b72dSSteffen Eiden 	}
206*8348b72dSSteffen Eiden 
207*8348b72dSSteffen Eiden 	if (!uv_os_is_guest()) {
208*8348b72dSSteffen Eiden 		report_skip("Not a protected guest");
209*8348b72dSSteffen Eiden 		goto done;
210*8348b72dSSteffen Eiden 	}
211*8348b72dSSteffen Eiden 
212*8348b72dSSteffen Eiden 	if (!uv_query_test_call(BIT_UVC_CMD_ATTESTATION)) {
213*8348b72dSSteffen Eiden 		report_skip("Attestation not supported.");
214*8348b72dSSteffen Eiden 		goto done;
215*8348b72dSSteffen Eiden 	}
216*8348b72dSSteffen Eiden 
217*8348b72dSSteffen Eiden 	page = (uint64_t)alloc_page();
218*8348b72dSSteffen Eiden 	/* The privilege check is done in uv-guest.c */
219*8348b72dSSteffen Eiden 	test_attest(page);
220*8348b72dSSteffen Eiden 	test_attest_v1(page);
221*8348b72dSSteffen Eiden 	free_page((void *)page);
222*8348b72dSSteffen Eiden done:
223*8348b72dSSteffen Eiden 	report_prefix_pop();
224*8348b72dSSteffen Eiden 	return report_summary();
225*8348b72dSSteffen Eiden }
226