1 /*
2 * Copyright 2020, 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 <android-base/logging.h>
18 #include <endian.h>
19 #include <memory>
20 #include <openssl/hmac.h>
21 #include <openssl/rand.h>
22 #include <openssl/sha.h>
23 #include <secure_input/evdev.h>
24 #include <secure_input/secure_input_device.h>
25 #include <teeui/utils.h>
26
27 #include <initializer_list>
28
29 using namespace secure_input;
30
31 using teeui::AuthTokenKey;
32 using teeui::ByteBufferProxy;
33 using teeui::Hmac;
34 using teeui::optional;
35 using teeui::ResponseCode;
36 using teeui::TestKeyBits;
37
38 constexpr const auto kTestKey = AuthTokenKey::fill(static_cast<uint8_t>(TestKeyBits::BYTE));
39
40 class SecureInputHMacer {
41 public:
hmac256(const AuthTokenKey & key,std::initializer_list<ByteBufferProxy> buffers)42 static optional<Hmac> hmac256(const AuthTokenKey& key,
43 std::initializer_list<ByteBufferProxy> buffers) {
44 HMAC_CTX hmacCtx;
45 HMAC_CTX_init(&hmacCtx);
46 if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(), nullptr)) {
47 return {};
48 }
49 for (auto& buffer : buffers) {
50 if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
51 return {};
52 }
53 }
54 Hmac result;
55 if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
56 return {};
57 }
58 return result;
59 }
60 };
61
62 using HMac = teeui::HMac<SecureInputHMacer>;
63
generateNonce()64 Nonce generateNonce() {
65 /*
66 * Completely random nonce.
67 * Running the secure input protocol from the HAL service is not secure
68 * because we don't trust the non-secure world (i.e., HLOS/Android/Linux). So
69 * using a constant "nonce" here does not weaken security. If this code runs
70 * on a truly trustworthy source of input events this function needs to return
71 * hight entropy nonces.
72 * As of this writing the call to RAND_bytes is commented, because the
73 * emulator this HAL service runs on does not have a good source of entropy.
74 * It would block the call to RAND_bytes indefinitely.
75 */
76 Nonce result{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
77 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
78 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04};
79 // RAND_bytes(result.data(), result.size());
80 return result;
81 }
82
83 /**
84 * This is an implementation of the SecureInput protocol in unserspace. This is
85 * just an example and should not be used as is. The protocol implemented her
86 * should be used by a trusted input device that can assert user events with
87 * high assurance even if the HLOS kernel is compromised. A confirmationui HAL
88 * that links directly against this implementation is not secure and shal not be
89 * used on a production device.
90 */
91 class NotSoSecureInput : public SecureInput {
92 public:
NotSoSecureInput(HsBeginCb hsBeginCb,HsFinalizeCb hsFinalizeCb,DeliverEventCb deliverEventCb,InputResultCb inputResultCb)93 NotSoSecureInput(HsBeginCb hsBeginCb, HsFinalizeCb hsFinalizeCb, DeliverEventCb deliverEventCb,
94 InputResultCb inputResultCb)
95 : hsBeginCb_{hsBeginCb}, hsFinalizeCb_{hsFinalizeCb}, deliverEventCb_{deliverEventCb},
96 inputResultCb_{inputResultCb}, discardEvents_{true} {}
97
operator bool() const98 operator bool() const override { return true; }
99
handleEvent(const EventDev & evdev)100 void handleEvent(const EventDev& evdev) override {
101 bool gotEvent;
102 input_event evt;
103 std::tie(gotEvent, evt) = evdev.readEvent();
104 while (gotEvent) {
105 if (!(discardEvents_) && evt.type == EV_KEY &&
106 (evt.code == KEY_POWER || evt.code == KEY_VOLUMEDOWN || evt.code == KEY_VOLUMEUP) &&
107 evt.value == 1) {
108 DTupKeyEvent event = DTupKeyEvent::RESERVED;
109
110 // Translate the event code into DTupKeyEvent which the TA understands.
111 switch (evt.code) {
112 case KEY_POWER:
113 event = DTupKeyEvent::PWR;
114 break;
115 case KEY_VOLUMEDOWN:
116 event = DTupKeyEvent::VOL_DOWN;
117 break;
118 case KEY_VOLUMEUP:
119 event = DTupKeyEvent::VOL_UP;
120 break;
121 }
122
123 // The event goes into the HMAC in network byte order.
124 uint32_t keyEventBE = htobe32(static_cast<uint32_t>(event));
125 auto signature = HMac::hmac256(kTestKey, kConfirmationUIEventLabel,
126 teeui::bytesCast(keyEventBE), nCi_);
127
128 teeui::ResponseCode rc;
129 InputResponse ir;
130 auto response = std::tie(rc, ir);
131 if (event != DTupKeyEvent::RESERVED) {
132 response = deliverEventCb_(event, *signature);
133 if (rc != ResponseCode::OK) {
134 LOG(ERROR) << "DeliverInputEvent returned with " << uint32_t(rc);
135 inputResultCb_(rc);
136 } else {
137 switch (ir) {
138 case InputResponse::OK:
139 inputResultCb_(rc);
140 break;
141 case InputResponse::PENDING_MORE:
142 rc = performDTUPHandshake();
143 if (rc != ResponseCode::OK) {
144 inputResultCb_(rc);
145 }
146 break;
147 case InputResponse::TIMED_OUT:
148 inputResultCb_(rc);
149 break;
150 }
151 }
152 }
153 }
154 std::tie(gotEvent, evt) = evdev.readEvent();
155 }
156 }
157
start()158 void start() override {
159 auto rc = performDTUPHandshake();
160 if (rc != ResponseCode::OK) {
161 inputResultCb_(rc);
162 }
163 discardEvents_ = false;
164 };
165
166 private:
performDTUPHandshake()167 teeui::ResponseCode performDTUPHandshake() {
168 ResponseCode rc;
169 LOG(INFO) << "Start handshake";
170 Nonce nCo;
171 std::tie(rc, nCo) = hsBeginCb_();
172 if (rc != ResponseCode::OK) {
173 LOG(ERROR) << "Failed to begin secure input handshake (" << uint32_t(rc) << ")";
174 return rc;
175 }
176
177 nCi_ = generateNonce();
178 rc =
179 hsFinalizeCb_(*HMac::hmac256(kTestKey, kConfirmationUIHandshakeLabel, nCo, nCi_), nCi_);
180
181 if (rc != ResponseCode::OK) {
182 LOG(ERROR) << "Failed to finalize secure input handshake (" << uint32_t(rc) << ")";
183 return rc;
184 }
185 return ResponseCode::OK;
186 }
187
188 HsBeginCb hsBeginCb_;
189 HsFinalizeCb hsFinalizeCb_;
190 DeliverEventCb deliverEventCb_;
191 InputResultCb inputResultCb_;
192
193 std::atomic_bool discardEvents_;
194 Nonce nCi_;
195 };
196
197 namespace secure_input {
198
createSecureInput(SecureInput::HsBeginCb hsBeginCb,SecureInput::HsFinalizeCb hsFinalizeCb,SecureInput::DeliverEventCb deliverEventCb,SecureInput::InputResultCb inputResultCb)199 std::shared_ptr<SecureInput> createSecureInput(SecureInput::HsBeginCb hsBeginCb,
200 SecureInput::HsFinalizeCb hsFinalizeCb,
201 SecureInput::DeliverEventCb deliverEventCb,
202 SecureInput::InputResultCb inputResultCb) {
203 return std::make_shared<NotSoSecureInput>(hsBeginCb, hsFinalizeCb, deliverEventCb,
204 inputResultCb);
205 }
206
207 } // namespace secure_input
208