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