1 /*
2 * Copyright 2021, 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 "acvp"
18
19 #include "acvp.h"
20
21 // NOTE: modulewrapper.h is not guarded against double inclusion and
22 // keymaster_ckdf.h uses it, so we need to include it before keymaster_ckdf.h
23 #include "modulewrapper.h"
24
25 #include "keymaster_ckdf.h"
26
27 #include <string>
28 #include <vector>
29
30 #include <assert.h>
31 #include <interface/acvp/acvp.h>
32 #include <lib/tipc/tipc.h>
33 #include <lib/tipc/tipc_srv.h>
34 #include <lk/err_ptr.h>
35 #include <openssl/digest.h>
36 #include <openssl/hkdf.h>
37 #include <openssl/span.h>
38 #include <sys/auxv.h>
39 #include <sys/mman.h>
40 #include <trusty_ipc.h>
41 #include <trusty_log.h>
42
43 #define ACVP_PAGE_SIZE getauxval(AT_PAGESZ)
44
45 // Keep modulewrapper.h and acvp.h in sync
46 static_assert(bssl::acvp::kMaxArgs == ACVP_MAX_NUM_ARGUMENTS);
47 static_assert(bssl::acvp::kMaxNameLength == ACVP_MAX_NAME_LENGTH);
48
49 static constexpr char kAdditionalConfig[] = R"(,
50 {
51 "algorithm": "KDF",
52 "revision": "1.0",
53 "capabilities": [{
54 "kdfMode": "counter",
55 "macMode": [
56 "CMAC-AES128",
57 "CMAC-AES256"
58 ],
59 "supportedLengths": [{
60 "min": 8,
61 "max": 4096,
62 "increment": 8
63 }],
64 "fixedDataOrder": [
65 "before fixed data"
66 ],
67 "counterLength": [
68 32
69 ]
70 }]
71 },
72 {
73 "algorithm": "KDA",
74 "mode": "TwoStep",
75 "revision": "Sp800-56Cr2",
76 "capabilities": [{
77 "macSaltMethods": [
78 "random",
79 "default"
80 ],
81 "fixedInfoPattern": "uPartyInfo||vPartyInfo",
82 "encoding": [
83 "concatenation"
84 ],
85 "kdfMode": "feedback",
86 "macMode": [
87 "HMAC-SHA2-256"
88 ],
89 "supportedLengths": [{
90 "min": 128,
91 "max": 1024,
92 "increment": 64
93 }],
94 "fixedDataOrder": [
95 "after fixed data"
96 ],
97 "counterLength": [
98 8
99 ],
100 "requiresEmptyIv": true,
101 "supportsEmptyIv": true
102 }],
103 "l": 1024,
104 "z": [256, 384]
105 }])";
106
107 static struct tipc_port_acl kAcvpPortAcl = {
108 .flags = IPC_PORT_ALLOW_TA_CONNECT | IPC_PORT_ALLOW_NS_CONNECT,
109 .uuid_num = 0,
110 .uuids = NULL,
111 .extra_data = NULL,
112 };
113
114 static struct tipc_port kAcvpPort = {
115 .name = ACVP_PORT,
116 .msg_max_size = ACVP_MAX_MESSAGE_LENGTH,
117 .msg_queue_len = 1,
118 .acl = &kAcvpPortAcl,
119 .priv = NULL,
120 };
121
AlignUpToPage(size_t size)122 static inline size_t AlignUpToPage(size_t size) {
123 return (size + (ACVP_PAGE_SIZE - 1)) & ~(ACVP_PAGE_SIZE - 1);
124 }
125
126 template <const EVP_MD* HashFunc()>
KAS_HKDF(const bssl::Span<const uint8_t> args[],bssl::acvp::ReplyCallback write_reply)127 static bool KAS_HKDF(const bssl::Span<const uint8_t> args[],
128 bssl::acvp::ReplyCallback write_reply) {
129 const bssl::Span<const uint8_t> secret = args[0];
130 const bssl::Span<const uint8_t> salt = args[1];
131 const bssl::Span<const uint8_t> info = args[2];
132 const bssl::Span<const uint8_t> out_len_bytes = args[3];
133
134 uint32_t out_len;
135 if (out_len_bytes.size() != sizeof(out_len)) {
136 return false;
137 }
138 memcpy(&out_len, out_len_bytes.data(), sizeof(out_len));
139
140 std::vector<uint8_t> out(static_cast<size_t>(out_len));
141 int res = HKDF(out.data(), out.size(), HashFunc(), secret.data(),
142 secret.size(), salt.data(), salt.size(), info.data(),
143 info.size());
144 if (res != 1) {
145 return false;
146 }
147
148 return write_reply({out});
149 }
150
151 class TrustyAcvpTool {
152 public:
TrustyAcvpTool(handle_t chan)153 TrustyAcvpTool(handle_t chan) : chan_(chan), arg_buffer_(NULL) {}
154
155 // Send a reply back to the acvptool.
156 //
157 // This function is used by the handler functions to write out results and
158 // should be customized by the tool implementation.
159 bool WriteReply(std::vector<bssl::Span<const uint8_t>> spans);
160
161 bool MapShm(handle_t handle, size_t shm_size);
162
arg_buffer() const163 const uint8_t* arg_buffer() const {
164 assert(arg_buffer_);
165 return arg_buffer_;
166 }
167
arg_buffer_size() const168 size_t arg_buffer_size() const { return arg_buffer_size_; }
169
170 void MessageCleanup();
171
172 ~TrustyAcvpTool();
173
174 private:
175 // Communication handle with the Android modulewrapper tool
176 handle_t chan_;
177
178 // Handle to the shared memory region for arguments
179 handle_t shm_handle_;
180
181 // Size of arg_buffer_ (must be page-aligned)
182 size_t arg_buffer_size_;
183
184 // Mapped buffer from shm_handle_
185 uint8_t* arg_buffer_;
186 };
187
WriteReply(std::vector<bssl::Span<const uint8_t>> spans)188 bool TrustyAcvpTool::WriteReply(std::vector<bssl::Span<const uint8_t>> spans) {
189 if (spans.empty() || spans.size() > bssl::acvp::kMaxArgs) {
190 abort();
191 }
192
193 struct acvp_resp resp;
194 resp.num_spans = spans.size();
195 uint8_t* cur_buffer = arg_buffer_;
196 for (size_t i = 0; i < spans.size(); i++) {
197 const auto& span = spans[i];
198 resp.lengths[i] = span.size();
199 if (span.empty()) {
200 continue;
201 }
202
203 assert(span.size() < arg_buffer_size_ &&
204 cur_buffer - arg_buffer_ + span.size() <= arg_buffer_size_);
205 memcpy(cur_buffer, span.data(), span.size());
206 cur_buffer += span.size();
207 }
208
209 int rc = tipc_send1(chan_, &resp, sizeof(struct acvp_resp));
210 if (rc != sizeof(struct acvp_resp)) {
211 TLOGE("Failed to send ACVP response\n");
212 return false;
213 }
214
215 return true;
216 }
217
MapShm(handle_t shm,size_t size)218 bool TrustyAcvpTool::MapShm(handle_t shm, size_t size) {
219 arg_buffer_size_ = AlignUpToPage(size);
220 shm_handle_ = shm;
221 arg_buffer_ = (uint8_t*)mmap(NULL, arg_buffer_size_, PROT_READ | PROT_WRITE,
222 0, shm_handle_, 0);
223 if (arg_buffer_ == MAP_FAILED) {
224 return false;
225 }
226
227 return true;
228 }
229
MessageCleanup()230 void TrustyAcvpTool::MessageCleanup() {
231 if (arg_buffer_) {
232 int rc = munmap((void*)arg_buffer_, arg_buffer_size_);
233 if (rc != NO_ERROR) {
234 TLOGW("munmap() failed: %d\n", rc);
235 }
236 arg_buffer_ = NULL;
237 }
238
239 if (shm_handle_ != INVALID_IPC_HANDLE) {
240 close(shm_handle_);
241 shm_handle_ = INVALID_IPC_HANDLE;
242 }
243 }
244
~TrustyAcvpTool()245 TrustyAcvpTool::~TrustyAcvpTool() {
246 MessageCleanup();
247 if (chan_ != INVALID_IPC_HANDLE) {
248 close(chan_);
249 }
250 }
251
ParseAcvpMessage(handle_t chan,uint8_t buffer[ACVP_MAX_MESSAGE_LENGTH],struct acvp_req ** request,handle_t * shared_mem)252 static int ParseAcvpMessage(handle_t chan,
253 uint8_t buffer[ACVP_MAX_MESSAGE_LENGTH],
254 struct acvp_req** request,
255 handle_t* shared_mem) {
256 int rc;
257 struct ipc_msg_info msg_info;
258
259 rc = get_msg(chan, &msg_info);
260 if (rc != NO_ERROR) {
261 TLOGE("failed (%d) to get_msg()\n", rc);
262 return rc;
263 }
264
265 struct iovec iov = {
266 .iov_base = buffer,
267 .iov_len = ACVP_MAX_MESSAGE_LENGTH,
268 };
269 struct ipc_msg msg = {
270 .num_iov = 1,
271 .iov = &iov,
272 .num_handles = msg_info.num_handles,
273 .handles = shared_mem,
274 };
275
276 if (msg_info.len < sizeof(struct acvp_req)) {
277 TLOGE("Message is too short: %zd\n", msg_info.len);
278 rc = ERR_BAD_LEN;
279 goto err;
280 }
281
282 if (msg_info.num_handles != 1) {
283 TLOGE("Expected 1 handle, found %d\n", msg_info.num_handles);
284 rc = ERR_BAD_LEN;
285 goto err;
286 }
287
288 rc = read_msg(chan, msg_info.id, 0, &msg);
289 if (rc != sizeof(struct acvp_req)) {
290 TLOGE("failed (%d) to read_msg()\n", rc);
291 if (rc >= 0) {
292 rc = ERR_BAD_LEN;
293 }
294 goto err;
295 }
296
297 rc = NO_ERROR;
298
299 *request = (struct acvp_req*)buffer;
300
301 err:
302 put_msg(chan, msg_info.id);
303 return rc;
304 }
305
AcvpOnConnect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)306 static int AcvpOnConnect(const struct tipc_port* port,
307 handle_t chan,
308 const struct uuid* peer,
309 void** ctx_p) {
310 TrustyAcvpTool* tool = new TrustyAcvpTool(chan);
311 *ctx_p = reinterpret_cast<void*>(tool);
312 return NO_ERROR;
313 }
314
RewriteConfig(TrustyAcvpTool & tool,const std::vector<bssl::Span<const uint8_t>> & args)315 static bool RewriteConfig(TrustyAcvpTool& tool,
316 const std::vector<bssl::Span<const uint8_t>>& args) {
317 assert(args.size() == 1);
318 auto config = args[0];
319 const uint8_t* loc = config.cend() - 1;
320 for (; loc >= config.cbegin(); loc--) {
321 if (*loc == '}') {
322 break;
323 }
324 }
325 assert(loc >= config.cbegin() && loc < config.cend());
326 size_t pos = loc - config.cbegin() + 1;
327
328 std::unique_ptr<uint8_t[]> buf(
329 new (std::nothrow) uint8_t[pos + sizeof(kAdditionalConfig) - 1]);
330 if (!buf) {
331 TLOGE("Could not allocate buffer for config\n");
332 return false;
333 }
334
335 memcpy(buf.get(), config.cbegin(), pos);
336 memcpy(&buf[pos], kAdditionalConfig, sizeof(kAdditionalConfig) - 1);
337 return tool.WriteReply({bssl::Span<uint8_t>(
338 buf.get(), pos + sizeof(kAdditionalConfig) - 1)});
339 }
340
341 static constexpr struct {
342 char name[bssl::acvp::kMaxNameLength + 1];
343 uint8_t num_expected_args;
344 bool (*handler)(const bssl::Span<const uint8_t> args[],
345 bssl::acvp::ReplyCallback write_reply);
346 } kFunctions[] = {
347 {"KDF-counter", 5, KeymasterCKDF},
348 {"HKDF/SHA2-256", 4, KAS_HKDF<EVP_sha256>},
349 };
350
FindTrustyHandler(bssl::Span<const bssl::Span<const uint8_t>> args)351 static bssl::acvp::Handler FindTrustyHandler(
352 bssl::Span<const bssl::Span<const uint8_t>> args) {
353 const bssl::Span<const uint8_t> algorithm = args[0];
354 for (const auto& func : kFunctions) {
355 if (StringEq(algorithm, func.name)) {
356 if (args.size() - 1 != func.num_expected_args) {
357 TLOGE("\'%s\' operation received %zu arguments but expected %u.\n",
358 func.name, args.size() - 1, func.num_expected_args);
359 return nullptr;
360 }
361
362 return func.handler;
363 }
364 }
365
366 const std::string name(reinterpret_cast<const char*>(algorithm.data()),
367 algorithm.size());
368 TLOGE("Unknown operation: %s\n", name.c_str());
369 return nullptr;
370 }
371
AcvpOnMessage(const struct tipc_port * port,handle_t chan,void * ctx)372 static int AcvpOnMessage(const struct tipc_port* port,
373 handle_t chan,
374 void* ctx) {
375 assert(port == &kAcvpPort);
376 assert(ctx != nullptr);
377
378 TrustyAcvpTool* tool = reinterpret_cast<TrustyAcvpTool*>(ctx);
379
380 uint8_t message_buffer[ACVP_MAX_MESSAGE_LENGTH];
381 struct acvp_req* request = nullptr;
382 handle_t shared_mem = INVALID_IPC_HANDLE;
383 int rc = ParseAcvpMessage(chan, message_buffer, &request, &shared_mem);
384 if (rc != NO_ERROR) {
385 TLOGE("Could not parse ACVP message: %d\n", rc);
386 return rc;
387 }
388
389 if (request->num_args > bssl::acvp::kMaxArgs) {
390 TLOGE("Too many args in ACVP message: %d\n", request->num_args);
391 return ERR_INVALID_ARGS;
392 }
393
394 if (!tool->MapShm(shared_mem, request->buffer_size)) {
395 TLOGE("Can't map memory\n");
396 if (shared_mem != INVALID_IPC_HANDLE) {
397 close(shared_mem);
398 }
399 return ERR_NO_MEMORY;
400 } else {
401 bssl::Span<const uint8_t> args[bssl::acvp::kMaxArgs];
402 rc = NO_ERROR;
403
404 uint32_t cur_offset = 0;
405 for (uint32_t i = 0; i < request->num_args; ++i) {
406 uint32_t end;
407 if (__builtin_add_overflow(cur_offset, request->lengths[i], &end) ||
408 end > tool->arg_buffer_size()) {
409 rc = ERR_INVALID_ARGS;
410 goto cleanup;
411 }
412 args[i] = bssl::Span<const uint8_t>(tool->arg_buffer() + cur_offset,
413 request->lengths[i]);
414 cur_offset = end;
415 }
416
417 auto handler =
418 bssl::acvp::FindHandler(bssl::Span(args, request->num_args));
419 if (!handler) {
420 handler = FindTrustyHandler(bssl::Span(args, request->num_args));
421 }
422 if (!handler) {
423 const std::string name(
424 reinterpret_cast<const char*>(args[0].data()),
425 args[0].size());
426 TLOGE("Unknown operation: %s\n", name.c_str());
427 rc = ERR_NOT_FOUND;
428 goto cleanup;
429 }
430
431 // We need to intercept getConfig and append our own config to it.
432 bool is_config = StringEq(args[0], "getConfig");
433
434 bssl::acvp::ReplyCallback callback;
435 if (is_config) {
436 callback = [tool](auto spans) {
437 return RewriteConfig(*tool, spans);
438 };
439 } else {
440 callback = [tool](auto spans) { return tool->WriteReply(spans); };
441 }
442
443 if (!handler(&args[1], callback)) {
444 const std::string name(
445 reinterpret_cast<const char*>(args[0].data()),
446 args[0].size());
447 TLOGE("\'%s\' operation failed.\n", name.c_str());
448 rc = ERR_GENERIC;
449 goto cleanup;
450 }
451 }
452
453 cleanup:
454 tool->MessageCleanup();
455
456 return rc;
457 }
458
AcvpOnChannelCleanup(void * ctx)459 static void AcvpOnChannelCleanup(void* ctx) {
460 TrustyAcvpTool* tool = reinterpret_cast<TrustyAcvpTool*>(ctx);
461 delete tool;
462 }
463
464 static struct tipc_srv_ops kAcvpOps = {
465 .on_connect = AcvpOnConnect,
466 .on_message = AcvpOnMessage,
467 .on_channel_cleanup = AcvpOnChannelCleanup,
468 };
469
main(void)470 int main(void) {
471 struct tipc_hset* hset = tipc_hset_create();
472
473 if (IS_ERR(hset)) {
474 return PTR_ERR(hset);
475 }
476
477 int rc = tipc_add_service(hset, &kAcvpPort, 1, 1, &kAcvpOps);
478 if (rc < 0) {
479 return rc;
480 }
481
482 rc = tipc_run_event_loop(hset);
483 return rc;
484 }
485