blob: 5830f2d963e5b6b85e7a8118318a8b50b80db8af [file] [log] [blame]
/*
* Copyright 2019, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "trusty_operation.h"
#include <secure_input/secure_input_proto.h>
#include <teeui/msg_formatting.h>
#include <stdio.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <trusty_log.h>
#define TLOG_TAG "confirmationui"
using teeui::AuthTokenKey;
using teeui::ByteBufferProxy;
using teeui::Hmac;
using teeui::optional;
using teeui::Protocol;
using teeui::read;
using teeui::ReadStream;
using teeui::ResponseCode;
using teeui::write;
using teeui::WriteStream;
using teeui::Command;
using teeui::Message;
using teeui::TestModeCommands;
using secure_input::InputResponse;
optional<Hmac> TrustyOperation::hmac256(
const AuthTokenKey& key,
std::initializer_list<ByteBufferProxy> buffers) {
HMAC_CTX hmacCtx;
HMAC_CTX_init(&hmacCtx);
if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(),
nullptr)) {
return {};
}
for (auto& buffer : buffers) {
if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
return {};
}
}
Hmac result;
if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
return {};
}
return result;
}
int TrustyOperation::handleMsg(void* msg,
uint32_t msglen,
void* reponse,
uint32_t* responselen) {
ReadStream in(reinterpret_cast<uint8_t*>(msg), msglen);
WriteStream out(reinterpret_cast<uint8_t*>(reponse), *responselen);
TLOGI("proto: %u cmd: %u\n", reinterpret_cast<uint32_t*>(msg)[0],
reinterpret_cast<uint32_t*>(msg)[1]);
auto result = dispatchCommandMessage(in, out);
if (!result) {
/*
* We failed to serialize the response,
* Make an attempt to write an error code to the stream, indicating that
* serialization failed.
*/
TLOGE("response buffer to small\n");
result = write(Message<ResponseCode>(), out, ResponseCode::SystemError);
}
*responselen = result.pos() - reinterpret_cast<uint8_t*>(reponse);
return 0;
}
ResponseCode TrustyOperation::initHook() {
auto rc = gui_.start(getPrompt().data(), languageIdBuffer_,
invertedColorModeRequested_, maginifiedViewRequested_);
if (rc != ResponseCode::OK) {
TLOGE("GUI start returned: %d\n", rc);
} else {
input_tracker_.newSession();
}
TLOGI("initHook: %u\n", rc);
return rc;
}
void TrustyOperation::abortHook() {
input_tracker_.abort();
gui_.stop();
}
void TrustyOperation::finalizeHook() {
gui_.stop();
}
ResponseCode TrustyOperation::testCommandHook(TestModeCommands testCmd) {
switch (testCmd) {
case TestModeCommands::OK_EVENT:
return input_tracker_.reportVerifiedInput(
InputTracker::InputEvent::UserConfirm);
case TestModeCommands::CANCEL_EVENT:
return input_tracker_.reportVerifiedInput(
InputTracker::InputEvent::UserCancel);
default:
/* we don't want to veto any unknown test commands. */
return ResponseCode::OK;
}
}
WriteStream TrustyOperation::extendedProtocolHook(Protocol proto,
ReadStream in,
WriteStream out) {
using namespace secure_input;
if (proto != kSecureInputProto) {
/* this write ResponseCodeU::Unimplemented to the output stream */
return this->Operation::extendedProtocolHook(proto, in, out);
}
auto [in_cmd, cmd] = teeui::readCmd<SecureInputCommand>(in);
switch (cmd) {
case SecureInputCommand::InputHandshake: {
auto [rc, nonce] = input_tracker_.beginHandshake();
if (rc != ResponseCode::OK) {
TLOGE("beginHandshake failed\n");
abort();
} else if ((rc = gui_.showInstructions(true /*enable*/)) !=
ResponseCode::OK) {
TLOGE("showInstructions failed\n");
abort();
}
return write(InputHandshakeResponse(), out, rc, nonce);
}
case SecureInputCommand::FinalizeInputSession: {
auto [in_msg, nCi, signature] =
read(FinalizeInputSessionHandshake(), in_cmd);
auto rc = ResponseCode::Unexpected;
if (in_msg) {
rc = input_tracker_.finalizeHandshake(nCi, signature, *hmacKey());
} else {
TLOGE("Message Parse Error\n");
}
if (rc != ResponseCode::OK)
abort();
return write(FinalizeInputSessionHandshakeResponse(), out, rc);
}
case SecureInputCommand::DeliverInputEvent: {
auto [in_msg, event, signature] = read(DeliverInputEvent(), in_cmd);
InputResponse ir;
auto rc = ResponseCode::Unexpected;
if (in_msg) {
std::tie(rc, ir) = input_tracker_.processInputEvent(
event, signature, *hmacKey());
}
if (rc != ResponseCode::OK)
abort();
else if (ir == InputResponse::OK) {
switch (input_tracker_.fetchInputEvent()) {
case ResponseCode::OK:
signConfirmation(*hmacKey());
break;
case ResponseCode::Canceled:
userCancel();
break;
default:
break;
}
}
return write(DeliverInputEventResponse(), out, rc, ir);
}
case SecureInputCommand::Invalid:
default:
return write(Message<ResponseCode>(), out, ResponseCode::Unimplemented);
}
}