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