1 /*
2  * Copyright 2019, 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 "trusty_operation.h"
18 #include <secure_input/secure_input_proto.h>
19 #include <teeui/msg_formatting.h>
20 
21 #include <stdio.h>
22 
23 #include <openssl/hmac.h>
24 #include <openssl/sha.h>
25 
26 #include <trusty_log.h>
27 
28 #define TLOG_TAG "confirmationui"
29 
30 using teeui::AuthTokenKey;
31 using teeui::ByteBufferProxy;
32 using teeui::Hmac;
33 using teeui::optional;
34 using teeui::Protocol;
35 using teeui::read;
36 using teeui::ReadStream;
37 using teeui::ResponseCode;
38 using teeui::write;
39 using teeui::WriteStream;
40 
41 using teeui::Command;
42 using teeui::Message;
43 using teeui::TestModeCommands;
44 
45 using secure_input::InputResponse;
46 
hmac256(const AuthTokenKey & key,std::initializer_list<ByteBufferProxy> buffers)47 optional<Hmac> TrustyOperation::hmac256(
48         const AuthTokenKey& key,
49         std::initializer_list<ByteBufferProxy> buffers) {
50     HMAC_CTX hmacCtx;
51     HMAC_CTX_init(&hmacCtx);
52     if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(),
53                       nullptr)) {
54         return {};
55     }
56     for (auto& buffer : buffers) {
57         if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
58             return {};
59         }
60     }
61     Hmac result;
62     if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
63         return {};
64     }
65     return result;
66 }
67 
handleMsg(void * msg,uint32_t msglen,void * reponse,uint32_t * responselen)68 int TrustyOperation::handleMsg(void* msg,
69                                uint32_t msglen,
70                                void* reponse,
71                                uint32_t* responselen) {
72     ReadStream in(reinterpret_cast<uint8_t*>(msg), msglen);
73     WriteStream out(reinterpret_cast<uint8_t*>(reponse), *responselen);
74 
75     TLOGI("proto: %u cmd: %u\n", reinterpret_cast<uint32_t*>(msg)[0],
76           reinterpret_cast<uint32_t*>(msg)[1]);
77 
78     auto result = dispatchCommandMessage(in, out);
79     if (!result) {
80         /*
81          * We failed to serialize the response,
82          * Make an attempt to write an error code to the stream, indicating that
83          * serialization failed.
84          */
85         TLOGE("response buffer to small\n");
86         result = write(Message<ResponseCode>(), out, ResponseCode::SystemError);
87     }
88     *responselen = result.pos() - reinterpret_cast<uint8_t*>(reponse);
89     return 0;
90 }
91 
initHook()92 ResponseCode TrustyOperation::initHook() {
93     auto rc = gui_.start(getPrompt().data(), languageIdBuffer_,
94                          invertedColorModeRequested_, maginifiedViewRequested_);
95     if (rc != ResponseCode::OK) {
96         TLOGE("GUI start returned: %d\n", rc);
97     } else {
98         input_tracker_.newSession();
99     }
100     TLOGI("initHook: %u\n", rc);
101     return rc;
102 }
103 
abortHook()104 void TrustyOperation::abortHook() {
105     input_tracker_.abort();
106     gui_.stop();
107 }
108 
finalizeHook()109 void TrustyOperation::finalizeHook() {
110     gui_.stop();
111 }
112 
testCommandHook(TestModeCommands testCmd)113 ResponseCode TrustyOperation::testCommandHook(TestModeCommands testCmd) {
114     switch (testCmd) {
115     case TestModeCommands::OK_EVENT:
116         return input_tracker_.reportVerifiedInput(
117                 InputTracker::InputEvent::UserConfirm);
118     case TestModeCommands::CANCEL_EVENT:
119         return input_tracker_.reportVerifiedInput(
120                 InputTracker::InputEvent::UserCancel);
121     default:
122         /* we don't want to veto any unknown test commands. */
123         return ResponseCode::OK;
124     }
125 }
126 
extendedProtocolHook(Protocol proto,ReadStream in,WriteStream out)127 WriteStream TrustyOperation::extendedProtocolHook(Protocol proto,
128                                                   ReadStream in,
129                                                   WriteStream out) {
130     using namespace secure_input;
131     if (proto != kSecureInputProto) {
132         /* this write ResponseCodeU::Unimplemented to the output stream */
133         return this->Operation::extendedProtocolHook(proto, in, out);
134     }
135     auto [in_cmd, cmd] = teeui::readCmd<SecureInputCommand>(in);
136     switch (cmd) {
137     case SecureInputCommand::InputHandshake: {
138         auto [rc, nonce] = input_tracker_.beginHandshake();
139         if (rc != ResponseCode::OK) {
140             TLOGE("beginHandshake failed\n");
141             abort();
142         } else if ((rc = gui_.showInstructions(true /*enable*/)) !=
143                    ResponseCode::OK) {
144             TLOGE("showInstructions failed\n");
145             abort();
146         }
147         return write(InputHandshakeResponse(), out, rc, nonce);
148     }
149     case SecureInputCommand::FinalizeInputSession: {
150         auto [in_msg, nCi, signature] =
151                 read(FinalizeInputSessionHandshake(), in_cmd);
152         auto rc = ResponseCode::Unexpected;
153         if (in_msg) {
154             rc = input_tracker_.finalizeHandshake(nCi, signature, *hmacKey());
155         } else {
156             TLOGE("Message Parse Error\n");
157         }
158         if (rc != ResponseCode::OK)
159             abort();
160         return write(FinalizeInputSessionHandshakeResponse(), out, rc);
161     }
162     case SecureInputCommand::DeliverInputEvent: {
163         auto [in_msg, event, signature] = read(DeliverInputEvent(), in_cmd);
164         InputResponse ir;
165         auto rc = ResponseCode::Unexpected;
166         if (in_msg) {
167             std::tie(rc, ir) = input_tracker_.processInputEvent(
168                     event, signature, *hmacKey());
169         }
170         if (rc != ResponseCode::OK)
171             abort();
172         else if (ir == InputResponse::OK) {
173             switch (input_tracker_.fetchInputEvent()) {
174             case ResponseCode::OK:
175                 signConfirmation(*hmacKey());
176                 break;
177             case ResponseCode::Canceled:
178                 userCancel();
179                 break;
180             default:
181                 break;
182             }
183         }
184         return write(DeliverInputEventResponse(), out, rc, ir);
185     }
186     case SecureInputCommand::Invalid:
187     default:
188         return write(Message<ResponseCode>(), out, ResponseCode::Unimplemented);
189     }
190 }
191