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