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