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