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 if (alt_uid_ != 0) {
97 gk_->deleteUser(alt_uid_);
98 }
99 }
100
GatekeeperAvailable()101 bool GatekeeperAvailable() { return (gk_ != nullptr) || (hidl_gk_ != nullptr); }
102
doEnroll(uint32_t uid,const std::vector<uint8_t> & newPwd,const std::vector<uint8_t> & curHandle={},const std::vector<uint8_t> & curPwd={})103 std::optional<GatekeeperEnrollResponse> doEnroll(uint32_t uid,
104 const std::vector<uint8_t>& newPwd,
105 const std::vector<uint8_t>& curHandle = {},
106 const std::vector<uint8_t>& curPwd = {}) {
107 if (gk_ != nullptr) {
108 while (true) {
109 GatekeeperEnrollResponse rsp;
110 Status status = gk_->enroll(uid, curHandle, curPwd, newPwd, &rsp);
111 if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
112 status.getServiceSpecificError() == IGatekeeper::ERROR_RETRY_TIMEOUT) {
113 sleep(1);
114 continue;
115 }
116 if (status.isOk()) {
117 return std::move(rsp);
118 } else {
119 GTEST_LOG_(ERROR) << "doEnroll(AIDL) failed: " << status;
120 return std::nullopt;
121 }
122 }
123 } else if (hidl_gk_ != nullptr) {
124 while (true) {
125 HidlGatekeeperResponse rsp;
126 auto status = hidl_gk_->enroll(
127 uid, curHandle, curPwd, newPwd,
__anonf6a0e8560102(const HidlGatekeeperResponse& cbRsp) 128 [&rsp](const HidlGatekeeperResponse& cbRsp) { rsp = cbRsp; });
129 if (!status.isOk()) {
130 GTEST_LOG_(ERROR) << "doEnroll(HIDL) failed";
131 return std::nullopt;
132 }
133 if (rsp.code == HidlGatekeeperStatusCode::ERROR_RETRY_TIMEOUT) {
134 sleep(1);
135 continue;
136 }
137 if (rsp.code != HidlGatekeeperStatusCode::STATUS_OK) {
138 GTEST_LOG_(ERROR) << "doEnroll(HIDL) failed with " << int(rsp.code);
139 return std::nullopt;
140 }
141 // "Parse" the returned data to get at the secure user ID.
142 if (rsp.data.size() != sizeof(::gatekeeper::password_handle_t)) {
143 GTEST_LOG_(ERROR)
144 << "HAL returned password handle of invalid length " << rsp.data.size();
145 return std::nullopt;
146 }
147 const ::gatekeeper::password_handle_t* handle =
148 reinterpret_cast<const ::gatekeeper::password_handle_t*>(rsp.data.data());
149
150 // Translate HIDL response to look like an AIDL response.
151 GatekeeperEnrollResponse aidl_rsp;
152 aidl_rsp.statusCode = IGatekeeper::STATUS_OK;
153 aidl_rsp.data = rsp.data;
154 aidl_rsp.secureUserId = handle->user_id;
155 return aidl_rsp;
156 }
157 } else {
158 return std::nullopt;
159 }
160 }
161
doEnroll(uint32_t uid,const string & newPwd,const std::vector<uint8_t> & curHandle={},const string & curPwd={})162 std::optional<GatekeeperEnrollResponse> doEnroll(uint32_t uid, const string& newPwd,
163 const std::vector<uint8_t>& curHandle = {},
164 const string& curPwd = {}) {
165 return doEnroll(uid, std::vector<uint8_t>(newPwd.begin(), newPwd.end()), curHandle,
166 std::vector<uint8_t>(curPwd.begin(), curPwd.end()));
167 }
doEnroll(const string & newPwd)168 std::optional<GatekeeperEnrollResponse> doEnroll(const string& newPwd) {
169 return doEnroll(uid_, newPwd);
170 }
171
doVerify(uint32_t uid,uint64_t challenge,const std::vector<uint8_t> & handle,const std::vector<uint8_t> & pwd)172 std::optional<HardwareAuthToken> doVerify(uint32_t uid, uint64_t challenge,
173 const std::vector<uint8_t>& handle,
174 const std::vector<uint8_t>& pwd) {
175 if (gk_ != nullptr) {
176 while (true) {
177 GatekeeperVerifyResponse rsp;
178 Status status = gk_->verify(uid, challenge, handle, pwd, &rsp);
179 if (!status.isOk() && status.getExceptionCode() == EX_SERVICE_SPECIFIC &&
180 status.getServiceSpecificError() == IGatekeeper::ERROR_RETRY_TIMEOUT) {
181 sleep(1);
182 continue;
183 }
184 if (status.isOk()) {
185 return rsp.hardwareAuthToken;
186 } else {
187 GTEST_LOG_(ERROR) << "doVerify(AIDL) failed: " << status;
188 return std::nullopt;
189 }
190 }
191 } else if (hidl_gk_ != nullptr) {
192 while (true) {
193 HidlGatekeeperResponse rsp;
194 auto status = hidl_gk_->verify(
195 uid, challenge, handle, pwd,
196 [&rsp](const HidlGatekeeperResponse& cbRsp) { rsp = cbRsp; });
197 if (!status.isOk()) {
198 GTEST_LOG_(ERROR) << "doVerify(HIDL) failed";
199 return std::nullopt;
200 }
201 if (rsp.code == HidlGatekeeperStatusCode::ERROR_RETRY_TIMEOUT) {
202 sleep(1);
203 continue;
204 }
205 if (rsp.code != HidlGatekeeperStatusCode::STATUS_OK) {
206 GTEST_LOG_(ERROR) << "doVerify(HIDL) failed with " << int(rsp.code);
207 return std::nullopt;
208 }
209 // "Parse" the returned data to get auth token contents.
210 if (rsp.data.size() != sizeof(hw_auth_token_t)) {
211 GTEST_LOG_(ERROR) << "Incorrect size of AuthToken payload.";
212 return std::nullopt;
213 }
214 const hw_auth_token_t* hwAuthToken =
215 reinterpret_cast<const hw_auth_token_t*>(rsp.data.data());
216 HardwareAuthToken authToken;
217 authToken.timestamp.milliSeconds = betoh64(hwAuthToken->timestamp);
218 authToken.challenge = hwAuthToken->challenge;
219 authToken.userId = hwAuthToken->user_id;
220 authToken.authenticatorId = hwAuthToken->authenticator_id;
221 authToken.authenticatorType = static_cast<HardwareAuthenticatorType>(
222 betoh32(hwAuthToken->authenticator_type));
223 authToken.mac.assign(&hwAuthToken->hmac[0], &hwAuthToken->hmac[32]);
224 return authToken;
225 }
226 } else {
227 return std::nullopt;
228 }
229 }
doVerify(uint32_t uid,uint64_t challenge,const std::vector<uint8_t> & handle,const string & pwd)230 std::optional<HardwareAuthToken> doVerify(uint32_t uid, uint64_t challenge,
231 const std::vector<uint8_t>& handle,
232 const string& pwd) {
233 return doVerify(uid, challenge, handle, std::vector<uint8_t>(pwd.begin(), pwd.end()));
234 }
doVerify(uint64_t challenge,const std::vector<uint8_t> & handle,const string & pwd)235 std::optional<HardwareAuthToken> doVerify(uint64_t challenge,
236 const std::vector<uint8_t>& handle,
237 const string& pwd) {
238 return doVerify(uid_, challenge, handle, pwd);
239 }
240
241 // 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)242 string ProcessMessage(const vector<uint8_t>& key_blob, KeyPurpose operation,
243 const string& message, const AuthorizationSet& in_params,
244 AuthorizationSet* out_params, const HardwareAuthToken& hat) {
245 AuthorizationSet begin_out_params;
246 ErrorCode result = Begin(operation, key_blob, in_params, out_params, hat);
247 EXPECT_EQ(ErrorCode::OK, result);
248 if (result != ErrorCode::OK) {
249 return "";
250 }
251
252 std::optional<secureclock::TimeStampToken> time_token = std::nullopt;
253 if (timestamp_token_required_ && clock_ != nullptr) {
254 // Ask a secure clock instance for a timestamp, including the per-op challenge.
255 secureclock::TimeStampToken token;
256 EXPECT_EQ(ErrorCode::OK,
257 GetReturnErrorCode(clock_->generateTimeStamp(challenge_, &token)));
258 time_token = token;
259 }
260
261 string output;
262 EXPECT_EQ(ErrorCode::OK, Finish(message, {} /* signature */, &output, hat, time_token));
263 return output;
264 }
265
EncryptMessage(const vector<uint8_t> & key_blob,const string & message,const AuthorizationSet & in_params,AuthorizationSet * out_params,const HardwareAuthToken & hat)266 string EncryptMessage(const vector<uint8_t>& key_blob, const string& message,
267 const AuthorizationSet& in_params, AuthorizationSet* out_params,
268 const HardwareAuthToken& hat) {
269 SCOPED_TRACE("EncryptMessage");
270 return ProcessMessage(key_blob, KeyPurpose::ENCRYPT, message, in_params, out_params, hat);
271 }
272
DecryptMessage(const vector<uint8_t> & key_blob,const string & ciphertext,const AuthorizationSet & params,const HardwareAuthToken & hat)273 string DecryptMessage(const vector<uint8_t>& key_blob, const string& ciphertext,
274 const AuthorizationSet& params, const HardwareAuthToken& hat) {
275 SCOPED_TRACE("DecryptMessage");
276 AuthorizationSet out_params;
277 string plaintext =
278 ProcessMessage(key_blob, KeyPurpose::DECRYPT, ciphertext, params, &out_params, hat);
279 EXPECT_TRUE(out_params.empty());
280 return plaintext;
281 }
282
SignMessage(const vector<uint8_t> & key_blob,const string & message,const AuthorizationSet & in_params,AuthorizationSet * out_params,const HardwareAuthToken & hat)283 string SignMessage(const vector<uint8_t>& key_blob, const string& message,
284 const AuthorizationSet& in_params, AuthorizationSet* out_params,
285 const HardwareAuthToken& hat) {
286 SCOPED_TRACE("SignMessage");
287 return ProcessMessage(key_blob, KeyPurpose::SIGN, message, in_params, out_params, hat);
288 }
289
290 protected:
291 std::shared_ptr<IGatekeeper> gk_;
292 sp<IHidlGatekeeper> hidl_gk_;
293 std::shared_ptr<ISecureClock> clock_;
294 string password_;
295 uint32_t uid_;
296 int64_t sid_;
297 uint32_t alt_uid_;
298 int64_t alt_sid_;
299 std::vector<uint8_t> handle_;
300 };
301
302 // Test use of a key that requires user-authentication within recent history.
TEST_P(AuthTest,TimeoutAuthentication)303 TEST_P(AuthTest, TimeoutAuthentication) {
304 if (!GatekeeperAvailable()) {
305 GTEST_SKIP() << "No Gatekeeper available";
306 }
307 if (timestamp_token_required_ && clock_ == nullptr) {
308 GTEST_SKIP() << "Device requires timestamps and no ISecureClock available";
309 }
310
311 // Create an AES key that requires authentication within the last 3 seconds.
312 const uint32_t timeout_secs = 3;
313 auto builder = AuthorizationSetBuilder()
314 .AesEncryptionKey(256)
315 .BlockMode(BlockMode::ECB)
316 .Padding(PaddingMode::PKCS7)
317 .Authorization(TAG_USER_SECURE_ID, sid_)
318 .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD)
319 .Authorization(TAG_AUTH_TIMEOUT, timeout_secs);
320 vector<uint8_t> keyblob;
321 vector<KeyCharacteristics> key_characteristics;
322 vector<Certificate> cert_chain;
323 ASSERT_EQ(ErrorCode::OK,
324 GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
325
326 // Attempt to use the AES key without authentication.
327 const string message = "Hello World!";
328 AuthorizationSet out_params;
329 auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
330 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
331 Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
332
333 // Verify to get a HAT, arbitrary challenge.
334 const uint64_t challenge = 42;
335 const std::optional<HardwareAuthToken> hat = doVerify(challenge, handle_, password_);
336 ASSERT_TRUE(hat.has_value());
337 EXPECT_EQ(hat->userId, sid_);
338
339 // Adding the auth token makes it possible to use the AES key.
340 const string ciphertext = EncryptMessage(keyblob, message, params, &out_params, hat.value());
341 const string plaintext = DecryptMessage(keyblob, ciphertext, params, hat.value());
342 EXPECT_EQ(message, plaintext);
343
344 // Altering a single bit in the MAC means no auth.
345 HardwareAuthToken dodgy_hat = hat.value();
346 ASSERT_GT(dodgy_hat.mac.size(), 0);
347 dodgy_hat.mac[0] ^= 0x01;
348 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
349 Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, dodgy_hat));
350
351 // Wait for long enough that the hardware auth token expires.
352 sleep(timeout_secs + 1);
353
354 auto begin_result = Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat);
355 if (begin_result == ErrorCode::OK) {
356 // If begin() succeeds despite the out-of-date HAT, that must mean that the KeyMint
357 // device doesn't have its own clock. In that case, it only detects timeout via a
358 // timestamp token provided on update()/finish()
359 ASSERT_TRUE(timestamp_token_required_);
360
361 secureclock::TimeStampToken time_token;
362 EXPECT_EQ(ErrorCode::OK,
363 GetReturnErrorCode(clock_->generateTimeStamp(challenge_, &time_token)));
364
365 string output;
366 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
367 Finish(message, {} /* signature */, &output, hat, time_token));
368 } else {
369 // The KeyMint implementation may have its own clock that can immediately detect timeout.
370 ASSERT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED, begin_result);
371 }
372 }
373
374 // Test use of a key that requires user-authentication within recent history, but where
375 // the `TimestampToken` provided to the device is unrelated to the in-progress operation.
TEST_P(AuthTest,TimeoutAuthenticationIncorrectTimestampToken)376 TEST_P(AuthTest, TimeoutAuthenticationIncorrectTimestampToken) {
377 if (!GatekeeperAvailable()) {
378 GTEST_SKIP() << "No Gatekeeper available";
379 }
380 if (!timestamp_token_required_) {
381 GTEST_SKIP() << "Test only applies to devices with no secure clock";
382 }
383 if (clock_ == nullptr) {
384 GTEST_SKIP() << "Device requires timestamps and no ISecureClock available";
385 }
386
387 // Create an AES key that requires authentication within the last 3 seconds.
388 const uint32_t timeout_secs = 3;
389 auto builder = AuthorizationSetBuilder()
390 .AesEncryptionKey(256)
391 .BlockMode(BlockMode::ECB)
392 .Padding(PaddingMode::PKCS7)
393 .Authorization(TAG_USER_SECURE_ID, sid_)
394 .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD)
395 .Authorization(TAG_AUTH_TIMEOUT, timeout_secs);
396 vector<uint8_t> keyblob;
397 vector<KeyCharacteristics> key_characteristics;
398 vector<Certificate> cert_chain;
399 ASSERT_EQ(ErrorCode::OK,
400 GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
401
402 // Verify to get a HAT, arbitrary challenge.
403 const uint64_t challenge = 42;
404 const std::optional<HardwareAuthToken> hat = doVerify(challenge, handle_, password_);
405 ASSERT_TRUE(hat.has_value());
406 EXPECT_EQ(hat->userId, sid_);
407
408 // KeyMint implementation has no clock, so only detects timeout via timestamp token provided
409 // on update()/finish(). However, for this test we ensure that that the timestamp token has a
410 // *different* challenge value.
411 const string message = "Hello World!";
412 auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
413 AuthorizationSet out_params;
414 ASSERT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, hat));
415
416 secureclock::TimeStampToken time_token;
417 EXPECT_EQ(ErrorCode::OK,
418 GetReturnErrorCode(clock_->generateTimeStamp(challenge_ + 1, &time_token)));
419 string output;
420 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
421 Finish(message, {} /* signature */, &output, hat, time_token));
422 }
423
424 // Test use of a key with multiple USER_SECURE_ID values. For variety, use an EC signing key
425 // generated with attestation.
TEST_P(AuthTest,TimeoutAuthenticationMultiSid)426 TEST_P(AuthTest, TimeoutAuthenticationMultiSid) {
427 if (!GatekeeperAvailable()) {
428 GTEST_SKIP() << "No Gatekeeper available";
429 }
430 if (timestamp_token_required_ && clock_ == nullptr) {
431 GTEST_SKIP() << "Device requires timestamps and no ISecureClock available";
432 }
433
434 // Enroll a password for a second user.
435 alt_uid_ = 20001;
436 const string alt_password = "correcthorsebatterystaple2";
437 std::optional<GatekeeperEnrollResponse> rsp = doEnroll(alt_uid_, alt_password);
438 ASSERT_TRUE(rsp.has_value());
439 alt_sid_ = rsp->secureUserId;
440 const std::vector<uint8_t> alt_handle = rsp->data;
441
442 // Create an attested EC key that requires authentication within the last 3 seconds from either
443 // secure ID. Also allow any authenticator type.
444 const uint32_t timeout_secs = 3;
445 auto builder = AuthorizationSetBuilder()
446 .EcdsaSigningKey(EcCurve::P_256)
447 .Digest(Digest::NONE)
448 .Digest(Digest::SHA_2_256)
449 .SetDefaultValidity()
450 .AttestationChallenge("challenge")
451 .AttestationApplicationId("app_id")
452 .Authorization(TAG_USER_SECURE_ID, alt_sid_)
453 .Authorization(TAG_USER_SECURE_ID, sid_)
454 .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::ANY)
455 .Authorization(TAG_AUTH_TIMEOUT, timeout_secs);
456 vector<uint8_t> keyblob;
457 vector<KeyCharacteristics> key_characteristics;
458 auto result = GenerateKey(builder, &keyblob, &key_characteristics);
459 ASSERT_EQ(ErrorCode::OK, result);
460
461 // Verify first user to get a HAT that should work.
462 const uint64_t challenge = 42;
463 const std::optional<HardwareAuthToken> hat = doVerify(uid_, challenge, handle_, password_);
464 ASSERT_TRUE(hat.has_value());
465 EXPECT_EQ(hat->userId, sid_);
466
467 const string message = "Hello World!";
468 auto params = AuthorizationSetBuilder().Digest(Digest::SHA_2_256);
469 AuthorizationSet out_params;
470 const string signature = SignMessage(keyblob, message, params, &out_params, hat.value());
471
472 // Verify second user to get a HAT that should work.
473 const uint64_t alt_challenge = 43;
474 const std::optional<HardwareAuthToken> alt_hat =
475 doVerify(alt_uid_, alt_challenge, alt_handle, alt_password);
476 ASSERT_TRUE(alt_hat.has_value());
477 EXPECT_EQ(alt_hat->userId, alt_sid_);
478
479 const string alt_signature =
480 SignMessage(keyblob, message, params, &out_params, alt_hat.value());
481 }
482
483 // Test use of a key that requires an auth token for each action on the operation, with
484 // a per-operation challenge value included.
TEST_P(AuthTest,AuthPerOperation)485 TEST_P(AuthTest, AuthPerOperation) {
486 if (!GatekeeperAvailable()) {
487 GTEST_SKIP() << "No Gatekeeper available";
488 }
489
490 // Create an AES key that requires authentication per-action.
491 auto builder = AuthorizationSetBuilder()
492 .AesEncryptionKey(256)
493 .BlockMode(BlockMode::ECB)
494 .Padding(PaddingMode::PKCS7)
495 .Authorization(TAG_USER_SECURE_ID, sid_)
496 .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD);
497 vector<uint8_t> keyblob;
498 vector<KeyCharacteristics> key_characteristics;
499 vector<Certificate> cert_chain;
500 ASSERT_EQ(ErrorCode::OK,
501 GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
502
503 // Attempt to use the AES key without authentication fails after begin.
504 const string message = "Hello World!";
505 AuthorizationSet out_params;
506 auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
507 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
508 string output;
509 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED, Finish(message, {} /* signature */, &output));
510
511 // Verify to get a HAT, but with an arbitrary challenge.
512 const uint64_t unrelated_challenge = 42;
513 const std::optional<HardwareAuthToken> unrelated_hat =
514 doVerify(unrelated_challenge, handle_, password_);
515 ASSERT_TRUE(unrelated_hat.has_value());
516 EXPECT_EQ(unrelated_hat->userId, sid_);
517
518 // Attempt to use the AES key with an unrelated authentication fails after begin.
519 EXPECT_EQ(ErrorCode::OK,
520 Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params, unrelated_hat.value()));
521 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
522 Finish(message, {} /* signature */, &output, unrelated_hat.value()));
523
524 // Now get a HAT with the challenge from an in-progress operation.
525 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
526 const std::optional<HardwareAuthToken> hat = doVerify(challenge_, handle_, password_);
527 ASSERT_TRUE(hat.has_value());
528 EXPECT_EQ(hat->userId, sid_);
529 string ciphertext;
530 EXPECT_EQ(ErrorCode::OK, Finish(message, {} /* signature */, &ciphertext, hat.value()));
531
532 // Altering a single bit in the MAC means no auth.
533 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
534 std::optional<HardwareAuthToken> dodgy_hat = doVerify(challenge_, handle_, password_);
535 ASSERT_TRUE(dodgy_hat.has_value());
536 EXPECT_EQ(dodgy_hat->userId, sid_);
537 ASSERT_GT(dodgy_hat->mac.size(), 0);
538 dodgy_hat->mac[0] ^= 0x01;
539 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
540 Finish(message, {} /* signature */, &ciphertext, dodgy_hat.value()));
541 }
542
543 // Test use of a key that requires an auth token for each action on the operation, with
544 // a per-operation challenge value included, with multiple secure IDs allowed.
TEST_P(AuthTest,AuthPerOperationMultiSid)545 TEST_P(AuthTest, AuthPerOperationMultiSid) {
546 if (!GatekeeperAvailable()) {
547 GTEST_SKIP() << "No Gatekeeper available";
548 }
549
550 // Enroll a password for a second user.
551 alt_uid_ = 20001;
552 const string alt_password = "correcthorsebatterystaple2";
553 std::optional<GatekeeperEnrollResponse> rsp = doEnroll(alt_uid_, alt_password);
554 ASSERT_TRUE(rsp.has_value());
555 alt_sid_ = rsp->secureUserId;
556 const std::vector<uint8_t> alt_handle = rsp->data;
557
558 // Create an AES key that requires authentication per-action.
559 auto builder = AuthorizationSetBuilder()
560 .AesEncryptionKey(256)
561 .BlockMode(BlockMode::ECB)
562 .Padding(PaddingMode::PKCS7)
563 .Authorization(TAG_USER_SECURE_ID, sid_)
564 .Authorization(TAG_USER_SECURE_ID, alt_sid_)
565 .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::ANY);
566 vector<uint8_t> keyblob;
567 vector<KeyCharacteristics> key_characteristics;
568 vector<Certificate> cert_chain;
569 ASSERT_EQ(ErrorCode::OK,
570 GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
571
572 // Get a HAT for first user with the challenge from an in-progress operation.
573 const string message = "Hello World!";
574 auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
575 AuthorizationSet out_params;
576 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
577 const std::optional<HardwareAuthToken> hat = doVerify(uid_, challenge_, handle_, password_);
578 ASSERT_TRUE(hat.has_value());
579 EXPECT_EQ(hat->userId, sid_);
580 string ciphertext;
581 EXPECT_EQ(ErrorCode::OK, Finish(message, {} /* signature */, &ciphertext, hat.value()));
582
583 // Get a HAT for second user with the challenge from an in-progress operation.
584 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
585 const std::optional<HardwareAuthToken> alt_hat =
586 doVerify(alt_uid_, challenge_, alt_handle, alt_password);
587 ASSERT_TRUE(alt_hat.has_value());
588 EXPECT_EQ(alt_hat->userId, alt_sid_);
589 string alt_ciphertext;
590 EXPECT_EQ(ErrorCode::OK, Finish(message, {} /* signature */, &ciphertext, alt_hat.value()));
591 }
592
593 // Test use of a key that requires an auth token for each action on the operation, but
594 // which gets passed a HAT of the wrong type
TEST_P(AuthTest,AuthPerOperationWrongAuthType)595 TEST_P(AuthTest, AuthPerOperationWrongAuthType) {
596 if (!GatekeeperAvailable()) {
597 GTEST_SKIP() << "No Gatekeeper available";
598 }
599
600 // Create an AES key that requires authentication per-action, but with no valid authenticator
601 // types.
602 auto builder =
603 AuthorizationSetBuilder()
604 .AesEncryptionKey(256)
605 .BlockMode(BlockMode::ECB)
606 .Padding(PaddingMode::PKCS7)
607 .Authorization(TAG_USER_SECURE_ID, sid_)
608 .Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::FINGERPRINT);
609 vector<uint8_t> keyblob;
610 vector<KeyCharacteristics> key_characteristics;
611 vector<Certificate> cert_chain;
612 ASSERT_EQ(ErrorCode::OK,
613 GenerateKey(builder, std::nullopt, &keyblob, &key_characteristics, &cert_chain));
614
615 // Get a HAT with the challenge from an in-progress operation.
616 const string message = "Hello World!";
617 auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
618 AuthorizationSet out_params;
619 EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, keyblob, params, &out_params));
620 const std::optional<HardwareAuthToken> hat = doVerify(challenge_, handle_, password_);
621 ASSERT_TRUE(hat.has_value());
622 EXPECT_EQ(hat->userId, sid_);
623
624 // Should fail because auth type doesn't (can't) match.
625 string ciphertext;
626 EXPECT_EQ(ErrorCode::KEY_USER_NOT_AUTHENTICATED,
627 Finish(message, {} /* signature */, &ciphertext, hat.value()));
628 }
629
630 INSTANTIATE_KEYMINT_AIDL_TEST(AuthTest);
631
632 } // namespace aidl::android::hardware::security::keymint::test
633