1 /*
2  * Copyright (C) 2016-2017 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 <assert.h>
18 #include <lk/compiler.h>
19 #include <stddef.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <trusty_ipc.h>
24 #include <uapi/err.h>
25 
26 #include <interface/hwkey/hwkey.h>
27 #include <nxp_hwcrypto_uuid_consts.h>
28 
29 #include "common.h"
30 #include "hwkey_srv_priv.h"
31 
32 #define TLOG_TAG "hwkey_srv"
33 #include <trusty_log.h>
34 
35 #define HWKEY_MAX_PAYLOAD_SIZE 2048
36 
37 struct hwkey_chan_ctx {
38     tipc_event_handler_t evt_handler;
39     handle_t chan;
40     uuid_t uuid;
41 };
42 
43 static void hwkey_port_handler(const uevent_t* ev, void* priv);
44 static void hwkey_chan_handler(const uevent_t* ev, void* priv);
45 
46 static tipc_event_handler_t hwkey_port_evt_handler = {
47         .proc = hwkey_port_handler,
48 };
49 
50 /* Make sure that key_data and reg_data buffers are not crossing page boundary
51  * so it is safe to pass them to DMA. An extra byte for req_data buf is used to
52  * zero terminate string so it is OK to have it on separate page as it will
53  * never be accesed by DMA engine.
54  */
55 static uint8_t key_data[HWKEY_MAX_PAYLOAD_SIZE]
56         __attribute__((aligned(HWKEY_MAX_PAYLOAD_SIZE)));
57 static uint8_t req_data[HWKEY_MAX_PAYLOAD_SIZE + 1]
58         __attribute__((aligned(HWKEY_MAX_PAYLOAD_SIZE)));
59 
60 static unsigned int key_slot_cnt;
61 static const struct hwkey_keyslot* key_slots;
62 
63 #if WITH_HWCRYPTO_UNITTEST
64 /*
65  *  Support for hwcrypto unittest keys should be only enabled
66  *  to test hwcrypto related APIs
67  */
68 
69 /* UUID of HWCRYPTO_UNITTEST application */
70 static const uuid_t hwcrypto_unittest_uuid = HWCRYPTO_UNITTEST_APP_UUID;
71 
72 static uint8_t _unittest_key32[32] = "unittestkeyslotunittestkeyslotun";
get_unittest_key32(const struct hwkey_keyslot * slot,uint8_t * kbuf,size_t kbuf_len,size_t * klen)73 static uint32_t get_unittest_key32(const struct hwkey_keyslot* slot,
74                                    uint8_t* kbuf,
75                                    size_t kbuf_len,
76                                    size_t* klen) {
77     assert(kbuf);
78     assert(klen);
79     assert(kbuf_len >= sizeof(_unittest_key32));
80 
81     /* just return predefined key */
82     memcpy(kbuf, _unittest_key32, sizeof(_unittest_key32));
83     *klen = sizeof(_unittest_key32);
84 
85     return HWKEY_NO_ERROR;
86 }
87 
88 static const struct hwkey_keyslot test_key_slots[] = {
89         {
90                 .uuid = &hwcrypto_unittest_uuid,
91                 .key_id = "com.android.trusty.hwcrypto.unittest.key32",
92                 .handler = get_unittest_key32,
93         },
94 };
95 #endif /* WITH_HWCRYPTO_UNITTEST */
96 
97 /*
98  * Close specified hwkey context
99  */
hwkey_ctx_close(struct hwkey_chan_ctx * ctx)100 static void hwkey_ctx_close(struct hwkey_chan_ctx* ctx) {
101     close(ctx->chan);
102     free(ctx);
103 }
104 
105 /*
106  * Send response message
107  */
hwkey_send_rsp(struct hwkey_chan_ctx * ctx,struct hwkey_msg * rsp_msg,uint8_t * rsp_data,size_t rsp_data_len)108 static int hwkey_send_rsp(struct hwkey_chan_ctx* ctx,
109                           struct hwkey_msg* rsp_msg,
110                           uint8_t* rsp_data,
111                           size_t rsp_data_len) {
112     rsp_msg->header.cmd |= HWKEY_RESP_BIT;
113     return tipc_send_two_segments(ctx->chan, rsp_msg, sizeof(*rsp_msg),
114                                   rsp_data, rsp_data_len);
115 }
116 
_handle_slots(struct hwkey_chan_ctx * ctx,const char * slot_id,const struct hwkey_keyslot * slots,unsigned int slot_cnt,uint8_t * kbuf,size_t kbuf_len,size_t * klen)117 static uint32_t _handle_slots(struct hwkey_chan_ctx* ctx,
118                               const char* slot_id,
119                               const struct hwkey_keyslot* slots,
120                               unsigned int slot_cnt,
121                               uint8_t* kbuf,
122                               size_t kbuf_len,
123                               size_t* klen) {
124     if (!slots)
125         return HWKEY_ERR_NOT_FOUND;
126 
127     for (unsigned int i = 0; i < slot_cnt; i++, slots++) {
128         /* check key id */
129         if (strcmp(slots->key_id, slot_id))
130             continue;
131 
132         /* Check if the caller is allowed to get that key */
133         if (memcmp(&ctx->uuid, slots->uuid, sizeof(uuid_t)) == 0) {
134             if (slots->handler) {
135                 return slots->handler(slots, kbuf, kbuf_len, klen);
136             }
137         }
138     }
139     return HWKEY_ERR_NOT_FOUND;
140 }
141 
142 /*
143  * Handle get key slot command
144  */
hwkey_handle_get_keyslot_cmd(struct hwkey_chan_ctx * ctx,struct hwkey_msg * msg,const char * slot_id)145 static int hwkey_handle_get_keyslot_cmd(struct hwkey_chan_ctx* ctx,
146                                         struct hwkey_msg* msg,
147                                         const char* slot_id) {
148     int rc;
149     size_t klen = 0;
150 
151     msg->header.status = _handle_slots(ctx, slot_id, key_slots, key_slot_cnt,
152                                        key_data, sizeof(key_data), &klen);
153 
154 #if WITH_HWCRYPTO_UNITTEST
155     if (msg->header.status == HWKEY_ERR_NOT_FOUND) {
156         /* also search test keys */
157         msg->header.status = _handle_slots(ctx, slot_id, test_key_slots,
158                                            countof(test_key_slots), key_data,
159                                            sizeof(key_data), &klen);
160     }
161 #endif
162 
163     rc = hwkey_send_rsp(ctx, msg, key_data, klen);
164     if (klen) {
165         /* sanitize key buffer */
166         memset(key_data, 0, klen);
167     }
168     return rc;
169 }
170 
171 /*
172  * Handle Derive key cmd
173  */
hwkey_handle_derive_key_cmd(struct hwkey_chan_ctx * ctx,struct hwkey_msg * msg,const uint8_t * ikm_data,size_t ikm_len)174 static int hwkey_handle_derive_key_cmd(struct hwkey_chan_ctx* ctx,
175                                        struct hwkey_msg* msg,
176                                        const uint8_t* ikm_data,
177                                        size_t ikm_len) {
178     int rc;
179     size_t key_len = sizeof(key_data);
180 
181     /* check requested key derivation function */
182     if (msg->arg1 == HWKEY_KDF_VERSION_BEST)
183         msg->arg1 = HWKEY_KDF_VERSION_1; /* we only support V1 */
184 
185     switch (msg->arg1) {
186     case HWKEY_KDF_VERSION_1:
187         msg->header.status = derive_key_v1(&ctx->uuid, ikm_data, ikm_len,
188                                            key_data, &key_len);
189         break;
190 
191     default:
192         TLOGE("%u is unsupported KDF function\n", msg->arg1);
193         key_len = 0;
194         msg->header.status = HWKEY_ERR_NOT_IMPLEMENTED;
195     }
196 
197     rc = hwkey_send_rsp(ctx, msg, key_data, key_len);
198     if (key_len) {
199         /* sanitize key buffer */
200         memset(key_data, 0, key_len);
201     }
202     return rc;
203 }
204 
205 /*
206  *  Read and queue HWKEY request message
207  */
hwkey_chan_handle_msg(struct hwkey_chan_ctx * ctx)208 static int hwkey_chan_handle_msg(struct hwkey_chan_ctx* ctx) {
209     int rc;
210     size_t req_data_len;
211     struct hwkey_msg msg;
212 
213     rc = tipc_recv_two_segments(ctx->chan, &msg, sizeof(msg), req_data,
214                                 sizeof(req_data) - 1);
215     if (rc < 0) {
216         TLOGE("failed (%d) to recv msg from chan %d\n", rc, ctx->chan);
217         return rc;
218     }
219 
220     /* calculate payload length */
221     req_data_len = (size_t)rc - sizeof(msg);
222 
223     /* handle it */
224     switch (msg.header.cmd) {
225     case HWKEY_GET_KEYSLOT:
226         req_data[req_data_len] = 0; /* force zero termination */
227         rc = hwkey_handle_get_keyslot_cmd(ctx, &msg, (const char*)req_data);
228         break;
229 
230     case HWKEY_DERIVE:
231         rc = hwkey_handle_derive_key_cmd(ctx, &msg, req_data, req_data_len);
232         memset(req_data, 0, req_data_len); /* sanitize request buffer */
233         break;
234 
235     default:
236         TLOGE("Unsupported request: %d\n", (int)msg.header.cmd);
237         msg.header.status = HWKEY_ERR_NOT_IMPLEMENTED;
238         rc = hwkey_send_rsp(ctx, &msg, NULL, 0);
239     }
240 
241     return rc;
242 }
243 
244 /*
245  *  HWKEY service channel event handler
246  */
hwkey_chan_handler(const uevent_t * ev,void * priv)247 static void hwkey_chan_handler(const uevent_t* ev, void* priv) {
248     struct hwkey_chan_ctx* ctx = priv;
249 
250     assert(ctx);
251     assert(ev->handle == ctx->chan);
252 
253     tipc_handle_chan_errors(ev);
254 
255     if (ev->event & IPC_HANDLE_POLL_HUP) {
256         /* closed by peer. */
257         hwkey_ctx_close(ctx);
258         return;
259     }
260 
261     if (ev->event & IPC_HANDLE_POLL_MSG) {
262         int rc = hwkey_chan_handle_msg(ctx);
263         if (rc < 0) {
264             /* report an error and close channel */
265             TLOGE("failed (%d) to handle event on channel %d\n", rc,
266                   ev->handle);
267             hwkey_ctx_close(ctx);
268         }
269     }
270 }
271 
272 /*
273  * HWKEY service port event handler
274  */
hwkey_port_handler(const uevent_t * ev,void * priv)275 static void hwkey_port_handler(const uevent_t* ev, void* priv) {
276     uuid_t peer_uuid;
277 
278     tipc_handle_port_errors(ev);
279 
280     if (ev->event & IPC_HANDLE_POLL_READY) {
281         /* incoming connection: accept it */
282         int rc = accept(ev->handle, &peer_uuid);
283         if (rc < 0) {
284             TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle);
285             return;
286         }
287 
288         handle_t chan = (handle_t)rc;
289         struct hwkey_chan_ctx* ctx = calloc(1, sizeof(*ctx));
290         if (!ctx) {
291             TLOGE("failed (%d) to allocate context on chan %d\n", rc, chan);
292             close(chan);
293             return;
294         }
295 
296         /* init channel state */
297         ctx->evt_handler.priv = ctx;
298         ctx->evt_handler.proc = hwkey_chan_handler;
299         ctx->chan = chan;
300         ctx->uuid = peer_uuid;
301 
302         rc = set_cookie(chan, &ctx->evt_handler);
303         if (rc < 0) {
304             TLOGE("failed (%d) to set_cookie on chan %d\n", rc, chan);
305             hwkey_ctx_close(ctx);
306             return;
307         }
308     }
309 }
310 
311 /*
312  *  Install Key slot provider
313  */
hwkey_install_keys(const struct hwkey_keyslot * keys,unsigned int kcnt)314 void hwkey_install_keys(const struct hwkey_keyslot* keys, unsigned int kcnt) {
315     assert(key_slots == NULL);
316     assert(key_slot_cnt == 0);
317     assert(keys && kcnt);
318 
319     key_slots = keys;
320     key_slot_cnt = kcnt;
321 }
322 
323 /*
324  *  Initialize HWKEY service
325  */
hwkey_start_service(void)326 int hwkey_start_service(void) {
327     int rc;
328     handle_t port;
329 
330     TLOGD("Start HWKEY service\n");
331 
332     /* Initialize service */
333     rc = port_create(HWKEY_PORT, 1,
334                      sizeof(struct hwkey_msg) + HWKEY_MAX_PAYLOAD_SIZE,
335                      IPC_PORT_ALLOW_TA_CONNECT);
336     if (rc < 0) {
337         TLOGE("Failed (%d) to create port %s\n", rc, HWKEY_PORT);
338         return rc;
339     }
340 
341     port = (handle_t)rc;
342     rc = set_cookie(port, &hwkey_port_evt_handler);
343     if (rc) {
344         TLOGE("failed (%d) to set_cookie on port %d\n", rc, port);
345         close(port);
346         return rc;
347     }
348 
349     return NO_ERROR;
350 }
351