1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  * Copyright 2017 NXP
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <assert.h>
19 #include <stddef.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <uapi/err.h>
24 
25 #include <interface/hwkey/hwkey.h>
26 #include <nxp_hwcrypto_uuid_consts.h>
27 #include <openssl/aes.h>
28 #include <openssl/cipher.h>
29 #include <openssl/digest.h>
30 #include <openssl/err.h>
31 #include <openssl/hkdf.h>
32 
33 #include "caam.h"
34 #include "common.h"
35 #include "hwkey_keyslots.h"
36 #include "hwkey_srv_priv.h"
37 
38 #define TLOG_TAG "hwkey_caam"
39 #include <trusty_log.h>
40 
41 static const uint8_t skeymod[16] __attribute__((aligned(16))) = {
42         0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
43         0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
44 
45 static uint8_t kdfv1_key[32] __attribute__((aligned(32)));
46 
47 /*
48  * Derive key V1 - HKDF based key derive.
49  */
derive_key_v1(const uuid_t * uuid,const uint8_t * ikm_data,size_t ikm_len,uint8_t * key_buf,size_t * key_len)50 uint32_t derive_key_v1(const uuid_t* uuid,
51                        const uint8_t* ikm_data,
52                        size_t ikm_len,
53                        uint8_t* key_buf,
54                        size_t* key_len) {
55     uint32_t res;
56 
57     *key_len = 0;
58 
59     if (!ikm_len)
60         return HWKEY_ERR_BAD_LEN;
61 
62     if (!HKDF(key_buf, ikm_len, EVP_sha256(), (const uint8_t*)kdfv1_key,
63               sizeof(kdfv1_key), (const uint8_t*)uuid, sizeof(uuid_t), ikm_data,
64               ikm_len)) {
65         TLOGE("HDKF failed 0x%x\n", ERR_get_error());
66         memset(key_buf, 0, ikm_len);
67         res = HWKEY_ERR_GENERIC;
68         goto done;
69     }
70     *key_len = ikm_len;
71     res = HWKEY_NO_ERROR;
72 done:
73     return res;
74 }
75 
76 /*
77  *  RPMB Key support
78  */
79 #define RPMB_SS_AUTH_KEY_SIZE 32
80 #define RPMB_SS_AUTH_KEY_ID "com.android.trusty.storage_auth.rpmb"
81 
82 /* Secure storage service app uuid */
83 static const uuid_t ss_uuid = SECURE_STORAGE_SERVER_APP_UUID;
84 static size_t rpmb_keyblob_len;
85 static uint8_t rpmb_keyblob[RPMBKEY_LEN];
86 
87 /*
88  * Fetch RPMB Secure Storage Authentication key
89  */
get_rpmb_ss_auth_key(const struct hwkey_keyslot * slot,uint8_t * kbuf,size_t kbuf_len,size_t * klen)90 static uint32_t get_rpmb_ss_auth_key(const struct hwkey_keyslot* slot,
91                                      uint8_t* kbuf,
92                                      size_t kbuf_len,
93                                      size_t* klen) {
94     uint32_t res;
95     assert(kbuf_len >= RPMB_SS_AUTH_KEY_SIZE);
96 
97     if (rpmb_keyblob_len != sizeof(rpmb_keyblob))
98         return HWKEY_ERR_NOT_FOUND; /* no RPMB key */
99 
100     res = caam_decap_blob(skeymod, sizeof(skeymod), kbuf, rpmb_keyblob,
101                           RPMB_SS_AUTH_KEY_SIZE);
102     if (res == CAAM_SUCCESS) {
103         *klen = RPMB_SS_AUTH_KEY_SIZE;
104         return HWKEY_NO_ERROR;
105     } else {
106         /* wipe target buffer */
107         TLOGE("%s: failed to unpack rpmb key\n", __func__);
108         memset(kbuf, 0, RPMB_SS_AUTH_KEY_SIZE);
109         return HWKEY_ERR_GENERIC;
110     }
111 }
112 
113 /*
114  *  List of keys slots that hwkey service supports
115  */
116 static const struct hwkey_keyslot _keys[] = {
117         {
118                 .uuid = &ss_uuid,
119                 .key_id = RPMB_SS_AUTH_KEY_ID,
120                 .handler = get_rpmb_ss_auth_key,
121         },
122 };
123 
unpack_kbox(void)124 static void unpack_kbox(void) {
125     uint32_t res;
126     struct keyslot_package* kbox = caam_get_keybox();
127 
128     if (strncmp(kbox->magic, KEYPACK_MAGIC, 4)) {
129         TLOGE("Invalid magic\n");
130         abort();
131     }
132 
133     /* Copy RPMB blob */
134     assert(!rpmb_keyblob_len); /* key should be unset */
135     if (kbox->rpmb_keyblob_len != sizeof(rpmb_keyblob)) {
136         TLOGE("Unexpected RPMB key len: %u\n", kbox->rpmb_keyblob_len);
137     } else {
138         memcpy(rpmb_keyblob, kbox->rpmb_keyblob, kbox->rpmb_keyblob_len);
139         rpmb_keyblob_len = kbox->rpmb_keyblob_len;
140     }
141 
142     /* generate kdfv1 root it should never fail */
143     res = caam_gen_kdfv1_root_key(kdfv1_key, sizeof(kdfv1_key));
144     assert(res == CAAM_SUCCESS);
145 
146     /* copy pubkey blob */
147 
148     /* wipe kbox in sram */
149     memset(kbox, 0, sizeof(*kbox));
150 }
151 
152 /*
153  *  Initialize Fake HWKEY service provider
154  */
hwkey_init_srv_provider(void)155 void hwkey_init_srv_provider(void) {
156     int rc;
157 
158     TLOGD("Init HWKEY service provider\n");
159 
160     unpack_kbox();
161 
162     /* install key handlers */
163     hwkey_install_keys(_keys, countof(_keys));
164 
165     /* start service */
166     rc = hwkey_start_service();
167     if (rc != NO_ERROR) {
168         TLOGE("failed (%d) to start HWKEY service\n", rc);
169     }
170 }
171