• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 here
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