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