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 "secure_input_tracker.h"
18 #include "trusty_operation.h"
19 
20 #include <secure_input/secure_input_proto.h>
21 
22 #include <lib/rng/trusty_rng.h>
23 
24 #include <inttypes.h>
25 #include <stdio.h>
26 
27 #include <teeui/utils.h>
28 
29 #include <trusty_log.h>
30 
31 #include <uapi/err.h>
32 
33 #define TLOG_TAG "confirmationui"
34 
35 using namespace secure_input;
36 using teeui::Array;
37 using teeui::AuthTokenKey;
38 using teeui::bytesCast;
39 using teeui::HMac;
40 using teeui::optional;
41 using teeui::ResponseCode;
42 
mtsNow()43 inline auto mtsNow() {
44     return monotonic_time_stamper::now();
45 }
46 
getNonce()47 static optional<Nonce> getNonce() {
48     Nonce result;
49     if (trusty_rng_secure_rand(result.data(), result.size()) == NO_ERROR) {
50         return result;
51     } else {
52         return {};
53     }
54 }
55 
newSession()56 ResponseCode InputTracker::newSession() {
57     state_ = InputState::Fresh;
58     event_ = InputEvent::None;
59     auto now = mtsNow();
60     // Initialize all timestamps to something sane.
61     for (auto& t : timestamps_) {
62         t = now;
63     }
64     return ResponseCode::OK;
65 }
66 
67 // input Handshake
beginHandshake()68 std::tuple<ResponseCode, Nonce> InputTracker::beginHandshake() {
69     ResponseCode rc;
70     auto now = mtsNow();
71     if ((state_ == InputState::Fresh &&
72          (now - timestamps_[uint32_t(InputState::Fresh)]) >=
73                  kUserPreInputGracePeriodMillis) ||
74         state_ == InputState::InputDeliveredMorePending) {
75         auto nonce = getNonce();
76         if (nonce) {
77             input_nonce_ = *nonce;
78             TLOGD("%u", uint32_t(state_));
79             state_ = InputState::HandshakeOutstanding;
80             timestamps_[uint32_t(state_)] = now;
81             return {ResponseCode::OK, input_nonce_};
82         } else {
83             rc = ResponseCode::SystemError;
84         }
85     }
86     rc = ResponseCode::Unexpected;
87     state_ = InputState::None;
88     return {rc, {}};
89 }
90 
91 // input Handshake finalize
finalizeHandshake(const Nonce & nCi,const Signature & signature,const AuthTokenKey & key)92 ResponseCode InputTracker::finalizeHandshake(const Nonce& nCi,
93                                              const Signature& signature,
94                                              const AuthTokenKey& key) {
95     ResponseCode rc;
96     if (state_ == InputState::HandshakeOutstanding) {
97         using HMacer = HMac<TrustyOperation>;
98         auto hmac = HMacer::hmac256(key, kConfirmationUIHandshakeLabel,
99                                     input_nonce_, nCi);
100         if (hmac) {
101             if (*hmac == signature) {
102                 // we can forget the nCo and input_nonce now becomes nCi
103                 input_nonce_ = nCi;
104                 state_ = InputState::HandshakeComplete;
105                 timestamps_[uint32_t(state_)] = mtsNow();
106                 TLOGD("%u", uint32_t(state_));
107                 return ResponseCode::OK;
108             } else {
109                 rc = ResponseCode::Aborted;
110             }
111         } else {
112             rc = ResponseCode::SystemError;
113         }
114     } else {
115         rc = ResponseCode::Unexpected;
116     }
117     state_ = InputState::None;
118     return rc;
119 }
120 
121 // process input event
processInputEvent(DTupKeyEvent keyEvent,const Signature & signature,const AuthTokenKey & key)122 std::tuple<ResponseCode, InputResponse> InputTracker::processInputEvent(
123         DTupKeyEvent keyEvent,
124         const Signature& signature,
125         const AuthTokenKey& key) {
126     std::tuple<ResponseCode, InputResponse> result = {ResponseCode::OK,
127                                                       InputResponse::TIMED_OUT};
128     ResponseCode& rc = std::get<0>(result);
129     InputResponse& ir = std::get<1>(result);
130     using HMacer = HMac<TrustyOperation>;
131     auto now = mtsNow();
132 
133     if (state_ != InputState::HandshakeComplete) {
134         state_ = InputState::None;
135         rc = ResponseCode::Unexpected;
136         return result;
137     }
138     uint32_t keyEventBE = htobe32(static_cast<uint32_t>(keyEvent));
139     auto hmac = HMacer::hmac256(key, kConfirmationUIEventLabel,
140                                 bytesCast(keyEventBE), input_nonce_);
141     if (!hmac) {
142         state_ = InputState::None;
143         rc = ResponseCode::SystemError;
144         return result;
145     }
146 
147     if (!(*hmac == signature)) {
148         state_ = InputState::None;
149         rc = ResponseCode::Aborted;
150         TLOGE("signature on input event did not check out");
151         return result;
152     }
153 
154     switch (keyEvent) {
155     // fall through intended
156     case DTupKeyEvent::VOL_DOWN:
157     case DTupKeyEvent::VOL_UP:
158         event_ = InputEvent::UserCancel;
159         state_ = InputState::InputDeliveredFinal;
160         ir = InputResponse::OK;
161         break;
162     case DTupKeyEvent::PWR:
163         if (state_ == InputState::HandshakeComplete &&
164             now - timestamps_[uint32_t(
165                           InputState::InputDeliveredMorePending)] <=
166                     kUserDoupleClickTimeoutMillis) {
167             state_ = InputState::InputDeliveredFinal;
168             ir = InputResponse::OK;
169             event_ = InputEvent::UserConfirm;
170         } else {
171             state_ = InputState::InputDeliveredMorePending;
172             ir = InputResponse::PENDING_MORE;
173         }
174         break;
175     case DTupKeyEvent::RESERVED:
176     default:
177         TLOGW("got RESERVED event");
178         rc = ResponseCode::Aborted;
179         state_ = InputState::None;
180         return result;
181     }
182     timestamps_[uint32_t(state_)] = now;
183     TLOGD("%u", uint32_t(state_));
184     return result;
185 }
186 
fetchInputEvent()187 ResponseCode InputTracker::fetchInputEvent() {
188     if (state_ == InputState::InputDeliveredFinal) {
189         state_ = InputState::InputFetched;
190         if (event_ == InputEvent::UserConfirm)
191             return ResponseCode::OK;
192         else
193             return ResponseCode::Canceled;
194     } else {
195         TLOGD("%u", uint32_t(state_));
196         state_ = InputState::None;
197         return ResponseCode::Unexpected;
198     }
199 }
200 
reportVerifiedInput(InputEvent event)201 ResponseCode InputTracker::reportVerifiedInput(InputEvent event) {
202     auto now = mtsNow();
203     if (state_ == InputState::Fresh &&
204         (now - timestamps_[uint32_t(InputState::Fresh)]) >=
205                 kUserPreInputGracePeriodMillis) {
206         state_ = InputState::InputDeliveredFinal;
207         event_ = event;
208     }
209     return ResponseCode::OK;
210 }
211