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