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