summaryrefslogtreecommitdiff
path: root/ipc/amlogic_keymaster_ipc.cpp (plain)
blob: 00e2d26d7fa20d395ab46dd1038930db78c11080
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#define LOG_TAG "AmlogicKeymaster"
18
19// TODO: make this generic in libtrusty
20
21#include <errno.h>
22#include <stdlib.h>
23#include <string.h>
24#include <sys/uio.h>
25#include <unistd.h>
26
27#include <algorithm>
28
29#include <log/log.h>
30#if !AMLOGIC_MODIFY
31#include <trusty/tipc.h>
32#endif
33#include <amlogic_keymaster/ipc/keymaster_ipc.h>
34#include <amlogic_keymaster/ipc/amlogic_keymaster_ipc.h>
35
36#if AMLOGIC_MODIFY
37TEEC_Result aml_keymaster_connect(TEEC_Context *c, TEEC_Session *s) {
38 TEEC_Result result = TEEC_SUCCESS;
39 TEEC_UUID svc_id = TA_KEYMASTER_UUID;
40 TEEC_Operation operation;
41 uint32_t err_origin;
42 struct timespec time;
43 uint64_t millis = 0;
44
45 memset(&operation, 0, sizeof(operation));
46
47 /* Initialize Context */
48 result = TEEC_InitializeContext(NULL, c);
49
50 if (result != TEEC_SUCCESS) {
51 ALOGD("TEEC_InitializeContext failed with error = %x\n", result);
52 return result;
53 }
54 /* Open Session */
55 result = TEEC_OpenSession(c, s, &svc_id,
56 TEEC_LOGIN_PUBLIC,
57 NULL, NULL,
58 &err_origin);
59
60 if (result != TEEC_SUCCESS) {
61 ALOGD("TEEC_Opensession failed with code 0x%x origin 0x%x",result, err_origin);
62 TEEC_FinalizeContext(c);
63 return result;
64 }
65
66 int res = clock_gettime(CLOCK_BOOTTIME, &time);
67 if (res < 0)
68 millis = 0;
69 else
70 millis = (time.tv_sec * 1000) + (time.tv_nsec / 1000 / 1000);
71
72 /* Init TA */
73 operation.paramTypes = TEEC_PARAM_TYPES(
74 TEEC_VALUE_INPUT, TEEC_NONE,
75 TEEC_NONE, TEEC_NONE);
76
77 operation.params[0].value.a = (millis >> 32);
78 operation.params[0].value.b = (millis & 0xffffffff);
79
80 result = TEEC_InvokeCommand(s,
81 KM_TA_INIT,
82 &operation,
83 NULL);
84
85 ALOGD("create id: %d, ctx: %p, ctx: %p\n", s->session_id, s->ctx, c);
86 return result;
87}
88
89TEEC_Result aml_keymaster_call(TEEC_Session *s, uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
90 uint32_t* out_size) {
91 TEEC_Result res = TEEC_SUCCESS;
92 TEEC_Operation op;
93 uint32_t ret_orig;
94
95 memset(&op, 0, sizeof(op));
96
97 op.params[0].tmpref.buffer = in;
98 op.params[0].tmpref.size = in_size;
99 op.params[1].tmpref.buffer = out;
100 op.params[1].tmpref.size = *out_size;
101 op.paramTypes = TEEC_PARAM_TYPES(
102 TEEC_MEMREF_TEMP_INPUT,
103 TEEC_MEMREF_TEMP_OUTPUT,
104 TEEC_VALUE_OUTPUT,
105 TEEC_NONE);
106
107 ALOGD("id: %d, ctx: %p, cmd: %d\n", s->session_id, s->ctx, cmd);
108 res = TEEC_InvokeCommand(s, cmd, &op, &ret_orig);
109 if (res != TEEC_SUCCESS) {
110 ALOGE("Invoke cmd: %u failed with res(%x), ret_orig(%x), return(%d)\n",
111 cmd, res, ret_orig, op.params[2].value.a);
112 } else {
113 *out_size = op.params[2].value.b;
114 }
115
116 return res;
117}
118
119TEEC_Result aml_keymaster_disconnect(TEEC_Context *c, TEEC_Session *s) {
120 TEEC_Operation operation;
121 TEEC_Result result = TEEC_SUCCESS;
122
123 operation.paramTypes = TEEC_PARAM_TYPES(
124 TEEC_NONE, TEEC_NONE,
125 TEEC_NONE, TEEC_NONE);
126
127 result = TEEC_InvokeCommand(s,
128 KM_TA_TERM,
129 &operation,
130 NULL);
131
132 TEEC_CloseSession(s);
133 TEEC_FinalizeContext(c);
134
135 return result;
136}
137
138keymaster_error_t aml_keymaster_send(TEEC_Session *s, uint32_t command, const keymaster::Serializable& req,
139 keymaster::KeymasterResponse* rsp) {
140 uint32_t req_size = req.SerializedSize();
141 if (req_size > AMLOGIC_KEYMASTER_SEND_BUF_SIZE) {
142 ALOGE("Request too big: %u Max size: %u", req_size, AMLOGIC_KEYMASTER_SEND_BUF_SIZE);
143 return KM_ERROR_INVALID_INPUT_LENGTH;
144 }
145
146 uint8_t send_buf[AMLOGIC_KEYMASTER_SEND_BUF_SIZE];
147 keymaster::Eraser send_buf_eraser(send_buf, AMLOGIC_KEYMASTER_SEND_BUF_SIZE);
148 req.Serialize(send_buf, send_buf + req_size);
149
150 // Send it
151 uint8_t recv_buf[AMLOGIC_KEYMASTER_RECV_BUF_SIZE];
152 keymaster::Eraser recv_buf_eraser(recv_buf, AMLOGIC_KEYMASTER_RECV_BUF_SIZE);
153 uint32_t rsp_size = AMLOGIC_KEYMASTER_RECV_BUF_SIZE;
154 int rc = aml_keymaster_call(s, command, send_buf, req_size, recv_buf, &rsp_size);
155 if (rc < 0) {
156 ALOGE("tipc error: %d\n", rc);
157 // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
158 return translate_error(rc);
159 } else {
160 ALOGD("Received %d byte response\n", rsp_size);
161 }
162
163 const keymaster_message* msg = (keymaster_message*)recv_buf;
164 const uint8_t* p = msg->payload;
165
166 if (!rsp->Deserialize(&p, p + rsp_size)) {
167 ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
168 return KM_ERROR_UNKNOWN_ERROR;
169 } else if (rsp->error != KM_ERROR_OK) {
170 ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
171 return rsp->error;
172 }
173 return rsp->error;
174}
175#else
176#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
177
178static int handle_ = -1;
179
180int trusty_keymaster_connect() {
181 int rc = tipc_connect(TRUSTY_DEVICE_NAME, KEYMASTER_PORT);
182 if (rc < 0) {
183 return rc;
184 }
185
186 handle_ = rc;
187 return 0;
188}
189
190int trusty_keymaster_call(uint32_t cmd, void* in, uint32_t in_size, uint8_t* out,
191 uint32_t* out_size) {
192 if (handle_ < 0) {
193 ALOGE("not connected\n");
194 return -EINVAL;
195 }
196
197 size_t msg_size = in_size + sizeof(struct keymaster_message);
198 struct keymaster_message* msg = reinterpret_cast<struct keymaster_message*>(malloc(msg_size));
199 if (!msg) {
200 ALOGE("failed to allocate msg buffer\n");
201 return -EINVAL;
202 }
203
204 msg->cmd = cmd;
205 memcpy(msg->payload, in, in_size);
206
207 ssize_t rc = write(handle_, msg, msg_size);
208 free(msg);
209
210 if (rc < 0) {
211 ALOGE("failed to send cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT, strerror(errno));
212 return -errno;
213 }
214 size_t out_max_size = *out_size;
215 *out_size = 0;
216 struct iovec iov[2];
217 struct keymaster_message header;
218 iov[0] = {.iov_base = &header, .iov_len = sizeof(struct keymaster_message)};
219 while (true) {
220 iov[1] = {.iov_base = out + *out_size,
221 .iov_len = std::min<uint32_t>(KEYMASTER_MAX_BUFFER_LENGTH,
222 out_max_size - *out_size)};
223 rc = readv(handle_, iov, 2);
224 if (rc < 0) {
225 ALOGE("failed to retrieve response for cmd (%d) to %s: %s\n", cmd, KEYMASTER_PORT,
226 strerror(errno));
227 return -errno;
228 }
229
230 if ((size_t)rc < sizeof(struct keymaster_message)) {
231 ALOGE("invalid response size (%d)\n", (int)rc);
232 return -EINVAL;
233 }
234
235 if ((cmd | KEYMASTER_RESP_BIT) != (header.cmd & ~(KEYMASTER_STOP_BIT))) {
236 ALOGE("invalid command (%d)", header.cmd);
237 return -EINVAL;
238 }
239 *out_size += ((size_t)rc - sizeof(struct keymaster_message));
240 if (header.cmd & KEYMASTER_STOP_BIT) {
241 break;
242 }
243 }
244
245 return rc;
246}
247
248void trusty_keymaster_disconnect() {
249 if (handle_ >= 0) {
250 tipc_close(handle_);
251 }
252 handle_ = -1;
253}
254
255#endif // AMLOGIC_MODIFY
256keymaster_error_t translate_error(int err) {
257 switch (err) {
258 case 0:
259 return KM_ERROR_OK;
260 case -EPERM:
261 case -EACCES:
262 return KM_ERROR_SECURE_HW_ACCESS_DENIED;
263
264 case -ECANCELED:
265 return KM_ERROR_OPERATION_CANCELLED;
266
267 case -ENODEV:
268 return KM_ERROR_UNIMPLEMENTED;
269
270 case -ENOMEM:
271 return KM_ERROR_MEMORY_ALLOCATION_FAILED;
272
273 case -EBUSY:
274 return KM_ERROR_SECURE_HW_BUSY;
275
276 case -EIO:
277 return KM_ERROR_SECURE_HW_COMMUNICATION_FAILED;
278
279 case -EOVERFLOW:
280 return KM_ERROR_INVALID_INPUT_LENGTH;
281
282 default:
283 return KM_ERROR_UNKNOWN_ERROR;
284 }
285}
286#if !AMLOGIC_MODIFY
287keymaster_error_t trusty_keymaster_send(uint32_t command, const keymaster::Serializable& req,
288 keymaster::KeymasterResponse* rsp) {
289 uint32_t req_size = req.SerializedSize();
290 if (req_size > TRUSTY_KEYMASTER_SEND_BUF_SIZE) {
291 ALOGE("Request too big: %u Max size: %u", req_size, TRUSTY_KEYMASTER_SEND_BUF_SIZE);
292 return KM_ERROR_INVALID_INPUT_LENGTH;
293 }
294
295 uint8_t send_buf[TRUSTY_KEYMASTER_SEND_BUF_SIZE];
296 keymaster::Eraser send_buf_eraser(send_buf, TRUSTY_KEYMASTER_SEND_BUF_SIZE);
297 req.Serialize(send_buf, send_buf + req_size);
298
299 // Send it
300 uint8_t recv_buf[TRUSTY_KEYMASTER_RECV_BUF_SIZE];
301 keymaster::Eraser recv_buf_eraser(recv_buf, TRUSTY_KEYMASTER_RECV_BUF_SIZE);
302 uint32_t rsp_size = TRUSTY_KEYMASTER_RECV_BUF_SIZE;
303 int rc = trusty_keymaster_call(command, send_buf, req_size, recv_buf, &rsp_size);
304 if (rc < 0) {
305 // Reset the connection on tipc error
306 trusty_keymaster_disconnect();
307 trusty_keymaster_connect();
308 ALOGE("tipc error: %d\n", rc);
309 // TODO(swillden): Distinguish permanent from transient errors and set error_ appropriately.
310 return translate_error(rc);
311 } else {
312 ALOGV("Received %d byte response\n", rsp_size);
313 }
314
315 const uint8_t* p = recv_buf;
316 if (!rsp->Deserialize(&p, p + rsp_size)) {
317 ALOGE("Error deserializing response of size %d\n", (int)rsp_size);
318 return KM_ERROR_UNKNOWN_ERROR;
319 } else if (rsp->error != KM_ERROR_OK) {
320 ALOGE("Response of size %d contained error code %d\n", (int)rsp_size, (int)rsp->error);
321 return rsp->error;
322 }
323 return rsp->error;
324}
325#endif //!AMLOGIC_MODIFY
326