• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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