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