Handle auth token with same timestamp
We observed on some Pixel C that they sometimes generate auth token with
a stuck timestamp value. Since the timestamp value does not increase,
newer auth token is not considered "superceding" old auth tokens and keystore
end up retrieving older auth tokens which are then treated as expired due to
its time_received value being too old.
We workaround this issue by comparing both the timestamp (which is part of
auth token) and the time_received (which is a monotonic clock value at the
time auth token is sent to keystore). So a new auth token with stuck timestamp
value but newer time_received still supercedes older auth tokens.
This is actually sufficient to workaround the issue on Pixel C, since the stuck
timestamp value is returned by the secure RTC, whose value is also used by
keymaster TA to check key authorization. In other words, the auth token is
still good to authorize auth-bound keys, even with a stuck timestamp value.
This does mean that on the affected Pixel C, auth-bound keys are not enforced
at TrustZone leve, but merely a logical check in keystore daemon.
Bug: 65283496
Test: boot device, unlock successfully
Change-Id: I0b9d5463e94241bfaf552dcb31fea04ee966596c
diff --git a/keystore/auth_token_table.cpp b/keystore/auth_token_table.cpp
index 8b81e47..46b644d 100644
--- a/keystore/auth_token_table.cpp
+++ b/keystore/auth_token_table.cpp
@@ -244,7 +244,7 @@
return (token_->userId == entry.token_->userId &&
token_->authenticatorType == entry.token_->authenticatorType &&
token_->authenticatorId == entry.token_->authenticatorId &&
- timestamp_host_order() > entry.timestamp_host_order());
+ is_newer_than(&entry));
}
} // namespace keymaster
diff --git a/keystore/auth_token_table.h b/keystore/auth_token_table.h
index 422c710..0056b26 100644
--- a/keystore/auth_token_table.h
+++ b/keystore/auth_token_table.h
@@ -114,9 +114,15 @@
bool Supersedes(const Entry& entry) const;
bool SatisfiesAuth(const std::vector<uint64_t>& sids, HardwareAuthenticatorType auth_type);
- bool is_newer_than(const Entry* entry) {
+ bool is_newer_than(const Entry* entry) const {
if (!entry) return true;
- return timestamp_host_order() > entry->timestamp_host_order();
+ uint64_t ts = timestamp_host_order();
+ uint64_t other_ts = entry->timestamp_host_order();
+ // Normally comparing timestamp_host_order alone is sufficient, but here is an
+ // additional hack to compare time_received value for some devices where their auth
+ // tokens contain fixed timestamp (due to the a stuck secure RTC on them)
+ return (ts > other_ts) ||
+ ((ts == other_ts) && (time_received_ > entry->time_received_));
}
void mark_completed() { operation_completed_ = true; }