1 /*
2 * Copyright (C) 2015 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 <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <trusty_ipc.h>
21 #include <uapi/err.h>
22
23 #include <dice/cbor_reader.h>
24 #include <interface/keymaster/keymaster.h>
25 #include <lib/keymaster/keymaster.h>
26
27 #include <openssl/hmac.h>
28
29 #define LOG_TAG "libkeymaster"
30 #define TLOGE(fmt, ...) \
31 fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ##__VA_ARGS__)
32
33 #define HMAC_LEN (sizeof(((hw_auth_token_t*)0)->hmac))
34
35 #define AUTH_TOKEN_KEY_LEN (32)
36
send_req(keymaster_session_t session,uint32_t cmd)37 static long send_req(keymaster_session_t session, uint32_t cmd) {
38 struct keymaster_message msg = {
39 .cmd = cmd,
40 };
41
42 struct iovec tx_iov = {
43 .iov_base = &msg,
44 .iov_len = sizeof(msg),
45 };
46 ipc_msg_t tx_msg = {
47 .iov = &tx_iov,
48 .num_iov = 1,
49 };
50
51 long rc = send_msg(session, &tx_msg);
52 if (rc < 0) {
53 TLOGE("%s: failed (%ld) to send_msg\n", __func__, rc);
54 return rc;
55 }
56
57 if (((size_t)rc) != sizeof(msg)) {
58 TLOGE("%s: msg invalid size (%zu != %zu)", __func__, (size_t)rc,
59 sizeof(msg));
60 return ERR_IO;
61 }
62
63 return NO_ERROR;
64 }
65
await_response(keymaster_session_t session,struct ipc_msg_info * inf)66 static long await_response(keymaster_session_t session,
67 struct ipc_msg_info* inf) {
68 uevent_t uevt;
69 long rc = wait(session, &uevt, INFINITE_TIME);
70 if (rc != NO_ERROR) {
71 TLOGE("%s: interrupted waiting for response (%ld)\n", __func__, rc);
72 return rc;
73 }
74
75 rc = get_msg(session, inf);
76 if (rc != NO_ERROR) {
77 TLOGE("%s: failed to get_msg (%ld)\n", __func__, rc);
78 }
79
80 return rc;
81 }
82
read_response(keymaster_session_t session,uint32_t msg_id,uint32_t cmd,uint8_t * buf,uint32_t size)83 static long read_response(keymaster_session_t session,
84 uint32_t msg_id,
85 uint32_t cmd,
86 uint8_t* buf,
87 uint32_t size) {
88 struct keymaster_message msg;
89
90 struct iovec rx_iov[2] = {
91 {.iov_base = &msg, .iov_len = sizeof(msg)},
92 {.iov_base = buf, .iov_len = size},
93 };
94 struct ipc_msg rx_msg = {
95 .iov = rx_iov,
96 .num_iov = 2,
97 };
98
99 long rc = read_msg(session, msg_id, 0, &rx_msg);
100 put_msg(session, msg_id);
101
102 if ((cmd | KM_RESP_BIT) != (msg.cmd & ~(KM_STOP_BIT))) {
103 TLOGE("%s: invalid response (0x%x) for cmd (0x%x)\n", __func__, msg.cmd,
104 cmd);
105 return ERR_NOT_VALID;
106 }
107
108 return rc;
109 }
110
keymaster_open(void)111 int keymaster_open(void) {
112 return connect(KEYMASTER_SECURE_PORT, IPC_CONNECT_WAIT_FOR_PORT);
113 }
114
keymaster_close(keymaster_session_t session)115 void keymaster_close(keymaster_session_t session) {
116 close(session);
117 }
118
keymaster_send_command(keymaster_session_t session,uint8_t command,uint8_t ** data_buf_p,uint32_t * size_p)119 int keymaster_send_command(keymaster_session_t session,
120 uint8_t command,
121 uint8_t** data_buf_p,
122 uint32_t* size_p) {
123 if (size_p == NULL || data_buf_p == NULL) {
124 return ERR_NOT_VALID;
125 }
126
127 long rc = send_req(session, command);
128 if (rc < 0) {
129 TLOGE("%s: failed (%ld) to send req\n", __func__, rc);
130 return rc;
131 }
132
133 struct ipc_msg_info inf;
134 rc = await_response(session, &inf);
135 if (rc < 0) {
136 TLOGE("%s: failed (%ld) to await response\n", __func__, rc);
137 return rc;
138 }
139
140 if (inf.len <= sizeof(struct keymaster_message)) {
141 TLOGE("%s: invalid response len (%zu)\n", __func__, inf.len);
142 put_msg(session, inf.id);
143 return ERR_NOT_FOUND;
144 }
145
146 size_t size = inf.len - sizeof(struct keymaster_message);
147 uint8_t* data_buf = malloc(size);
148 if (data_buf == NULL) {
149 TLOGE("%s: out of memory (%zu)\n", __func__, inf.len);
150 put_msg(session, inf.id);
151 return ERR_NO_MEMORY;
152 }
153
154 rc = read_response(session, inf.id, command, data_buf, size);
155 if (rc < 0) {
156 goto err_bad_read;
157 }
158
159 size_t read_len = (size_t)rc;
160 if (read_len != inf.len) {
161 // data read in does not match message length
162 TLOGE("%s: invalid read length: (%zu != %zu)\n", __func__, read_len,
163 inf.len);
164 rc = ERR_IO;
165 goto err_bad_read;
166 }
167
168 *size_p = (uint32_t)size;
169 *data_buf_p = data_buf;
170 return NO_ERROR;
171
172 err_bad_read:
173 free(data_buf);
174 TLOGE("%s: failed read_msg (%ld)\n", __func__, rc);
175 return rc;
176 }
177
keymaster_get_auth_token_key(keymaster_session_t session,uint8_t ** key_buf_p,uint32_t * size_p)178 int keymaster_get_auth_token_key(keymaster_session_t session,
179 uint8_t** key_buf_p,
180 uint32_t* size_p) {
181 long rc = keymaster_send_command(session, KM_GET_AUTH_TOKEN_KEY, key_buf_p,
182 size_p);
183 /*
184 * TODO: Return message of this API contains an error if one happened and a
185 * key on success. It may be impossible to distinguish the two if they are
186 * the same size. A proper fix would require changing the layout of the
187 * return message. However, that changes the ABI. So, just assume that the
188 * key is 32 bytes. We know that from KM code.
189 */
190 if (rc == NO_ERROR && *size_p != AUTH_TOKEN_KEY_LEN) {
191 TLOGE("%s: auth token key wrong length: %u, expected %d\n", __func__,
192 *size_p, AUTH_TOKEN_KEY_LEN);
193 rc = ERR_BAD_LEN;
194 free(*key_buf_p);
195 *key_buf_p = NULL;
196 }
197 return rc;
198 }
199
keymaster_get_device_info(keymaster_session_t session,uint8_t ** info_buffer_p,uint32_t * size_p)200 int keymaster_get_device_info(keymaster_session_t session,
201 uint8_t** info_buffer_p,
202 uint32_t* size_p) {
203 long rc = keymaster_send_command(session, KM_GET_DEVICE_INFO, info_buffer_p,
204 size_p);
205 /*
206 * TODO: Return message of this API contains an error if one happened and a
207 * key on success. It may be impossible to distinguish the two if they are
208 * the same size. A proper fix would require changing the layout of the
209 * return message. However, that changes the ABI. So, attempt to parse the
210 * message as a valid CBOR map with non-zero entries. If this fails, it's
211 * an error.
212 */
213 if (rc == NO_ERROR) {
214 struct CborIn in;
215 CborInInit(*info_buffer_p, *size_p, &in);
216 size_t pair_count;
217 if (*size_p == 0 ||
218 CborReadMap(&in, &pair_count) != CBOR_READ_RESULT_OK) {
219 TLOGE("%s: device info byte stream is not valid CBOR or a map.\n",
220 __func__);
221 goto err_bad_cbor;
222 }
223 // Each entry would require at least two bytes.
224 if (*size_p < pair_count * 2) {
225 TLOGE("%s: Device info is malformed. Size is %u, expected > %zu\n",
226 __func__, *size_p, pair_count * 2);
227 goto err_bad_cbor;
228 }
229 }
230 return rc;
231
232 err_bad_cbor:
233 rc = ERR_FAULT;
234 free(*info_buffer_p);
235 *info_buffer_p = NULL;
236 return rc;
237 }
238
mint_hmac(uint8_t * key,size_t key_size,uint8_t * message,size_t message_size,uint8_t * hmac)239 static int mint_hmac(uint8_t* key,
240 size_t key_size,
241 uint8_t* message,
242 size_t message_size,
243 uint8_t* hmac) {
244 unsigned int tok_size;
245 unsigned char* ret;
246 memset(hmac, 0, HMAC_LEN);
247 ret = HMAC(EVP_sha256(), (void*)key, key_size, message, message_size, hmac,
248 &tok_size);
249 if (ret == NULL || tok_size != HMAC_LEN) {
250 TLOGE("Failed to execute HMAC()!\n");
251 return ERR_FAULT;
252 }
253
254 return NO_ERROR;
255 }
256
keymaster_sign_auth_token(keymaster_session_t session,hw_auth_token_t * token)257 int keymaster_sign_auth_token(keymaster_session_t session,
258 hw_auth_token_t* token) {
259 int ret = NO_ERROR;
260
261 if (token == NULL) {
262 TLOGE("Invalid token!\n");
263 return ERR_NOT_VALID;
264 }
265
266 uint8_t* key_buf;
267 uint32_t key_buf_size;
268 ret = keymaster_get_auth_token_key(session, &key_buf, &key_buf_size);
269 if (ret) {
270 return ret;
271 }
272
273 /* Initialize the token and message size */
274 size_t message_size = sizeof(hw_auth_token_t) - sizeof(token->hmac);
275 /* Mint the token key with the given HMAC key and message */
276 ret = mint_hmac(key_buf, key_buf_size, (uint8_t*)token, message_size,
277 token->hmac);
278
279 free_mem:
280 free(key_buf);
281 return ret;
282 }
283
keymaster_validate_auth_token(keymaster_session_t session,hw_auth_token_t * token)284 int keymaster_validate_auth_token(keymaster_session_t session,
285 hw_auth_token_t* token) {
286 int ret = NO_ERROR;
287
288 if (token == NULL) {
289 TLOGE("Invalid token!\n");
290 return ERR_NOT_VALID;
291 }
292
293 uint8_t* key_buf;
294 uint32_t key_buf_size;
295 ret = keymaster_get_auth_token_key(session, &key_buf, &key_buf_size);
296 if (ret) {
297 return ret;
298 }
299
300 /* compute the expected token hmac */
301 uint8_t expected_hmac[HMAC_LEN];
302 size_t message_size = sizeof(hw_auth_token_t) - sizeof(token->hmac);
303
304 ret = mint_hmac(key_buf, key_buf_size, (uint8_t*)token, message_size,
305 expected_hmac);
306 if (ret) {
307 goto free_mem;
308 }
309
310 /* Compare the expected hmac with the provided hmac */
311 ret = memcmp(expected_hmac, token->hmac, sizeof(expected_hmac));
312
313 free_mem:
314 free(key_buf);
315 return ret;
316 }
317