/* * Copyright 2020, 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 #include #include #include #include #include #include #include #include #include using namespace secure_input; using teeui::AuthTokenKey; using teeui::ByteBufferProxy; using teeui::Hmac; using teeui::optional; using teeui::ResponseCode; using teeui::TestKeyBits; constexpr const auto kTestKey = AuthTokenKey::fill(static_cast(TestKeyBits::BYTE)); class SecureInputHMacer { public: static optional hmac256(const AuthTokenKey& key, std::initializer_list 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; } }; using HMac = teeui::HMac; Nonce generateNonce() { /* * Completely random nonce. * Running the secure input protocol from the HAL service is not secure * because we don't trust the non-secure world (i.e., HLOS/Android/Linux). So * using a constant "nonce" here does not weaken security. If this code runs * on a truly trustworthy source of input events this function needs to return * hight entropy nonces. * As of this writing the call to RAND_bytes is commented, because the * emulator this HAL service runs on does not have a good source of entropy. * It would block the call to RAND_bytes indefinitely. */ Nonce result{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}; // RAND_bytes(result.data(), result.size()); return result; } /** * This is an implementation of the SecureInput protocol in unserspace. This is * just an example and should not be used as is. The protocol implemented here * should be used by a trusted input device that can assert user events with * high assurance even if the HLOS kernel is compromised. A confirmationui HAL * that links directly against this implementation is not secure and shal not be * used on a production device. */ class NotSoSecureInput : public SecureInput { public: NotSoSecureInput(HsBeginCb hsBeginCb, HsFinalizeCb hsFinalizeCb, DeliverEventCb deliverEventCb, InputResultCb inputResultCb) : hsBeginCb_{hsBeginCb}, hsFinalizeCb_{hsFinalizeCb}, deliverEventCb_{deliverEventCb}, inputResultCb_{inputResultCb}, discardEvents_{true} {} operator bool() const override { return true; } void handleEvent(const EventDev& evdev) override { bool gotEvent; input_event evt; std::tie(gotEvent, evt) = evdev.readEvent(); while (gotEvent) { if (!(discardEvents_) && evt.type == EV_KEY && (evt.code == KEY_POWER || evt.code == KEY_VOLUMEDOWN || evt.code == KEY_VOLUMEUP) && evt.value == 1) { DTupKeyEvent event = DTupKeyEvent::RESERVED; // Translate the event code into DTupKeyEvent which the TA understands. switch (evt.code) { case KEY_POWER: event = DTupKeyEvent::PWR; break; case KEY_VOLUMEDOWN: event = DTupKeyEvent::VOL_DOWN; break; case KEY_VOLUMEUP: event = DTupKeyEvent::VOL_UP; break; } // The event goes into the HMAC in network byte order. uint32_t keyEventBE = htobe32(static_cast(event)); auto signature = HMac::hmac256(kTestKey, kConfirmationUIEventLabel, teeui::bytesCast(keyEventBE), nCi_); teeui::ResponseCode rc; InputResponse ir; auto response = std::tie(rc, ir); if (event != DTupKeyEvent::RESERVED) { response = deliverEventCb_(event, *signature); if (rc != ResponseCode::OK) { LOG(ERROR) << "DeliverInputEvent returned with " << uint32_t(rc); inputResultCb_(rc); } else { switch (ir) { case InputResponse::OK: inputResultCb_(rc); break; case InputResponse::PENDING_MORE: rc = performDTUPHandshake(); if (rc != ResponseCode::OK) { inputResultCb_(rc); } break; case InputResponse::TIMED_OUT: inputResultCb_(rc); break; } } } } std::tie(gotEvent, evt) = evdev.readEvent(); } } void start() override { auto rc = performDTUPHandshake(); if (rc != ResponseCode::OK) { inputResultCb_(rc); } discardEvents_ = false; }; private: teeui::ResponseCode performDTUPHandshake() { ResponseCode rc; LOG(INFO) << "Start handshake"; Nonce nCo; std::tie(rc, nCo) = hsBeginCb_(); if (rc != ResponseCode::OK) { LOG(ERROR) << "Failed to begin secure input handshake (" << uint32_t(rc) << ")"; return rc; } nCi_ = generateNonce(); rc = hsFinalizeCb_(*HMac::hmac256(kTestKey, kConfirmationUIHandshakeLabel, nCo, nCi_), nCi_); if (rc != ResponseCode::OK) { LOG(ERROR) << "Failed to finalize secure input handshake (" << uint32_t(rc) << ")"; return rc; } return ResponseCode::OK; } HsBeginCb hsBeginCb_; HsFinalizeCb hsFinalizeCb_; DeliverEventCb deliverEventCb_; InputResultCb inputResultCb_; std::atomic_bool discardEvents_; Nonce nCi_; }; namespace secure_input { std::shared_ptr createSecureInput(SecureInput::HsBeginCb hsBeginCb, SecureInput::HsFinalizeCb hsFinalizeCb, SecureInput::DeliverEventCb deliverEventCb, SecureInput::InputResultCb inputResultCb) { return std::make_shared(hsBeginCb, hsFinalizeCb, deliverEventCb, inputResultCb); } } // namespace secure_input