1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "include/lib/hwbcc/client/hwbcc.h"
18 #define TLOG_TAG "hwbcc-client"
19
20 #include <assert.h>
21 #include <interface/hwbcc/hwbcc.h>
22 #include <lib/hwbcc/client/hwbcc.h>
23 #include <lib/tipc/tipc.h>
24 #include <string.h>
25 #include <trusty_log.h>
26 #include <uapi/err.h>
27
recv_resp(handle_t chan,struct hwbcc_req_hdr * hdr,uint8_t * buf,size_t buf_size,size_t * out_size)28 static int recv_resp(handle_t chan,
29 struct hwbcc_req_hdr* hdr,
30 uint8_t* buf,
31 size_t buf_size,
32 size_t* out_size) {
33 uevent_t uevt;
34 struct hwbcc_resp_hdr resp;
35
36 assert(buf);
37 assert(out_size);
38
39 int rc = wait(chan, &uevt, INFINITE_TIME);
40 if (rc != NO_ERROR) {
41 TLOGE("Failure while waiting for response: %d\n", rc);
42 return rc;
43 }
44
45 rc = tipc_recv2(chan, sizeof(resp), &resp, sizeof(resp), buf, buf_size);
46 if (rc < 0) {
47 TLOGE("Failure on receiving response: %d\n", rc);
48 return rc;
49 }
50
51 if (resp.cmd != (hdr->cmd | HWBCC_CMD_RESP_BIT)) {
52 TLOGE("Unknown response cmd: %x\n", resp.cmd);
53 return ERR_CMD_UNKNOWN;
54 }
55
56 if (resp.status != NO_ERROR) {
57 TLOGE("Status is not SUCCESS. Actual: %d\n", resp.status);
58 rc = resp.status;
59 return rc;
60 }
61
62 if (resp.payload_size != (size_t)rc - sizeof(resp)) {
63 return ERR_IO;
64 }
65
66 if (resp.payload_size > HWBCC_MAX_RESP_PAYLOAD_SIZE ||
67 resp.payload_size > buf_size) {
68 TLOGE("Response payload size: %d\n", resp.payload_size);
69 return ERR_BAD_LEN;
70 }
71
72 *out_size = resp.payload_size;
73 return NO_ERROR;
74 }
75
76 /**
77 * sign_data() - Signs data and returns a COSE_Sign1 message.
78 * @chan: TIPC channel to HWBCC server
79 * @test_mode: Whether or not a to return test values.
80 * @cose_algorithm: COSE encoding of which signing algorithm to use.
81 * @data: Pointer to data.
82 * @data_size: Size of @data.
83 * @aad: Pointer to AAD.
84 * @aad_size: Size of @aad.
85 * @cose_sign1: Buffer to push the formatted Sign1 msg into.
86 * @cose_sign1_buf_size: Size of the buffer.
87 * @cose_sign1_size: Out parameter for actual size of the buffer used.
88 *
89 * Signs data using the device private key, encoding the result in a
90 * COSE_Sign1 message.
91 *
92 * Return: 0 on success, or an error code < 0 on failure.
93 */
sign_data(handle_t chan,uint8_t test_mode,int32_t cose_algorithm,const uint8_t * data,uint32_t data_size,const uint8_t * aad,size_t aad_size,uint8_t * cose_sign1,size_t cose_sign1_buf_size,size_t * cose_sign1_size)94 static int sign_data(handle_t chan,
95 uint8_t test_mode,
96 int32_t cose_algorithm,
97 const uint8_t* data,
98 uint32_t data_size,
99 const uint8_t* aad,
100 size_t aad_size,
101 uint8_t* cose_sign1,
102 size_t cose_sign1_buf_size,
103 size_t* cose_sign1_size) {
104 int rc;
105 struct hwbcc_sign_data_hdr {
106 struct hwbcc_req_hdr hdr;
107 struct hwbcc_req_sign_data args;
108 } req;
109 STATIC_ASSERT(sizeof(struct hwbcc_sign_data_hdr) ==
110 sizeof(struct hwbcc_req_hdr) +
111 sizeof(struct hwbcc_req_sign_data));
112 assert(data);
113 if (aad_size > 0) {
114 assert(aad);
115 }
116 assert(cose_sign1);
117 assert(cose_sign1_size);
118
119 if (data_size > HWBCC_MAX_DATA_TO_SIGN_SIZE) {
120 TLOGE("Data exceeds HWBCC_MAX_DATA_TO_SIGN_SIZE limit: %u > %u.\n",
121 data_size, HWBCC_MAX_DATA_TO_SIGN_SIZE);
122 return ERR_BAD_LEN;
123 }
124
125 if (aad_size > HWBCC_MAX_AAD_SIZE) {
126 TLOGE("AAD exceeds HWBCC_MAX_AAD_SIZE limit: %zu > %u\n", aad_size,
127 HWBCC_MAX_AAD_SIZE);
128 return ERR_BAD_LEN;
129 }
130
131 memset(&req, 0, sizeof(req));
132 req.hdr.cmd = HWBCC_CMD_SIGN_DATA;
133 req.hdr.test_mode = test_mode;
134 req.args.algorithm = cose_algorithm;
135 req.args.data_size = data_size;
136 req.args.aad_size = aad_size;
137
138 uint32_t iov_count = 2;
139 struct iovec iovs[3] = {
140 {
141 .iov_base = (void*)&req,
142 .iov_len = sizeof(req),
143 },
144 {
145 .iov_base = (void*)data,
146 .iov_len = data_size,
147 },
148 {
149 .iov_base = NULL,
150 .iov_len = aad_size,
151 },
152 };
153 if (aad) {
154 iov_count = 3;
155 iovs[2].iov_base = (void*)aad;
156 }
157 ipc_msg_t msg = {
158 .iov = iovs,
159 .num_iov = iov_count,
160 .handles = NULL,
161 .num_handles = 0,
162 };
163
164 rc = send_msg(chan, &msg);
165 if (rc < 0) {
166 TLOGE("Unable to send sign_data request: %d\n", rc);
167 return rc;
168 }
169
170 if ((size_t)rc != sizeof(req) + req.args.data_size + req.args.aad_size) {
171 TLOGE("Only sent %d bytes of the sign_data request.\n", rc);
172 return rc;
173 }
174
175 return recv_resp(chan, &req.hdr, cose_sign1, cose_sign1_buf_size,
176 cose_sign1_size);
177 }
178
179 /**
180 * get_bcc() - Retrieves the Boot Certificate Chain for the device.
181 * @chan: TIPC channel to HWBCC server
182 * @test_mode: Whether or not a to return test values.
183 * @bcc: Pointer to a buffer to store the BCC in.
184 * @bcc_buf_size: Size of the @bcc buffer.
185 * @bcc_size: Actual size of the buffer used.
186 *
187 * Return: 0 on success, or an error code < 0 on failure.
188 */
get_bcc(handle_t chan,uint8_t test_mode,uint8_t * bcc,size_t bcc_buf_size,size_t * bcc_size)189 static int get_bcc(handle_t chan,
190 uint8_t test_mode,
191 uint8_t* bcc,
192 size_t bcc_buf_size,
193 size_t* bcc_size) {
194 int rc;
195
196 assert(bcc);
197 assert(bcc_size);
198
199 struct hwbcc_req_hdr hdr = {
200 .cmd = HWBCC_CMD_GET_BCC,
201 .test_mode = test_mode
202 };
203
204 rc = tipc_send1(chan, &hdr, sizeof(hdr));
205 if (rc < 0) {
206 TLOGE("Unable to send get_bcc request: %d\n", rc);
207 return rc;
208 }
209
210 if ((size_t)rc != sizeof(hdr)) {
211 TLOGE("Only sent %d bytes of the get_bcc request.\n", rc);
212 return rc;
213 }
214
215 return recv_resp(chan, &hdr, bcc, bcc_buf_size, bcc_size);
216 }
217
hwbcc_get_protected_data(uint8_t test_mode,int32_t cose_algorithm,const uint8_t * data,uint32_t data_size,const uint8_t * aad,size_t aad_size,uint8_t * cose_sign1,size_t cose_sign1_buf_size,size_t * cose_sign1_size,uint8_t * bcc,size_t bcc_buf_size,size_t * bcc_size)218 int hwbcc_get_protected_data(uint8_t test_mode,
219 int32_t cose_algorithm,
220 const uint8_t* data,
221 uint32_t data_size,
222 const uint8_t* aad,
223 size_t aad_size,
224 uint8_t* cose_sign1,
225 size_t cose_sign1_buf_size,
226 size_t* cose_sign1_size,
227 uint8_t* bcc,
228 size_t bcc_buf_size,
229 size_t* bcc_size) {
230 int rc;
231 handle_t chan;
232
233 rc = tipc_connect(&chan, HWBCC_PORT);
234 if (rc < 0) {
235 TLOGE("Failed to connect to %s: %d\n", HWBCC_PORT, rc);
236 return rc;
237 }
238
239 rc = sign_data(chan, test_mode, cose_algorithm, data, data_size, aad,
240 aad_size, cose_sign1, cose_sign1_buf_size, cose_sign1_size);
241 if (rc != NO_ERROR) {
242 TLOGE("Failed sign_data(): %d\n", rc);
243 goto out;
244 }
245
246 rc = get_bcc(chan, test_mode, bcc, bcc_buf_size, bcc_size);
247 if (rc != NO_ERROR) {
248 TLOGE("Failed get_bcc(): %d\n", rc);
249 goto out;
250 }
251
252 out:
253 close(chan);
254 return rc;
255 }
256
hwbcc_get_dice_artifacts(uint64_t context,uint8_t * dice_artifacts,size_t dice_artifacts_buf_size,size_t * dice_artifacts_size)257 int hwbcc_get_dice_artifacts(uint64_t context,
258 uint8_t* dice_artifacts,
259 size_t dice_artifacts_buf_size,
260 size_t* dice_artifacts_size) {
261 int rc;
262 handle_t chan;
263
264 rc = tipc_connect(&chan, HWBCC_PORT);
265 if (rc < 0) {
266 TLOGE("Failed to connect to %s: %d\n", HWBCC_PORT, rc);
267 return rc;
268 }
269
270 assert(dice_artifacts);
271 assert(dice_artifacts_size);
272
273 struct hwbcc_req_hdr hdr = {
274 .cmd = HWBCC_CMD_GET_DICE_ARTIFACTS,
275 .context = context
276 };
277
278 rc = tipc_send1(chan, &hdr, sizeof(hdr));
279 if (rc < 0) {
280 TLOGE("Unable to send get_dice_artifacts request: %d\n", rc);
281 goto out;
282 }
283
284 if ((size_t)rc != sizeof(hdr)) {
285 TLOGE("Only sent %d bytes of get_dice_artifacts request.\n", rc);
286 goto out;
287 }
288
289 rc = recv_resp(chan, &hdr, dice_artifacts, dice_artifacts_buf_size,
290 dice_artifacts_size);
291 if (rc != NO_ERROR) {
292 TLOGE("Failed get_dice_artifacts(): %d\n", rc);
293 goto out;
294 }
295
296 out:
297 close(chan);
298 return rc;
299 }
300
hwbcc_ns_deprivilege(void)301 int hwbcc_ns_deprivilege(void) {
302 int rc;
303 handle_t chan;
304
305 rc = tipc_connect(&chan, HWBCC_PORT);
306 if (rc < 0) {
307 TLOGE("Failed to connect to %s: %d\n", HWBCC_PORT, rc);
308 return rc;
309 }
310
311 struct hwbcc_req_hdr hdr = {
312 .cmd = HWBCC_CMD_NS_DEPRIVILEGE
313 };
314
315 rc = tipc_send1(chan, &hdr, sizeof(hdr));
316 if (rc < 0) {
317 TLOGE("Unable to send deprivilege request: %d\n", rc);
318 goto out;
319 }
320
321 if ((size_t)rc != sizeof(hdr)) {
322 TLOGE("Only sent %d bytes of deprivilege request.\n", rc);
323 goto out;
324 }
325
326 /*Receive respose which only contains a header*/
327 uevent_t uevt;
328 struct hwbcc_resp_hdr resp;
329
330 rc = wait(chan, &uevt, INFINITE_TIME);
331 if (rc != NO_ERROR) {
332 TLOGE("Failure while waiting for response: %d\n", rc);
333 goto out;
334 }
335
336 rc = tipc_recv1(chan, sizeof(resp), &resp, sizeof(resp));
337 if (rc < 0) {
338 TLOGE("Failure on receiving response: %d\n", rc);
339 goto out;
340 }
341
342 if (resp.cmd != (hdr.cmd | HWBCC_CMD_RESP_BIT)) {
343 TLOGE("Unknown response cmd: %x\n", resp.cmd);
344 rc = ERR_CMD_UNKNOWN;
345 goto out;
346 }
347
348 if (resp.status != NO_ERROR) {
349 TLOGE("Status is not SUCCESS. Actual: %d\n", resp.status);
350 rc = resp.status;
351 goto out;
352 }
353
354 rc = NO_ERROR;
355
356 out:
357 close(chan);
358 return rc;
359 }
360