1 /*
2 * Copyright (C) 2016 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 #define TLOG_TAG "hwkey_srv"
18
19 #include <assert.h>
20 #include <lk/list.h>
21 #include <stdbool.h>
22 #include <stddef.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <uapi/err.h>
27
28 #include <interface/hwkey/hwkey.h>
29 #include <lib/tipc/tipc.h>
30 #include <openssl/evp.h>
31 #include <openssl/mem.h>
32 #include <trusty_log.h>
33
34 #include <hwcrypto/hwrng_dev.h>
35 #include <hwcrypto_consts.h>
36 #include "hwkey_srv_priv.h"
37
38 struct hwkey_chan_ctx {
39 struct tipc_event_handler evt_handler;
40 handle_t chan;
41 uuid_t uuid;
42 };
43
44 /**
45 * An opaque key access token.
46 *
47 * Clients can retrieve an opaque access token as a handle to a key they are
48 * allowed to use but not read directly. This handle can then be passed to other
49 * crypto services which can use the token to retrieve the actual key from
50 * hwkey.
51 */
52 typedef char access_token_t[HWKEY_OPAQUE_HANDLE_SIZE];
53
54 struct opaque_handle_node {
55 const struct hwkey_keyslot* key_slot;
56 struct hwkey_chan_ctx* owner;
57 access_token_t token;
58 struct list_node node;
59 };
60
61 /*
62 * Global list of currently valid opaque handles. Each client may only have a
63 * single entry in this list for a given key slot, and this entry will be
64 * cleaned up when the connection it was created for is closed.
65 */
66 static struct list_node opaque_handles = LIST_INITIAL_VALUE(opaque_handles);
67
68 static void hwkey_port_handler(const uevent_t* ev, void* priv);
69 static void hwkey_chan_handler(const uevent_t* ev, void* priv);
70
71 static struct tipc_event_handler hwkey_port_evt_handler = {
72 .proc = hwkey_port_handler,
73 };
74
75 static uint8_t req_data[HWKEY_MAX_MSG_SIZE + 1];
76 static __attribute__((aligned(4))) uint8_t key_data[HWKEY_MAX_MSG_SIZE];
77
78 static unsigned int key_slot_cnt;
79 static const struct hwkey_keyslot* key_slots;
80
is_opaque_handle(const struct hwkey_keyslot * key_slot)81 static bool is_opaque_handle(const struct hwkey_keyslot* key_slot) {
82 assert(key_slot);
83 return key_slot->handler == get_key_handle;
84 }
85
delete_opaque_handle(struct opaque_handle_node * node)86 static void delete_opaque_handle(struct opaque_handle_node* node) {
87 assert(node);
88
89 /* Zero out the access token just in case the memory is reused */
90 memset(node->token, 0, HWKEY_OPAQUE_HANDLE_SIZE);
91
92 list_delete(&node->node);
93 free(node);
94 }
95
96 /*
97 * Close specified hwkey context
98 */
hwkey_ctx_close(struct hwkey_chan_ctx * ctx)99 static void hwkey_ctx_close(struct hwkey_chan_ctx* ctx) {
100 struct opaque_handle_node* entry;
101 struct opaque_handle_node* temp;
102 list_for_every_entry_safe(&opaque_handles, entry, temp,
103 struct opaque_handle_node, node) {
104 if (entry->owner == ctx) {
105 delete_opaque_handle(entry);
106 }
107 }
108 close(ctx->chan);
109 free(ctx);
110 }
111
112 /*
113 * Send response message
114 */
hwkey_send_rsp(struct hwkey_chan_ctx * ctx,struct hwkey_msg * rsp_hdr,uint8_t * rsp_data,size_t rsp_data_len)115 static int hwkey_send_rsp(struct hwkey_chan_ctx* ctx,
116 struct hwkey_msg* rsp_hdr,
117 uint8_t* rsp_data,
118 size_t rsp_data_len) {
119 rsp_hdr->header.cmd |= HWKEY_RESP_BIT;
120 return tipc_send2(ctx->chan, rsp_hdr, sizeof(*rsp_hdr), rsp_data,
121 rsp_data_len);
122 }
123
is_allowed_to_read_opaque_key(const uuid_t * uuid,const struct hwkey_keyslot * slot)124 static bool is_allowed_to_read_opaque_key(const uuid_t* uuid,
125 const struct hwkey_keyslot* slot) {
126 assert(slot);
127 const struct hwkey_opaque_handle_data* handle = slot->priv;
128 assert(handle);
129
130 for (size_t i = 0; i < handle->allowed_uuids_len; ++i) {
131 if (memcmp(handle->allowed_uuids[i], uuid, sizeof(uuid_t)) == 0) {
132 return true;
133 }
134 }
135 return false;
136 }
137
find_opaque_handle_for_slot(const struct hwkey_keyslot * slot)138 static struct opaque_handle_node* find_opaque_handle_for_slot(
139 const struct hwkey_keyslot* slot) {
140 struct opaque_handle_node* entry;
141 list_for_every_entry(&opaque_handles, entry, struct opaque_handle_node,
142 node) {
143 if (entry->key_slot == slot) {
144 return entry;
145 }
146 }
147
148 return NULL;
149 }
150
151 /*
152 * If a handle doesn't exist yet for the given slot, create and insert a new one
153 * in the global list.
154 */
insert_handle_node(struct hwkey_chan_ctx * ctx,const struct hwkey_keyslot * slot)155 static uint32_t insert_handle_node(struct hwkey_chan_ctx* ctx,
156 const struct hwkey_keyslot* slot) {
157 struct opaque_handle_node* entry = find_opaque_handle_for_slot(slot);
158
159 if (!entry) {
160 entry = calloc(1, sizeof(struct opaque_handle_node));
161 if (!entry) {
162 TLOGE("Could not allocate new opaque_handle_node\n");
163 return HWKEY_ERR_GENERIC;
164 }
165
166 entry->owner = ctx;
167 entry->key_slot = slot;
168 list_add_tail(&opaque_handles, &entry->node);
169 }
170
171 return HWKEY_NO_ERROR;
172 }
173
_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)174 static uint32_t _handle_slots(struct hwkey_chan_ctx* ctx,
175 const char* slot_id,
176 const struct hwkey_keyslot* slots,
177 unsigned int slot_cnt,
178 uint8_t* kbuf,
179 size_t kbuf_len,
180 size_t* klen) {
181 if (!slots)
182 return HWKEY_ERR_NOT_FOUND;
183
184 for (unsigned int i = 0; i < slot_cnt; i++, slots++) {
185 /* check key id */
186 if (strcmp(slots->key_id, slot_id))
187 continue;
188
189 /* Check if the caller is allowed to get that key */
190 if (memcmp(&ctx->uuid, slots->uuid, sizeof(uuid_t)) == 0) {
191 if (slots->handler) {
192 if (is_opaque_handle(slots)) {
193 uint32_t rc = insert_handle_node(ctx, slots);
194 if (rc != HWKEY_NO_ERROR)
195 return rc;
196 }
197 return slots->handler(slots, kbuf, kbuf_len, klen);
198 }
199 }
200 }
201
202 /*
203 * We couldn't match a key ID, so try to treat the id as an opaque access
204 * handle
205 */
206 return get_opaque_key(&ctx->uuid, slot_id, kbuf, kbuf_len, klen);
207 }
208
hwkey_get_derived_key(const struct hwkey_derived_keyslot_data * data,uint8_t * kbuf,size_t kbuf_len,size_t * klen)209 uint32_t hwkey_get_derived_key(const struct hwkey_derived_keyslot_data* data,
210 uint8_t* kbuf,
211 size_t kbuf_len,
212 size_t* klen) {
213 assert(kbuf);
214 assert(klen);
215 assert(data);
216 assert(data->encrypted_key_size_ptr);
217
218 uint8_t key_buffer[HWKEY_DERIVED_KEY_MAX_SIZE] = {0};
219 size_t key_len;
220 uint32_t rc =
221 data->retriever(data, key_buffer, sizeof(key_buffer), &key_len);
222 if (rc != HWKEY_NO_ERROR) {
223 return rc;
224 }
225
226 const EVP_CIPHER* cipher;
227 switch (key_len) {
228 case 16:
229 cipher = EVP_aes_128_cbc();
230 break;
231 case 32:
232 cipher = EVP_aes_256_cbc();
233 break;
234 default:
235 TLOGE("invalid key length: (%zd)\n", key_len);
236 return HWKEY_ERR_GENERIC;
237 }
238
239 int evp_ret;
240 int out_len = 0;
241 uint8_t* iv = NULL;
242 EVP_CIPHER_CTX* cipher_ctx = EVP_CIPHER_CTX_new();
243 if (!cipher_ctx) {
244 return HWKEY_ERR_GENERIC;
245 }
246
247 /* if we exit early */
248 rc = HWKEY_ERR_GENERIC;
249
250 evp_ret = EVP_DecryptInit_ex(cipher_ctx, cipher, NULL, NULL, NULL);
251 if (evp_ret != 1) {
252 TLOGE("Initializing decryption algorithm failed\n");
253 goto out;
254 }
255
256 unsigned int iv_length = EVP_CIPHER_CTX_iv_length(cipher_ctx);
257
258 /* encrypted key contains IV + ciphertext */
259 if (iv_length >= *data->encrypted_key_size_ptr) {
260 TLOGE("Encrypted key is too small\n");
261 goto out;
262 }
263
264 if (kbuf_len < *data->encrypted_key_size_ptr - iv_length) {
265 TLOGE("Not enough space in output buffer\n");
266 rc = HWKEY_ERR_BAD_LEN;
267 goto out;
268 }
269
270 evp_ret = EVP_DecryptInit_ex(cipher_ctx, cipher, NULL, key_buffer,
271 data->encrypted_key_data);
272 if (evp_ret != 1) {
273 TLOGE("Initializing decryption algorithm failed\n");
274 goto out;
275 }
276
277 evp_ret = EVP_CIPHER_CTX_set_padding(cipher_ctx, 0);
278 if (evp_ret != 1) {
279 TLOGE("EVP_CIPHER_CTX_set_padding failed\n");
280 goto out;
281 }
282
283 evp_ret = EVP_DecryptUpdate(cipher_ctx, kbuf, &out_len,
284 data->encrypted_key_data + iv_length,
285 *data->encrypted_key_size_ptr - iv_length);
286 if (evp_ret != 1) {
287 TLOGE("EVP_DecryptUpdate failed\n");
288 goto out;
289 }
290
291 /* We don't support padding so input length == output length */
292 assert(out_len >= 0 &&
293 (unsigned int)out_len == *data->encrypted_key_size_ptr - iv_length);
294
295 evp_ret = EVP_DecryptFinal_ex(cipher_ctx, NULL, &out_len);
296 if (evp_ret != 1) {
297 TLOGE("EVP_DecryptFinal failed\n");
298 goto out;
299 }
300
301 assert(out_len == 0);
302
303 *klen = *data->encrypted_key_size_ptr - iv_length;
304
305 /* Decryption was successful */
306 rc = HWKEY_NO_ERROR;
307
308 out:
309 if (iv) {
310 free(iv);
311 }
312 EVP_CIPHER_CTX_free(cipher_ctx);
313 return rc;
314 }
315
316 /*
317 * Handle get key slot command
318 */
hwkey_handle_get_keyslot_cmd(struct hwkey_chan_ctx * ctx,struct hwkey_msg * hdr,const char * slot_id)319 static int hwkey_handle_get_keyslot_cmd(struct hwkey_chan_ctx* ctx,
320 struct hwkey_msg* hdr,
321 const char* slot_id) {
322 int rc;
323 size_t klen = 0;
324
325 hdr->header.status = _handle_slots(ctx, slot_id, key_slots, key_slot_cnt,
326 key_data, sizeof(key_data), &klen);
327
328 rc = hwkey_send_rsp(ctx, hdr, key_data, klen);
329 if (klen) {
330 /* sanitize key buffer */
331 memset(key_data, 0, klen);
332 }
333 return rc;
334 }
335
336 /* Shared implementation for the unversioned key derivation API */
hwkey_handle_derive_key_impl(uint32_t * kdf_version,const uuid_t * uuid,const uint8_t * context,size_t context_len,uint8_t * key,size_t key_len)337 static uint32_t hwkey_handle_derive_key_impl(uint32_t* kdf_version,
338 const uuid_t* uuid,
339 const uint8_t* context,
340 size_t context_len,
341 uint8_t* key,
342 size_t key_len) {
343 /* check requested key derivation function */
344 if (*kdf_version == HWKEY_KDF_VERSION_BEST) {
345 *kdf_version = HWKEY_KDF_VERSION_1;
346 }
347
348 if (!context || !key || key_len == 0) {
349 return HWKEY_ERR_NOT_VALID;
350 }
351
352 switch (*kdf_version) {
353 case HWKEY_KDF_VERSION_1:
354 return derive_key_v1(uuid, context, context_len, key, key_len);
355
356 default:
357 TLOGE("%u is unsupported KDF function\n", *kdf_version);
358 return HWKEY_ERR_NOT_IMPLEMENTED;
359 }
360 }
361
362 /*
363 * Handle Derive key cmd
364 */
hwkey_handle_derive_key_cmd(struct hwkey_chan_ctx * ctx,struct hwkey_msg * hdr,const uint8_t * ikm_data,size_t ikm_len)365 static int hwkey_handle_derive_key_cmd(struct hwkey_chan_ctx* ctx,
366 struct hwkey_msg* hdr,
367 const uint8_t* ikm_data,
368 size_t ikm_len) {
369 int rc;
370 size_t key_len = ikm_len;
371 if (key_len > HWKEY_MAX_MSG_SIZE - sizeof(*hdr)) {
372 TLOGE("Key length exceeds message size: %zu\n", key_len);
373 key_len = 0;
374 hdr->header.status = HWKEY_ERR_BAD_LEN;
375 goto send_response;
376 }
377
378 hdr->header.status = hwkey_handle_derive_key_impl(
379 &hdr->arg1, &ctx->uuid, ikm_data, ikm_len, key_data, key_len);
380
381 send_response:
382 rc = hwkey_send_rsp(ctx, hdr, key_data, key_len);
383 if (key_len) {
384 /* sanitize key buffer */
385 memset(key_data, 0, sizeof(key_data));
386 }
387 return rc;
388 }
389
390 /**
391 * hwkey_handle_derive_versioned_key_cmd() - Handle versioned key derivation
392 * @ctx: client context
393 * @msg: request/response message
394 * @context: key derivation info input
395 * @context_len: length in bytes of @context
396 *
397 * Derive a new key from an internal secret key, unique to the provided context,
398 * UUID of the client, and requested rollback version. Rollback versions greater
399 * than the current image or fused rollback version are not allowed. See &struct
400 * hwkey_derive_versioned_msg for more details.
401 *
402 * Because key versions newer than the current image rollback version are not
403 * available to clients, incrementing this version in the Trusty image results
404 * in a new set of keys being available that previous Trusty apps never had
405 * access to. This mechanism can be used to roll to new keys after patching a
406 * Trusty app vulnerability that may have exposed old keys. If the key
407 * derivation is implemented outside of Trusty entirely, then keys can be
408 * refreshed after a potential Trusty kernel compromise.
409 *
410 * Return: A negative return value indicates an error occurred sending the IPC
411 * response back to the client.
412 */
hwkey_handle_derive_versioned_key_cmd(struct hwkey_chan_ctx * ctx,struct hwkey_derive_versioned_msg * msg,const uint8_t * context,size_t context_len)413 static int hwkey_handle_derive_versioned_key_cmd(
414 struct hwkey_chan_ctx* ctx,
415 struct hwkey_derive_versioned_msg* msg,
416 const uint8_t* context,
417 size_t context_len) {
418 int i;
419 int rc;
420 bool shared = msg->key_options & HWKEY_SHARED_KEY_TYPE;
421 uint32_t status;
422 size_t key_len;
423
424 key_len = msg->key_len;
425 if (key_len > HWKEY_MAX_MSG_SIZE - sizeof(*msg)) {
426 TLOGE("Key length (%zu) exceeds buffer length\n", key_len);
427 status = HWKEY_ERR_BAD_LEN;
428 goto send_response;
429 }
430
431 /*
432 * make sure to retrieve the current OS version before calling
433 * hwkey_derive_versioned_msg_compatible_with_unversioned() so that we
434 * derive the same key with CURRENT == 0 and 0 passed explicitly.
435 */
436
437 int os_rollback_version =
438 msg->rollback_versions[HWKEY_ROLLBACK_VERSION_OS_INDEX];
439 if (os_rollback_version == HWKEY_ROLLBACK_VERSION_CURRENT) {
440 os_rollback_version =
441 get_current_os_rollback_version(msg->rollback_version_source);
442 if (os_rollback_version < 0) {
443 status = HWKEY_ERR_GENERIC;
444 goto send_response;
445 }
446 msg->rollback_versions[HWKEY_ROLLBACK_VERSION_OS_INDEX] =
447 os_rollback_version;
448 }
449
450 for (i = HWKEY_ROLLBACK_VERSION_SUPPORTED_COUNT;
451 i < HWKEY_ROLLBACK_VERSION_INDEX_COUNT; ++i) {
452 if (msg->rollback_versions[i] != 0) {
453 TLOGE("Unsupported rollback version set: %d\n", i);
454 status = HWKEY_ERR_NOT_VALID;
455 goto send_response;
456 }
457 }
458
459 if (hwkey_derive_versioned_msg_compatible_with_unversioned(msg)) {
460 status = hwkey_handle_derive_key_impl(&msg->kdf_version, &ctx->uuid,
461 context, context_len, key_data,
462 key_len);
463 if (key_len == 0) {
464 /*
465 * derive_key_v1() doesn't support an empty key length, but we still
466 * want to allow querying key versions with NULL key and zero
467 * length. Reset the status to ok in this case.
468 */
469 status = HWKEY_NO_ERROR;
470 }
471 goto send_response;
472 }
473
474 /* check requested key derivation function */
475 if (msg->kdf_version == HWKEY_KDF_VERSION_BEST) {
476 msg->kdf_version = HWKEY_KDF_VERSION_1;
477 }
478
479 switch (msg->kdf_version) {
480 case HWKEY_KDF_VERSION_1:
481 status = derive_key_versioned_v1(&ctx->uuid, shared,
482 msg->rollback_version_source,
483 msg->rollback_versions, context,
484 context_len, key_data, key_len);
485 break;
486
487 default:
488 TLOGE("%u is unsupported KDF function\n", msg->kdf_version);
489 status = HWKEY_ERR_NOT_IMPLEMENTED;
490 }
491
492 send_response:
493 if (status != HWKEY_NO_ERROR) {
494 msg->key_len = 0;
495 }
496
497 msg->header.status = status;
498 msg->header.cmd |= HWKEY_RESP_BIT;
499 rc = tipc_send2(ctx->chan, msg, sizeof(*msg), key_data, msg->key_len);
500 if (msg->key_len) {
501 /* sanitize key buffer */
502 memset(key_data, 0, sizeof(key_data));
503 }
504 return rc;
505 }
506
507 /*
508 * Read and queue HWKEY request message
509 */
hwkey_chan_handle_msg(struct hwkey_chan_ctx * ctx)510 static int hwkey_chan_handle_msg(struct hwkey_chan_ctx* ctx) {
511 int rc;
512 size_t req_data_len;
513 struct hwkey_msg_header* hdr;
514
515 rc = tipc_recv1(ctx->chan, sizeof(*hdr), req_data, sizeof(req_data) - 1);
516 if (rc < 0) {
517 TLOGE("failed (%d) to recv msg from chan %d\n", rc, ctx->chan);
518 return rc;
519 }
520
521 req_data_len = (size_t)rc;
522
523 if (req_data_len < sizeof(*hdr)) {
524 TLOGE("Received too little data (%zu) from chan %d\n", req_data_len,
525 ctx->chan);
526 return ERR_BAD_LEN;
527 }
528
529 hdr = (struct hwkey_msg_header*)req_data;
530
531 /* handle it */
532 switch (hdr->cmd) {
533 case HWKEY_GET_KEYSLOT:
534 req_data[req_data_len] = 0; /* force zero termination */
535 if (req_data_len < sizeof(struct hwkey_msg)) {
536 TLOGE("Received too little data (%zu) from chan %d\n", req_data_len,
537 ctx->chan);
538 return ERR_BAD_LEN;
539 }
540 rc = hwkey_handle_get_keyslot_cmd(
541 ctx, (struct hwkey_msg*)req_data,
542 (const char*)(req_data + sizeof(struct hwkey_msg)));
543 break;
544
545 case HWKEY_DERIVE:
546 if (req_data_len < sizeof(struct hwkey_msg)) {
547 TLOGE("Received too little data (%zu) from chan %d\n", req_data_len,
548 ctx->chan);
549 return ERR_BAD_LEN;
550 }
551 rc = hwkey_handle_derive_key_cmd(
552 ctx, (struct hwkey_msg*)req_data,
553 req_data + sizeof(struct hwkey_msg),
554 req_data_len - sizeof(struct hwkey_msg));
555 memset(req_data, 0, req_data_len); /* sanitize request buffer */
556 break;
557
558 case HWKEY_DERIVE_VERSIONED:
559 if (req_data_len < sizeof(struct hwkey_derive_versioned_msg)) {
560 TLOGE("Received too little data (%zu) from chan %d\n", req_data_len,
561 ctx->chan);
562 return ERR_BAD_LEN;
563 }
564 rc = hwkey_handle_derive_versioned_key_cmd(
565 ctx, (struct hwkey_derive_versioned_msg*)req_data,
566 req_data + sizeof(struct hwkey_derive_versioned_msg),
567 req_data_len - sizeof(struct hwkey_derive_versioned_msg));
568 memset(req_data, 0, req_data_len); /* sanitize request buffer */
569 break;
570
571 default:
572 TLOGE("Unsupported request: %d\n", (int)hdr->cmd);
573 hdr->status = HWKEY_ERR_NOT_IMPLEMENTED;
574 hdr->cmd |= HWKEY_RESP_BIT;
575 rc = tipc_send1(ctx->chan, hdr, sizeof(*hdr));
576 }
577
578 return rc;
579 }
580
581 /*
582 * HWKEY service channel event handler
583 */
hwkey_chan_handler(const uevent_t * ev,void * priv)584 static void hwkey_chan_handler(const uevent_t* ev, void* priv) {
585 struct hwkey_chan_ctx* ctx = priv;
586
587 assert(ctx);
588 assert(ev->handle == ctx->chan);
589
590 tipc_handle_chan_errors(ev);
591
592 if (ev->event & IPC_HANDLE_POLL_HUP) {
593 /* closed by peer. */
594 hwkey_ctx_close(ctx);
595 return;
596 }
597
598 if (ev->event & IPC_HANDLE_POLL_MSG) {
599 int rc = hwkey_chan_handle_msg(ctx);
600 if (rc < 0) {
601 /* report an error and close channel */
602 TLOGE("failed (%d) to handle event on channel %d\n", rc,
603 ev->handle);
604 hwkey_ctx_close(ctx);
605 }
606 }
607 }
608
609 /*
610 * HWKEY service port event handler
611 */
hwkey_port_handler(const uevent_t * ev,void * priv)612 static void hwkey_port_handler(const uevent_t* ev, void* priv) {
613 uuid_t peer_uuid;
614
615 tipc_handle_port_errors(ev);
616
617 if (ev->event & IPC_HANDLE_POLL_READY) {
618 /* incoming connection: accept it */
619 int rc = accept(ev->handle, &peer_uuid);
620 if (rc < 0) {
621 TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle);
622 return;
623 }
624
625 handle_t chan = (handle_t)rc;
626 if (!hwkey_client_allowed(&peer_uuid)) {
627 TLOGE("access to hwkey service denied\n");
628 close(chan);
629 return;
630 }
631
632 struct hwkey_chan_ctx* ctx = calloc(1, sizeof(*ctx));
633 if (!ctx) {
634 TLOGE("failed (%d) to allocate context on chan %d\n", rc, chan);
635 close(chan);
636 return;
637 }
638
639 /* init channel state */
640 ctx->evt_handler.priv = ctx;
641 ctx->evt_handler.proc = hwkey_chan_handler;
642 ctx->chan = chan;
643 ctx->uuid = peer_uuid;
644
645 rc = set_cookie(chan, &ctx->evt_handler);
646 if (rc < 0) {
647 TLOGE("failed (%d) to set_cookie on chan %d\n", rc, chan);
648 hwkey_ctx_close(ctx);
649 return;
650 }
651 }
652 }
653
654 /*
655 * Install Key slot provider
656 */
hwkey_install_keys(const struct hwkey_keyslot * keys,unsigned int kcnt)657 void hwkey_install_keys(const struct hwkey_keyslot* keys, unsigned int kcnt) {
658 assert(key_slots == NULL);
659 assert(key_slot_cnt == 0);
660 assert(keys && kcnt);
661
662 key_slots = keys;
663 key_slot_cnt = kcnt;
664 }
665
is_empty_token(const char * access_token)666 static bool is_empty_token(const char* access_token) {
667 for (int i = 0; i < HWKEY_OPAQUE_HANDLE_SIZE; i++) {
668 if (access_token[i] != 0) {
669 assert(strnlen(access_token, HWKEY_OPAQUE_HANDLE_SIZE) ==
670 HWKEY_OPAQUE_HANDLE_SIZE - 1);
671 return false;
672 }
673 }
674 return true;
675 }
676
get_key_handle(const struct hwkey_keyslot * slot,uint8_t * kbuf,size_t kbuf_len,size_t * klen)677 uint32_t get_key_handle(const struct hwkey_keyslot* slot,
678 uint8_t* kbuf,
679 size_t kbuf_len,
680 size_t* klen) {
681 assert(kbuf);
682 assert(klen);
683
684 const struct hwkey_opaque_handle_data* handle = slot->priv;
685 assert(handle);
686 assert(kbuf_len >= HWKEY_OPAQUE_HANDLE_SIZE);
687
688 struct opaque_handle_node* entry = find_opaque_handle_for_slot(slot);
689 /* _handle_slots should have already created an entry for this slot */
690 assert(entry);
691
692 if (!is_empty_token(entry->token)) {
693 /*
694 * We do not allow fetching a token again for the same slot again after
695 * the token is first created and returned
696 */
697 return HWKEY_ERR_ALREADY_EXISTS;
698 }
699
700 /*
701 * We want to generate a null-terminated opaque handle with no interior null
702 * bytes, so we generate extra randomness and only use the non-zero bytes.
703 */
704 uint8_t random_buf[HWKEY_OPAQUE_HANDLE_SIZE + 2];
705 while (1) {
706 int rc = hwrng_dev_get_rng_data(random_buf, sizeof(random_buf));
707 if (rc != NO_ERROR) {
708 /* Don't leave an empty entry if we couldn't generate a token */
709 delete_opaque_handle(entry);
710 return rc;
711 }
712
713 size_t token_offset = 0;
714 for (size_t i = 0; i < sizeof(random_buf) &&
715 token_offset < HWKEY_OPAQUE_HANDLE_SIZE - 1;
716 ++i) {
717 if (random_buf[i] != 0) {
718 entry->token[token_offset] = random_buf[i];
719 token_offset++;
720 }
721 }
722 if (token_offset == HWKEY_OPAQUE_HANDLE_SIZE - 1) {
723 break;
724 }
725 }
726
727 /* ensure that token is properly null-terminated */
728 assert(entry->token[HWKEY_OPAQUE_HANDLE_SIZE - 1] == 0);
729
730 memcpy(kbuf, entry->token, HWKEY_OPAQUE_HANDLE_SIZE);
731 *klen = HWKEY_OPAQUE_HANDLE_SIZE;
732
733 return HWKEY_NO_ERROR;
734 }
735
get_opaque_key(const uuid_t * uuid,const char * access_token,uint8_t * kbuf,size_t kbuf_len,size_t * klen)736 uint32_t get_opaque_key(const uuid_t* uuid,
737 const char* access_token,
738 uint8_t* kbuf,
739 size_t kbuf_len,
740 size_t* klen) {
741 struct opaque_handle_node* entry;
742 list_for_every_entry(&opaque_handles, entry, struct opaque_handle_node,
743 node) {
744 /* get_key_handle should never leave an empty token in the list */
745 assert(!is_empty_token(entry->token));
746
747 if (!is_allowed_to_read_opaque_key(uuid, entry->key_slot))
748 continue;
749
750 /*
751 * We are using a constant-time memcmp here to avoid side-channel
752 * leakage of the access token. Even if we trust the service that is
753 * allowed to retrieve this key, one of its clients may be trying to
754 * brute force the token, so this comparison must be constant-time.
755 */
756 if (CRYPTO_memcmp(entry->token, access_token,
757 HWKEY_OPAQUE_HANDLE_SIZE) == 0) {
758 const struct hwkey_opaque_handle_data* handle =
759 entry->key_slot->priv;
760 assert(handle);
761 return handle->retriever(handle, kbuf, kbuf_len, klen);
762 }
763 }
764
765 return HWKEY_ERR_NOT_FOUND;
766 }
767
768 /*
769 * Initialize HWKEY service
770 */
hwkey_start_service(void)771 int hwkey_start_service(void) {
772 int rc;
773 handle_t port;
774
775 TLOGD("Start HWKEY service\n");
776
777 /* Initialize service */
778 rc = port_create(HWKEY_PORT, 1, HWKEY_MAX_MSG_SIZE,
779 IPC_PORT_ALLOW_TA_CONNECT);
780 if (rc < 0) {
781 TLOGE("Failed (%d) to create port %s\n", rc, HWKEY_PORT);
782 return rc;
783 }
784
785 port = (handle_t)rc;
786 rc = set_cookie(port, &hwkey_port_evt_handler);
787 if (rc) {
788 TLOGE("failed (%d) to set_cookie on port %d\n", rc, port);
789 close(port);
790 return rc;
791 }
792
793 return NO_ERROR;
794 }
795