1 /*
2  * Copyright (C) 2022 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 <fcntl.h>
18 #include <inttypes.h>
19 #include <unistd.h>
20 #include <cstdio>
21 #include <android-base/unique_fd.h>
22 #include <debug.h>
23 #include "storage.h"
24 
25 namespace aidl::android::hardware::biometrics::fingerprint {
26 
27 namespace {
28 using ::android::base::unique_fd;
29 
30 constexpr uint32_t kFileSignature = 0x46507261;
31 
openFile(const int32_t sensorId,const int32_t userId,const bool output)32 unique_fd openFile(const int32_t sensorId, const int32_t userId, const bool output) {
33     char filename[64];
34     ::snprintf(filename, sizeof(filename), "/data/vendor_de/%d/fpdata/sensor%d.bin",
35                userId, sensorId);
36 
37     int fd;
38     if (output) {
39         fd = ::open(filename, O_CLOEXEC | O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
40     } else {
41         fd = ::open(filename, O_CLOEXEC | O_RDONLY);
42     }
43 
44     if (fd >= 0) {
45         return unique_fd(fd);
46     } else {
47         return FAILURE_V(unique_fd(), "open('%s', output=%d) failed with errno=%d",
48                          filename, output, errno);
49     }
50 }
51 
loadFile(const int fd)52 std::vector<uint8_t> loadFile(const int fd) {
53     constexpr size_t kChunkSize = 256;
54     std::vector<uint8_t> result;
55     size_t size = 0;
56 
57     while (true) {
58         result.resize(size + kChunkSize);
59         const int n = TEMP_FAILURE_RETRY(::read(fd, &result[size], kChunkSize));
60         if (n > 0) {
61             size += n;
62         } else if (n < 0) {
63             decltype(result) empty;
64             return FAILURE_V(empty, "error reading from a file, errno=%d", errno);
65         } else {
66             result.resize(size);
67             return result;
68         }
69     }
70 }
71 
saveFile(const int fd,const uint8_t * i,size_t size)72 bool saveFile(const int fd, const uint8_t* i, size_t size) {
73     while (size > 0) {
74         const int n = TEMP_FAILURE_RETRY(::write(fd, i, size));
75         if (n > 0) {
76             i += n;
77             size -= n;
78         } else if (n < 0) {
79             return FAILURE_V(false, "error writing to a file, errno=%d", errno);
80         } else {
81             return FAILURE_V(false, "`write` returned zero, size=%zu, errno=%d",
82                              size, errno);
83         }
84     }
85     return true;
86 }
87 
loadT(const uint8_t ** i,const uint8_t * end,T * x)88 template <class T> bool loadT(const uint8_t** i, const uint8_t* end, T* x) {
89     const uint8_t* p = *i;
90     if ((p + sizeof(*x)) <= end) {
91         memcpy(x, p, sizeof(*x));
92         *i = p + sizeof(*x);
93         return true;
94     } else {
95         return false;
96     }
97 }
98 
operator <<(std::vector<uint8_t> & v,const T & x)99 template <class T> std::vector<uint8_t>& operator<<(std::vector<uint8_t>& v, const T& x) {
100     const uint8_t* x8 = reinterpret_cast<const uint8_t*>(&x);
101     v.insert(v.end(), x8, x8 + sizeof(x));
102     return v;
103 }
104 
operator <<(std::vector<uint8_t> & v,const uint8_t x)105 std::vector<uint8_t>& operator<<(std::vector<uint8_t>& v, const uint8_t x) {
106     v.push_back(x);
107     return v;
108 }
109 
110 }  // namespace
111 
Storage(const int32_t sensorId,const int32_t userId)112 Storage::Storage(const int32_t sensorId, const int32_t userId)
113         : mSensorId(sensorId), mUserId(userId) {
114     unique_fd file(openFile(sensorId, mUserId, false));
115     if (!file.ok()) {
116         return;
117     }
118 
119     const std::vector<uint8_t> data = loadFile(file.get());
120     const uint8_t* i = data.data();
121     const uint8_t* const end = i + data.size();
122 
123     uint32_t signature;
124     if (!loadT(&i, end, &signature)) {
125         ALOGE("%s:%d", __func__, __LINE__);
126         return;
127     }
128     if (signature != kFileSignature) {
129         ALOGE("%s:%d", __func__, __LINE__);
130         return;
131     }
132     if (!loadT(&i, end, &mAuthId)) {
133         ALOGE("%s:%d", __func__, __LINE__);
134         return;
135     }
136     if (!loadT(&i, end, &mSecureUserId)) {
137         ALOGE("%s:%d", __func__, __LINE__);
138         return;
139     }
140     uint8_t nEnrollments;
141     if (!loadT(&i, end, &nEnrollments)) {
142         ALOGE("%s:%d", __func__, __LINE__);
143         return;
144     }
145     for (; nEnrollments > 0; --nEnrollments) {
146         int32_t enrollmentId;
147         if (loadT(&i, end, &enrollmentId)) {
148             mEnrollments.insert(enrollmentId);
149         } else {
150             ALOGE("%s:%d", __func__, __LINE__);
151             return;
152         }
153     }
154 }
155 
save() const156 void Storage::save() const {
157     unique_fd file(openFile(mSensorId, mUserId, true));
158     if (file.ok()) {
159         const std::vector<uint8_t> data = serialize();
160         saveFile(file.get(), data.data(), data.size());
161     }
162 }
163 
serialize() const164 std::vector<uint8_t> Storage::serialize() const {
165     std::vector<uint8_t> result;
166 
167     result << kFileSignature << mAuthId << mSecureUserId << uint8_t(mEnrollments.size());
168     for (const int32_t enrollmentId : mEnrollments) {
169         result << enrollmentId;
170     }
171 
172     return result;
173 }
174 
invalidateAuthenticatorId(const int64_t newAuthId)175 int64_t Storage::invalidateAuthenticatorId(const int64_t newAuthId) {
176     mAuthId = newAuthId;
177     save();
178     return newAuthId;
179 }
180 
enumerateEnrollments() const181 std::vector<int32_t> Storage::enumerateEnrollments() const {
182     return {mEnrollments.begin(), mEnrollments.end()};
183 }
184 
enroll(const int enrollmentId,const int64_t secureUserId,const int64_t newAuthId)185 bool Storage::enroll(const int enrollmentId,
186             const int64_t secureUserId,
187             const int64_t newAuthId) {
188     if (mEnrollments.insert(enrollmentId).second) {
189         mSecureUserId = secureUserId;
190         mAuthId = newAuthId;
191         save();
192         return true;
193     } else {
194         return false;
195     }
196 }
197 
removeEnrollments(const std::vector<int32_t> & enrollmentIds)198 void Storage::removeEnrollments(const std::vector<int32_t>& enrollmentIds) {
199     for (const int enrollmentId : enrollmentIds) {
200         mEnrollments.erase(enrollmentId);
201     }
202     save();
203 }
204 
205 std::tuple<Storage::AuthResult, int32_t, Storage::AuthToken>
authenticate(const int32_t enrollmentId)206 Storage::authenticate(const int32_t enrollmentId) {
207     const auto now = std::chrono::steady_clock::now();
208 
209     switch (mLockOut.state) {
210     default:
211     case LockOut::State::NO:
212         break;
213 
214     case LockOut::State::TIMED:
215     case LockOut::State::TIMED_LOCKED:
216         if (mLockOut.nextAttempt > now) {
217             mLockOut.state = LockOut::State::TIMED_LOCKED;
218             const int64_t inMs =
219                 std::chrono::duration_cast<
220                     std::chrono::milliseconds>(mLockOut.nextAttempt - now).count();
221             return {AuthResult::LOCKED_OUT_TIMED, static_cast<int>(inMs), {}};
222         }
223         break;
224 
225     case LockOut::State::PERMANENT:
226         return {AuthResult::LOCKED_OUT_PERMANENT, 0, {}};
227     }
228 
229     if (mEnrollments.count(enrollmentId) > 0) {
230         mLockOut.state = LockOut::State::NO;
231         AuthToken tok;
232         tok.userId = mSecureUserId;
233         tok.authenticatorId = mAuthId;
234         return {AuthResult::OK, 0, tok};
235     } else {
236         const int failedAttempts =
237             (mLockOut.state == LockOut::State::NO)
238                 ? 1 : ++mLockOut.failedAttempts;
239 
240         if (failedAttempts >= 10) {
241             mLockOut.state = LockOut::State::PERMANENT;
242             return {AuthResult::LOCKED_OUT_PERMANENT, 0, {}};
243         }
244 
245         mLockOut.state = LockOut::State::TIMED;
246         if (failedAttempts >= 5) {
247             mLockOut.nextAttempt = now + std::chrono::seconds(10);
248             mLockOut.expiration = now + std::chrono::minutes(10);
249         } else if (failedAttempts >= 3) {
250             mLockOut.nextAttempt = now + std::chrono::seconds(3);
251             mLockOut.expiration = now + std::chrono::minutes(1);
252         } else {
253             mLockOut.nextAttempt = now + std::chrono::milliseconds(500);
254             mLockOut.expiration = now + std::chrono::seconds(10);
255         }
256 
257         return {AuthResult::FAILED, 0, {}};
258     }
259 }
260 
resetLockout()261 void Storage::resetLockout() {
262     mLockOut.state = LockOut::State::NO;
263 }
264 
checkIfLockoutCleared()265 bool Storage::checkIfLockoutCleared() {
266     if (mLockOut.state != LockOut::State::TIMED_LOCKED) {
267         return false;
268     }
269 
270     const auto now = std::chrono::steady_clock::now();
271     if (now > mLockOut.expiration) {
272         mLockOut.state = LockOut::State::NO;
273         return true;
274     } else if (now > mLockOut.nextAttempt) {
275         mLockOut.state = LockOut::State::TIMED;
276         return true;
277     } else {
278         return false;
279     }
280 }
281 
282 } // namespace aidl::android::hardware::biometrics::fingerprint
283