1 /*
2  * Copyright (C) 2019-2022 Intel Corporation.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer in
9  *    this position and unchanged.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stdint.h>
35 #include <errno.h>
36 #include <linux/mei.h>
37 #include "att_keybox.h"
38 #include "log.h"
39 
40 static const uuid_le HECI_CLIENT_GUID =
41 	UUID_LE(0x8e6a6715, 0x9abc, 0x4043,
42 			0x88, 0xef, 0x9e, 0x39, 0xc6, 0xf6, 0x3e, 0x0f);
43 
44 #define MEI_DEV                     "/dev/mei0"
45 #define HECI_READ_ATTKB_GRP_ID      0x0a
46 #define HECI_READ_ATTKB_EX_CMD_REQ  0x1a
47 #define HECI_MTU 2048
48 
get_attkb_size(void)49 uint16_t get_attkb_size(void)
50 {
51 	struct mei_connect_client_data mdcd;
52 	int fd = -1, ret = 0;
53 	HECI_READ_ATTKB_EX_Request req;
54 	HECI_READ_ATTKB_EX_Response resp;
55 
56 	fd = open(MEI_DEV, O_RDWR);
57 	if (fd == -1) {
58 		pr_err("Failed to open %s, %s\n",
59 				MEI_DEV, strerror(errno));
60 		return 0;
61 	}
62 
63 	memset(&mdcd, 0, sizeof(mdcd));
64 	memcpy(&mdcd.in_client_uuid, &HECI_CLIENT_GUID, sizeof(HECI_CLIENT_GUID));
65 
66 	ret = ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &mdcd);
67 	if (ret) {
68 		pr_err("HECI connection failed, %s\n",
69 				strerror(errno));
70 		goto err;
71 	}
72 
73 	/* Get the size of encrypted attestation keybox */
74 	memset(&req, 0, sizeof(req));
75 	req.header.groupid = HECI_READ_ATTKB_GRP_ID;
76 	req.header.command = HECI_READ_ATTKB_EX_CMD_REQ;
77 	req.size = 0;
78 	req.offset = 0;
79 	req.flags.encryption = 1;
80 
81 	ret = write(fd, &req, sizeof(req));
82 	if (ret != sizeof(req)) {
83 		pr_err("Failed to send HECI command, %s\n",
84 				strerror(errno));
85 		goto err;
86 	}
87 
88 	ret = read(fd, &resp, sizeof(resp));
89 	if (ret != sizeof(resp)) {
90 		pr_err("ret = %d,Failed to read HECI command result, %d:%s\n",
91 				ret, errno, strerror(errno));
92 		goto err;
93 	}
94 
95 	if ((resp.header.is_response != 1) || (resp.header.result != 0)) {
96 		pr_err("Failed to check resp header = 0x%x\n",
97 				resp.header.result);
98 		goto err;
99 	}
100 
101 	if (resp.total_file_size == 0) {
102 		pr_err("ret = %d, Unexpected filesize 0!\n", ret);
103 	}
104 
105 	close(fd);
106 
107 	return resp.total_file_size;
108 
109 err:
110 	close(fd);
111 	return 0;
112 }
113 
read_attkb(void * data,uint16_t size)114 uint16_t read_attkb(void *data, uint16_t size)
115 {
116 	struct mei_connect_client_data mdcd;
117 	HECI_READ_ATTKB_EX_Request req;
118 	HECI_READ_ATTKB_EX_Response resp;
119 	int fd = -1, ret = 0;
120 	uint16_t left_size = 0;
121 	uint16_t bytes_read = 0;
122 	void *ptr = data;
123 
124 	if ((ptr == NULL) || (size == 0)) {
125 		return 0;
126 	}
127 
128 	fd = open(MEI_DEV, O_RDWR);
129 	if (fd == -1) {
130 		pr_err("Failed to open %s, %s\n",
131 				MEI_DEV, strerror(errno));
132 		return 0;
133 	}
134 
135 	memset(&mdcd, 0, sizeof(mdcd));
136 	memcpy(&mdcd.in_client_uuid, &HECI_CLIENT_GUID, sizeof(HECI_CLIENT_GUID));
137 
138 	ret = ioctl(fd, IOCTL_MEI_CONNECT_CLIENT, &mdcd);
139 	if (ret) {
140 		pr_err("HECI connection failed, %s\n",
141 				strerror(errno));
142 		goto err;
143 	}
144 
145 	left_size = size;
146 
147 	memset(&req, 0, sizeof(req));
148 	req.header.groupid = HECI_READ_ATTKB_GRP_ID;
149 	req.header.command = HECI_READ_ATTKB_EX_CMD_REQ;
150 	req.offset = 0;
151 	req.size = HECI_MTU > left_size ? left_size : HECI_MTU;
152 	req.flags.encryption = 1;
153 
154 	while (left_size) {
155 		req.offset = bytes_read;
156 		req.size = HECI_MTU > left_size ? left_size : HECI_MTU;
157 
158 		ret = write(fd, &req, sizeof(req));
159 		if (ret != sizeof(req)) {
160 			pr_err("Failed to send HECI command, %s\n",
161 					strerror(errno));
162 			goto err;
163 		}
164 
165 		ret = read(fd, &resp, sizeof(resp));
166 		if (ret != sizeof(resp)) {
167 			pr_err("Failed to read HECI command result, %s\n",
168 					strerror(errno));
169 			goto err;
170 		}
171 
172 		if ((resp.header.is_response != 1) || (resp.header.result != 0)) {
173 			pr_err("Failed to check resp header = 0x%x\n",
174 					resp.header.result);
175 			goto err;
176 		}
177 
178 		ret = read(fd, (uint8_t *)data + bytes_read, req.size);
179 		if (ret != req.size) {
180 			pr_err("Failed to read attkb, %s\n",
181 					strerror(errno));
182 			goto err;
183 		}
184 
185 		ptr += ret;
186 		bytes_read += ret;
187 		left_size -= ret;
188 	}
189 
190 	close(fd);
191 
192 	return bytes_read;
193 
194 err:
195 	close(fd);
196 	return 0;
197 }
198