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 munmap((void*)arg_buffer_, arg_buffer_size_);
233 arg_buffer_ = NULL;
234 }
235
236 if (shm_handle_ != INVALID_IPC_HANDLE) {
237 close(shm_handle_);
238 shm_handle_ = INVALID_IPC_HANDLE;
239 }
240 }
241
~TrustyAcvpTool()242 TrustyAcvpTool::~TrustyAcvpTool() {
243 MessageCleanup();
244 if (chan_ != INVALID_IPC_HANDLE) {
245 close(chan_);
246 }
247 }
248
ParseAcvpMessage(handle_t chan,uint8_t buffer[ACVP_MAX_MESSAGE_LENGTH],struct acvp_req ** request,handle_t * shared_mem)249 static int ParseAcvpMessage(handle_t chan,
250 uint8_t buffer[ACVP_MAX_MESSAGE_LENGTH],
251 struct acvp_req** request,
252 handle_t* shared_mem) {
253 int rc;
254 struct ipc_msg_info msg_info;
255
256 rc = get_msg(chan, &msg_info);
257 if (rc != NO_ERROR) {
258 TLOGE("failed (%d) to get_msg()\n", rc);
259 return rc;
260 }
261
262 struct iovec iov = {
263 .iov_base = buffer,
264 .iov_len = ACVP_MAX_MESSAGE_LENGTH,
265 };
266 struct ipc_msg msg = {
267 .num_iov = 1,
268 .iov = &iov,
269 .num_handles = msg_info.num_handles,
270 .handles = shared_mem,
271 };
272
273 if (msg_info.len < sizeof(struct acvp_req)) {
274 TLOGE("Message is too short: %zd\n", msg_info.len);
275 rc = ERR_BAD_LEN;
276 goto err;
277 }
278
279 if (msg_info.num_handles != 1) {
280 TLOGE("Expected 1 handle, found %d\n", msg_info.num_handles);
281 rc = ERR_BAD_LEN;
282 goto err;
283 }
284
285 rc = read_msg(chan, msg_info.id, 0, &msg);
286 if (rc != sizeof(struct acvp_req)) {
287 TLOGE("failed (%d) to read_msg()\n", rc);
288 if (rc >= 0) {
289 rc = ERR_BAD_LEN;
290 }
291 goto err;
292 }
293
294 rc = NO_ERROR;
295
296 *request = (struct acvp_req*)buffer;
297
298 err:
299 put_msg(chan, msg_info.id);
300 return rc;
301 }
302
AcvpOnConnect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)303 static int AcvpOnConnect(const struct tipc_port* port,
304 handle_t chan,
305 const struct uuid* peer,
306 void** ctx_p) {
307 TrustyAcvpTool* tool = new TrustyAcvpTool(chan);
308 *ctx_p = reinterpret_cast<void*>(tool);
309 return NO_ERROR;
310 }
311
RewriteConfig(TrustyAcvpTool & tool,const std::vector<bssl::Span<const uint8_t>> & args)312 static bool RewriteConfig(TrustyAcvpTool& tool,
313 const std::vector<bssl::Span<const uint8_t>>& args) {
314 assert(args.size() == 1);
315 auto config = args[0];
316 const uint8_t* loc = config.cend() - 1;
317 for (; loc >= config.cbegin(); loc--) {
318 if (*loc == '}') {
319 break;
320 }
321 }
322 assert(loc >= config.cbegin() && loc < config.cend());
323 size_t pos = loc - config.cbegin() + 1;
324
325 std::unique_ptr<uint8_t[]> buf(
326 new (std::nothrow) uint8_t[pos + sizeof(kAdditionalConfig) - 1]);
327 if (!buf) {
328 TLOGE("Could not allocate buffer for config\n");
329 return false;
330 }
331
332 memcpy(buf.get(), config.cbegin(), pos);
333 memcpy(&buf[pos], kAdditionalConfig, sizeof(kAdditionalConfig) - 1);
334 return tool.WriteReply({bssl::Span<uint8_t>(
335 buf.get(), pos + sizeof(kAdditionalConfig) - 1)});
336 }
337
338 static constexpr struct {
339 char name[bssl::acvp::kMaxNameLength + 1];
340 uint8_t num_expected_args;
341 bool (*handler)(const bssl::Span<const uint8_t> args[],
342 bssl::acvp::ReplyCallback write_reply);
343 } kFunctions[] = {
344 {"KDF-counter", 5, KeymasterCKDF},
345 {"HKDF/SHA2-256", 4, KAS_HKDF<EVP_sha256>},
346 };
347
FindTrustyHandler(bssl::Span<const bssl::Span<const uint8_t>> args)348 static bssl::acvp::Handler FindTrustyHandler(
349 bssl::Span<const bssl::Span<const uint8_t>> args) {
350 const bssl::Span<const uint8_t> algorithm = args[0];
351 for (const auto& func : kFunctions) {
352 if (StringEq(algorithm, func.name)) {
353 if (args.size() - 1 != func.num_expected_args) {
354 TLOGE("\'%s\' operation received %zu arguments but expected %u.\n",
355 func.name, args.size() - 1, func.num_expected_args);
356 return nullptr;
357 }
358
359 return func.handler;
360 }
361 }
362
363 const std::string name(reinterpret_cast<const char*>(algorithm.data()),
364 algorithm.size());
365 TLOGE("Unknown operation: %s\n", name.c_str());
366 return nullptr;
367 }
368
AcvpOnMessage(const struct tipc_port * port,handle_t chan,void * ctx)369 static int AcvpOnMessage(const struct tipc_port* port,
370 handle_t chan,
371 void* ctx) {
372 assert(port == &kAcvpPort);
373 assert(ctx != nullptr);
374
375 TrustyAcvpTool* tool = reinterpret_cast<TrustyAcvpTool*>(ctx);
376
377 uint8_t message_buffer[ACVP_MAX_MESSAGE_LENGTH];
378 struct acvp_req* request = nullptr;
379 handle_t shared_mem = INVALID_IPC_HANDLE;
380 int rc = ParseAcvpMessage(chan, message_buffer, &request, &shared_mem);
381 if (rc != NO_ERROR) {
382 TLOGE("Could not parse ACVP message: %d\n", rc);
383 return rc;
384 }
385
386 if (request->num_args > bssl::acvp::kMaxArgs) {
387 TLOGE("Too many args in ACVP message: %d\n", request->num_args);
388 return ERR_INVALID_ARGS;
389 }
390
391 if (!tool->MapShm(shared_mem, request->buffer_size)) {
392 TLOGE("Can't map memory\n");
393 if (shared_mem != INVALID_IPC_HANDLE) {
394 close(shared_mem);
395 }
396 return ERR_NO_MEMORY;
397 } else {
398 bssl::Span<const uint8_t> args[bssl::acvp::kMaxArgs];
399 rc = NO_ERROR;
400
401 uint32_t cur_offset = 0;
402 for (uint32_t i = 0; i < request->num_args; ++i) {
403 uint32_t end;
404 if (__builtin_add_overflow(cur_offset, request->lengths[i], &end) ||
405 end > tool->arg_buffer_size()) {
406 rc = ERR_INVALID_ARGS;
407 goto cleanup;
408 }
409 args[i] = bssl::Span<const uint8_t>(tool->arg_buffer() + cur_offset,
410 request->lengths[i]);
411 cur_offset = end;
412 }
413
414 auto handler =
415 bssl::acvp::FindHandler(bssl::Span(args, request->num_args));
416 if (!handler) {
417 handler = FindTrustyHandler(bssl::Span(args, request->num_args));
418 }
419 if (!handler) {
420 const std::string name(
421 reinterpret_cast<const char*>(args[0].data()),
422 args[0].size());
423 TLOGE("Unknown operation: %s\n", name.c_str());
424 rc = ERR_NOT_FOUND;
425 goto cleanup;
426 }
427
428 // We need to intercept getConfig and append our own config to it.
429 bool is_config = StringEq(args[0], "getConfig");
430
431 bssl::acvp::ReplyCallback callback;
432 if (is_config) {
433 callback = [tool](auto spans) {
434 return RewriteConfig(*tool, spans);
435 };
436 } else {
437 callback = [tool](auto spans) { return tool->WriteReply(spans); };
438 }
439
440 if (!handler(&args[1], callback)) {
441 const std::string name(
442 reinterpret_cast<const char*>(args[0].data()),
443 args[0].size());
444 TLOGE("\'%s\' operation failed.\n", name.c_str());
445 rc = ERR_GENERIC;
446 goto cleanup;
447 }
448 }
449
450 cleanup:
451 tool->MessageCleanup();
452
453 return rc;
454 }
455
AcvpOnChannelCleanup(void * ctx)456 static void AcvpOnChannelCleanup(void* ctx) {
457 TrustyAcvpTool* tool = reinterpret_cast<TrustyAcvpTool*>(ctx);
458 delete tool;
459 }
460
461 static struct tipc_srv_ops kAcvpOps = {
462 .on_connect = AcvpOnConnect,
463 .on_message = AcvpOnMessage,
464 .on_channel_cleanup = AcvpOnChannelCleanup,
465 };
466
main(void)467 int main(void) {
468 struct tipc_hset* hset = tipc_hset_create();
469
470 if (IS_ERR(hset)) {
471 return PTR_ERR(hset);
472 }
473
474 int rc = tipc_add_service(hset, &kAcvpPort, 1, 1, &kAcvpOps);
475 if (rc < 0) {
476 return rc;
477 }
478
479 rc = tipc_run_event_loop(hset);
480 return rc;
481 }
482