1 /*
2 * Copyright (C) 2023 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 #define LOG_TAG "keymint_1_test"
18 #include <cutils/log.h>
19
20 #include <iostream>
21 #include <optional>
22
23 #include "KeyMintAidlTestBase.h"
24
25 #include <aidl/android/hardware/gatekeeper/GatekeeperEnrollResponse.h>
26 #include <aidl/android/hardware/gatekeeper/GatekeeperVerifyResponse.h>
27 #include <aidl/android/hardware/gatekeeper/IGatekeeper.h>
28 #include <aidl/android/hardware/security/secureclock/ISecureClock.h>
29 #include <android-base/logging.h>
30 #include <android/binder_manager.h>
31
32 using aidl::android::hardware::gatekeeper::GatekeeperEnrollResponse;
33 using aidl::android::hardware::gatekeeper::GatekeeperVerifyResponse;
34 using aidl::android::hardware::gatekeeper::IGatekeeper;
35 using aidl::android::hardware::security::keymint::HardwareAuthToken;
36 using aidl::android::hardware::security::secureclock::ISecureClock;
37
38 #include <android/hardware/gatekeeper/1.0/IGatekeeper.h>
39 #include <android/hardware/gatekeeper/1.0/types.h>
40 #include <gatekeeper/password_handle.h> // for password_handle_t
41 #include <hardware/hw_auth_token.h>
42
43 using ::android::sp;
44 using IHidlGatekeeper = ::android::hardware::gatekeeper::V1_0::IGatekeeper;
45 using HidlGatekeeperResponse = ::android::hardware::gatekeeper::V1_0::GatekeeperResponse;
46 using HidlGatekeeperStatusCode = ::android::hardware::gatekeeper::V1_0::GatekeeperStatusCode;
47
48 namespace aidl::android::hardware::security::keymint::test {
49
50 class AuthTest : public KeyMintAidlTestBase {
51 public:
SetUp()52 void SetUp() {
53 KeyMintAidlTestBase::SetUp();
54
55 // Find the default Gatekeeper instance.
56 string gk_name = string(IGatekeeper::descriptor) + "/default";
57 if (AServiceManager_isDeclared(gk_name.c_str())) {
58 // Enroll a user with AIDL Gatekeeper.
59 ::ndk::SpAIBinder binder(AServiceManager_waitForService(gk_name.c_str()));
60 gk_ = IGatekeeper::fromBinder(binder);
61 } else {
62 // Prior to Android U, Gatekeeper was HIDL not AIDL and so may not be present.
63 // Try to enroll user with HIDL Gatekeeper instead.
64 string gk_name = "default";
65 hidl_gk_ = IHidlGatekeeper::getService(gk_name.c_str());
66 if (hidl_gk_ == nullptr) {
67 std::cerr << "No HIDL Gatekeeper instance for '" << gk_name << "' found.\n";
68 return;
69 }
70 std::cerr << "No AIDL Gatekeeper instance for '" << gk_name << "' found, using HIDL.\n";
71 }
72
73 // If the device needs timestamps, find the default ISecureClock instance.
74 if (timestamp_token_required_) {
75 string clock_name = string(ISecureClock::descriptor) + "/default";
76 if (AServiceManager_isDeclared(clock_name.c_str())) {
77 ::ndk::SpAIBinder binder(AServiceManager_waitForService(clock_name.c_str()));
78 clock_ = ISecureClock::fromBinder(binder);
79 } else {
80 std::cerr << "No ISecureClock instance for '" << clock_name << "' found.\n";
81 }
82 }
83
84 // Enroll a password for a user.
85 uid_ = 10001;
86 password_ = "correcthorsebatterystaple";
87 std::optional<GatekeeperEnrollResponse> rsp = doEnroll(password_);
88 ASSERT_TRUE(rsp.has_value());
89 sid_ = rsp->secureUserId;
90 handle_ = rsp->data;
91 }
92
TearDown()93 void TearDown() {
94 if (gk_ == nullptr) return;
95 gk_->deleteUser(uid_);
96 }
97
GatekeeperAvailable()98 bool GatekeeperAvailable() { return (gk_ != nullptr) || (hidl_gk_ != nullptr); }
99
doEnroll(const std::vector<uint8_t> & newPwd,const std::vector<uint8_t> & curHandle={},const std::vector<uint8_t> & curPwd={})100 std::optional<GatekeeperEnrollResponse> doEnroll(const std::vector<uint8_t>& newPwd,
101 const std::vector<uint8_t>& curHandle = {},
102 const std::vector<uint8_t>& curPwd = {}) {
103 if (gk_ != nullptr) {
104 while (true) {
105 GatekeeperEnrollResponse rsp;
106 Status status = gk_->enroll(uid_, curHandle, curPwd, newPwd, &rsp);
107 if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
108 status.getServiceSpecificError() == IGatekeeper::ERROR_RETRY_TIMEOUT) {
109 sleep(1);
110 continue;
111 }
112 if (status.isOk()) {
113 return std::move(rsp);
114 } else {
115 GTEST_LOG_(ERROR) << "doEnroll(AIDL) failed: " << status;
116 return std::nullopt;
117 }
118 }
119 } else if (hidl_gk_ != nullptr) {
120 while (true) {
121 HidlGatekeeperResponse rsp;
122 auto status = hidl_gk_->enroll(
123 uid_, curHandle, curPwd, newPwd,
__anon6c3d41050102(const HidlGatekeeperResponse& cbRsp) 124 [&rsp](const HidlGatekeeperResponse& cbRsp) { rsp = cbRsp; });
125 if (!status.isOk()) {
126 GTEST_LOG_(ERROR) << "doEnroll(HIDL) failed";
127 return std::nullopt;
128 }
129 if (rsp.code == HidlGatekeeperStatusCode::ERROR_RETRY_TIMEOUT) {
130 sleep(1);
131 continue;
132 }
133 if (rsp.code != HidlGatekeeperStatusCode::STATUS_OK) {
134 GTEST_LOG_(ERROR) << "doEnroll(HIDL) failed with " << int(rsp.code);
135 return std::nullopt;
136 }
137 // "Parse" the returned data to get at the secure user ID.
138 if (rsp.data.size() != sizeof(::gatekeeper::password_handle_t)) {
139 GTEST_LOG_(ERROR)
140 << "HAL returned password handle of invalid length " << rsp.data.size();
141 return std::nullopt;
142 }
143 const ::gatekeeper::password_handle_t* handle =
144 reinterpret_cast<const ::gatekeeper::password_handle_t*>(rsp.data.data());
145
146 // Translate HIDL response to look like an AIDL response.
147 GatekeeperEnrollResponse aidl_rsp;
148 aidl_rsp.statusCode = IGatekeeper::STATUS_OK;
149 aidl_rsp.data = rsp.data;
150 aidl_rsp.secureUserId = handle->user_id;
151 return aidl_rsp;
152 }
153 } else {
154 return std::nullopt;
155 }
156 }
157
doEnroll(const string & newPwd,const std::vector<uint8_t> & curHandle={},const string & curPwd={})158 std::optional<GatekeeperEnrollResponse> doEnroll(const string& newPwd,
159 const std::vector<uint8_t>& curHandle = {},
160 const string& curPwd = {}) {
161 return doEnroll(std::vector<uint8_t>(newPwd.begin(), newPwd.end()), curHandle,
162 std::vector<uint8_t>(curPwd.begin(), curPwd.end()));
163 }
164
doVerify(uint64_t challenge,const std::vector<uint8_t> & handle,const std::vector<uint8_t> & pwd)165 std::optional<HardwareAuthToken> doVerify(uint64_t challenge,
166 const std::vector<uint8_t>& handle,
167 const std::vector<uint8_t>& pwd) {
168 if (gk_ != nullptr) {
169 while (true) {
170 GatekeeperVerifyResponse rsp;
171 Status status = gk_->verify(uid_, challenge, handle, pwd, &rsp);
172 if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
173 status.getServiceSpecificError() == IGatekeeper::ERROR_RETRY_TIMEOUT) {
174 sleep(1);
175 continue;
176 }
177 if (status.isOk()) {
178 return rsp.hardwareAuthToken;
179 } else {
180 GTEST_LOG_(ERROR) << "doVerify(AIDL) failed: " << status;
181 return std::nullopt;
182 }
183 }
184 } else if (hidl_gk_ != nullptr) {
185 while (true) {
186 HidlGatekeeperResponse rsp;
187 auto status = hidl_gk_->verify(
188 uid_, challenge, handle, pwd,
189 [&rsp](const HidlGatekeeperResponse& cbRsp) { rsp = cbRsp; });
190 if (!status.isOk()) {
191 GTEST_LOG_(ERROR) << "doVerify(HIDL) failed";
192 return std::nullopt;
193 }
194 if (rsp.code == HidlGatekeeperStatusCode::ERROR_RETRY_TIMEOUT) {
195 sleep(1);
196 continue;
197 }
198 if (rsp.code != HidlGatekeeperStatusCode::STATUS_OK) {
199 GTEST_LOG_(ERROR) << "doVerify(HIDL) failed with " << int(rsp.code);
200 return std::nullopt;
201 }
202 // "Parse" the returned data to get auth token contents.
203 if (rsp.data.size() != sizeof(hw_auth_token_t)) {
204 GTEST_LOG_(ERROR) << "Incorrect size of AuthToken payload.";
205 return std::nullopt;
206 }
207 const hw_auth_token_t* hwAuthToken =
208 reinterpret_cast<const hw_auth_token_t*>(rsp.data.data());
209 HardwareAuthToken authToken;
210 authToken.timestamp.milliSeconds = betoh64(hwAuthToken->timestamp);
211 authToken.challenge = hwAuthToken->challenge;
212 authToken.userId = hwAuthToken->user_id;
213 authToken.authenticatorId = hwAuthToken->authenticator_id;
214 authToken.authenticatorType = static_cast<HardwareAuthenticatorType>(
215 betoh32(hwAuthToken->authenticator_type));
216 authToken.mac.assign(&hwAuthToken->hmac[0], &hwAuthToken->hmac[32]);
217 return authToken;
218 }
219 } else {
220 return std::nullopt;
221 }
222 }
doVerify(uint64_t challenge,const std::vector<uint8_t> & handle,const string & pwd)223 std::optional<HardwareAuthToken> doVerify(uint64_t challenge,
224 const std::vector<uint8_t>& handle,
225 const string& pwd) {
226 return doVerify(challenge, handle, std::vector<uint8_t>(pwd.begin(), pwd.end()));
227 }
228
229 // Variants of the base class methods but with authentication information included.
ProcessMessage(const vector<uint8_t> & key_blob,KeyPurpose operation,const string & message,const AuthorizationSet & in_params,AuthorizationSet * out_params,const HardwareAuthToken & hat)230 string ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
231 const string& message, const AuthorizationSet& in_params,
232 AuthorizationSet* out_params, const HardwareAuthToken& hat) {
233 AuthorizationSet begin_out_params;
234 ErrorCode result = Begin(operation, key_blob, in_params, out_params, hat);
235 EXPECT_EQ(ErrorCode::OK, result);
236 if (result != ErrorCode::OK) {
237 return "";
238 }
239
240 std::optional<secureclock::TimeStampToken> time_token = std::nullopt;
241 if (timestamp_token_required_ && clock_ != nullptr) {
242 // Ask a secure clock instance for a timestamp, including the per-op challenge.
243 secureclock::TimeStampToken token;
244 EXPECT_EQ(ErrorCode::OK,
245 GetReturnErrorCode(clock_->generateTimeStamp(challenge_, &token)));
246 time_token = token;
247 }
248
249 string output;
250 EXPECT_EQ(ErrorCode::OK, Finish(message, {} /* signature */, &output, hat, time_token));
251 return output;
252 }
253
EncryptMessage(const vector<uint8_t> & key_blob,const string & message,const AuthorizationSet & in_params,AuthorizationSet * out_params,const HardwareAuthToken & hat)254 string EncryptMessage(const vector<uint8_t>& key_blob, const string& message,
255 const AuthorizationSet& in_params, AuthorizationSet* out_params,
256 const HardwareAuthToken& hat) {
257 SCOPED_TRACE("EncryptMessage");
258 return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params, hat);
259 }
260
DecryptMessage(const vector<uint8_t> & key_blob,const string & ciphertext,const AuthorizationSet & params,const HardwareAuthToken & hat)261 string DecryptMessage(const vector<uint8_t>& key_blob, const string& ciphertext,
262 const AuthorizationSet& params, const HardwareAuthToken& hat) {
263 SCOPED_TRACE("DecryptMessage");
264 AuthorizationSet out_params;
265 string plaintext =
266 ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params, hat);
267 EXPECT_TRUE(out_params.empty());
268 return plaintext;
269 }
270
271 protected:
272 std::shared_ptr<IGatekeeper> gk_;
273 sp<IHidlGatekeeper> hidl_gk_;
274 std::shared_ptr<ISecureClock> clock_;
275 string password_;
276 uint32_t uid_;
277 int64_t sid_;
278 std::vector<uint8_t> handle_;
279 };
280
281 // Test use of a key that requires user-authentication within recent history.
TEST_P(AuthTest,TimeoutAuthentication)282 TEST_P(AuthTest, TimeoutAuthentication) {
283 if (!GatekeeperAvailable()) {
284 GTEST_SKIP() << "No Gatekeeper available";
285 }
286 if (timestamp_token_required_ && clock_ == nullptr) {
287 GTEST_SKIP() << "Device requires timestamps and no ISecureClock available";
288 }
289
290 // Create an AES key that requires authentication within the last 3 seconds.
291 const uint32_t timeout_secs = 3;
292 auto builder = AuthorizationSetBuilder()
293 .AesEncryptionKey(256)
294 .BlockMode(BlockMode::ECB)
295 .Padding(PaddingMode::PKCS7)
296 .Authorization(TAG_USER_SECURE_ID, sid_)
297 .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD)
298 .Authorization(TAG_AUTH_TIMEOUT, timeout_secs);
299 vector<uint8_t> keyblob;
300 vector<KeyCharacteristics> key_characteristics;
301 vector<Certificate> cert_chain;
302 ASSERT_EQ(ErrorCode::OK,
303 GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
304
305 // Attempt to use the AES key without authentication.
306 const string message = "Hello World!";
307 AuthorizationSet out_params;
308 auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
309 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
310 Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
311
312 // Verify to get a HAT, arbitrary challenge.
313 const uint64_t challenge = 42;
314 const std::optional<HardwareAuthToken> hat = doVerify(challenge, handle_, password_);
315 ASSERT_TRUE(hat.has_value());
316 EXPECT_EQ(hat->userId, sid_);
317
318 // Adding the auth token makes it possible to use the AES key.
319 const string ciphertext = EncryptMessage(keyblob, message, params, &out_params, hat.value());
320 const string plaintext = DecryptMessage(keyblob, ciphertext, params, hat.value());
321 EXPECT_EQ(message, plaintext);
322
323 // Altering a single bit in the MAC means no auth.
324 HardwareAuthToken dodgy_hat = hat.value();
325 ASSERT_GT(dodgy_hat.mac.size(), 0);
326 dodgy_hat.mac[0] ^= 0x01;
327 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
328 Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, dodgy_hat));
329
330 // Wait for long enough that the hardware auth token expires.
331 sleep(timeout_secs + 1);
332
333 auto begin_result = Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat);
334 if (begin_result == ErrorCode::OK) {
335 // If begin() succeeds despite the out-of-date HAT, that must mean that the KeyMint
336 // device doesn't have its own clock. In that case, it only detects timeout via a
337 // timestamp token provided on update()/finish()
338 ASSERT_TRUE(timestamp_token_required_);
339
340 secureclock::TimeStampToken time_token;
341 EXPECT_EQ(ErrorCode::OK,
342 GetReturnErrorCode(clock_->generateTimeStamp(challenge_, &time_token)));
343
344 string output;
345 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
346 Finish(message, {} /* signature */, &output, hat, time_token));
347 } else {
348 // The KeyMint implementation may have its own clock that can immediately detect timeout.
349 ASSERT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED, begin_result);
350 }
351 }
352
353 // Test use of a key that requires an auth token for each action on the operation, with
354 // a per-operation challenge value included.
TEST_P(AuthTest,AuthPerOperation)355 TEST_P(AuthTest, AuthPerOperation) {
356 if (!GatekeeperAvailable()) {
357 GTEST_SKIP() << "No Gatekeeper available";
358 }
359
360 // Create an AES key that requires authentication per-action.
361 auto builder = AuthorizationSetBuilder()
362 .AesEncryptionKey(256)
363 .BlockMode(BlockMode::ECB)
364 .Padding(PaddingMode::PKCS7)
365 .Authorization(TAG_USER_SECURE_ID, sid_)
366 .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD);
367 vector<uint8_t> keyblob;
368 vector<KeyCharacteristics> key_characteristics;
369 vector<Certificate> cert_chain;
370 ASSERT_EQ(ErrorCode::OK,
371 GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
372
373 // Attempt to use the AES key without authentication fails after begin.
374 const string message = "Hello World!";
375 AuthorizationSet out_params;
376 auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
377 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
378 string output;
379 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED, Finish(message, {} /* signature */, &output));
380
381 // Verify to get a HAT, but with an arbitrary challenge.
382 const uint64_t unrelated_challenge = 42;
383 const std::optional<HardwareAuthToken> unrelated_hat =
384 doVerify(unrelated_challenge, handle_, password_);
385 ASSERT_TRUE(unrelated_hat.has_value());
386 EXPECT_EQ(unrelated_hat->userId, sid_);
387
388 // Attempt to use the AES key with an unrelated authentication fails after begin.
389 EXPECT_EQ(ErrorCode::OK,
390 Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, unrelated_hat.value()));
391 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
392 Finish(message, {} /* signature */, &output, unrelated_hat.value()));
393
394 // Now get a HAT with the challenge from an in-progress operation.
395 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
396 const std::optional<HardwareAuthToken> hat = doVerify(challenge_, handle_, password_);
397 ASSERT_TRUE(hat.has_value());
398 EXPECT_EQ(hat->userId, sid_);
399 string ciphertext;
400 EXPECT_EQ(ErrorCode::OK, Finish(message, {} /* signature */, &ciphertext, hat.value()));
401
402 // Altering a single bit in the MAC means no auth.
403 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
404 std::optional<HardwareAuthToken> dodgy_hat = doVerify(challenge_, handle_, password_);
405 ASSERT_TRUE(dodgy_hat.has_value());
406 EXPECT_EQ(dodgy_hat->userId, sid_);
407 ASSERT_GT(dodgy_hat->mac.size(), 0);
408 dodgy_hat->mac[0] ^= 0x01;
409 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
410 Finish(message, {} /* signature */, &ciphertext, hat.value()));
411 }
412
413 INSTANTIATE_KEYMINT_AIDL_TEST(AuthTest);
414
415 } // namespace aidl::android::hardware::security::keymint::test
416