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