1 /*
2  * Copyright 2020, 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 <gtest/gtest.h>
18 
19 #include "km_compat.h"
20 #include <keymint_support/keymint_tags.h>
21 
22 #include <aidl/android/hardware/security/keymint/ErrorCode.h>
23 #include <aidl/android/hardware/security/keymint/IKeyMintOperation.h>
24 
25 using ::aidl::android::hardware::security::keymint::Algorithm;
26 using ::aidl::android::hardware::security::keymint::BlockMode;
27 using ::aidl::android::hardware::security::keymint::Certificate;
28 using ::aidl::android::hardware::security::keymint::Digest;
29 using ::aidl::android::hardware::security::keymint::ErrorCode;
30 using ::aidl::android::hardware::security::keymint::IKeyMintOperation;
31 using ::aidl::android::hardware::security::keymint::KeyCharacteristics;
32 using ::aidl::android::hardware::security::keymint::KeyPurpose;
33 using ::aidl::android::hardware::security::keymint::PaddingMode;
34 using ::aidl::android::hardware::security::keymint::SecurityLevel;
35 
36 namespace KMV1 = ::aidl::android::hardware::security::keymint;
37 
generateAESKey(std::shared_ptr<KeyMintDevice> device)38 static std::vector<uint8_t> generateAESKey(std::shared_ptr<KeyMintDevice> device) {
39     auto keyParams = std::vector<KeyParameter>({
40         KMV1::makeKeyParameter(KMV1::TAG_ALGORITHM, Algorithm::AES),
41         KMV1::makeKeyParameter(KMV1::TAG_KEY_SIZE, 128),
42         KMV1::makeKeyParameter(KMV1::TAG_BLOCK_MODE, BlockMode::CBC),
43         KMV1::makeKeyParameter(KMV1::TAG_PADDING, PaddingMode::NONE),
44         KMV1::makeKeyParameter(KMV1::TAG_NO_AUTH_REQUIRED, true),
45         KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::ENCRYPT),
46         KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::DECRYPT),
47     });
48     KeyCreationResult creationResult;
49     auto status = device->generateKey(keyParams, std::nullopt /* attest_key */, &creationResult);
50     if (!status.isOk()) {
51         return {};
52     }
53     return creationResult.keyBlob;
54 }
55 
begin(std::shared_ptr<KeyMintDevice> device,bool valid)56 static std::variant<BeginResult, ScopedAStatus> begin(std::shared_ptr<KeyMintDevice> device,
57                                                       bool valid) {
58     auto blob = generateAESKey(device);
59     std::vector<KeyParameter> kps;
60     if (valid) {
61         kps.push_back(KMV1::makeKeyParameter(KMV1::TAG_BLOCK_MODE, BlockMode::CBC));
62         kps.push_back(KMV1::makeKeyParameter(KMV1::TAG_PADDING, PaddingMode::NONE));
63     }
64     BeginResult beginResult;
65     auto status = device->begin(KeyPurpose::ENCRYPT, blob, kps, HardwareAuthToken(), &beginResult);
66     if (!status.isOk()) {
67         return status;
68     }
69     return beginResult;
70 }
71 
72 static const int NUM_SLOTS = 2;
73 
TEST(SlotTest,TestSlots)74 TEST(SlotTest, TestSlots) {
75     static std::shared_ptr<KeyMintDevice> device =
76         KeyMintDevice::createKeyMintDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
77     device->setNumFreeSlots(NUM_SLOTS);
78 
79     // A begin() that returns a failure should not use a slot.
80     auto result = begin(device, false);
81     ASSERT_TRUE(std::holds_alternative<ScopedAStatus>(result));
82 
83     // Fill up all the slots.
84     std::vector<std::shared_ptr<IKeyMintOperation>> operations;
85     for (int i = 0; i < NUM_SLOTS; i++) {
86         auto result = begin(device, true);
87         ASSERT_TRUE(std::holds_alternative<BeginResult>(result));
88         operations.push_back(std::get<BeginResult>(result).operation);
89     }
90 
91     // We should not be able to create a new operation.
92     result = begin(device, true);
93     ASSERT_TRUE(std::holds_alternative<ScopedAStatus>(result));
94     ASSERT_EQ(std::get<ScopedAStatus>(result).getServiceSpecificError(),
95               static_cast<int32_t>(ErrorCode::TOO_MANY_OPERATIONS));
96 
97     // TODO: I'm not sure how to generate a failing update call to test that.
98 
99     // Calling finish should free up a slot.
100     auto last = operations.back();
101     operations.pop_back();
102     std::vector<uint8_t> byteVec;
103     auto status = last->finish(std::nullopt /* input */, std::nullopt /* signature */,
104                                std::nullopt /* authToken */, std::nullopt /* timestampToken */,
105                                std::nullopt /* confirmationToken */, &byteVec);
106     ASSERT_TRUE(status.isOk());
107     result = begin(device, true);
108     ASSERT_TRUE(std::holds_alternative<BeginResult>(result));
109     operations.push_back(std::get<BeginResult>(result).operation);
110 
111     // Calling finish and abort on an already-finished operation should not free up another slot.
112     status = last->finish(std::nullopt /* input */, std::nullopt /* signature */,
113                           std::nullopt /* authToken */, std::nullopt /* timestampToken */,
114                           std::nullopt /* confirmationToken */, &byteVec);
115     ASSERT_TRUE(!status.isOk());
116     status = last->abort();
117     ASSERT_TRUE(!status.isOk());
118     result = begin(device, true);
119     ASSERT_TRUE(std::holds_alternative<ScopedAStatus>(result));
120     ASSERT_EQ(std::get<ScopedAStatus>(result).getServiceSpecificError(),
121               static_cast<int32_t>(ErrorCode::TOO_MANY_OPERATIONS));
122 
123     // Calling abort should free up a slot.
124     last = operations.back();
125     operations.pop_back();
126     status = last->abort();
127     ASSERT_TRUE(status.isOk());
128     result = begin(device, true);
129     ASSERT_TRUE(std::holds_alternative<BeginResult>(result));
130     operations.push_back(std::get<BeginResult>(result).operation);
131 
132     // Calling finish and abort on an already-aborted operation should not free up another slot.
133     status = last->finish(std::nullopt /* input */, std::nullopt /* signature */,
134                           std::nullopt /* authToken */, std::nullopt /* timestampToken */,
135                           std::nullopt /* confirmationToken */, &byteVec);
136     ASSERT_TRUE(!status.isOk());
137     status = last->abort();
138     ASSERT_TRUE(!status.isOk());
139     result = begin(device, true);
140     ASSERT_TRUE(std::holds_alternative<ScopedAStatus>(result));
141     ASSERT_EQ(std::get<ScopedAStatus>(result).getServiceSpecificError(),
142               static_cast<int32_t>(ErrorCode::TOO_MANY_OPERATIONS));
143 
144     // Generating a certificate with signWith uses a slot but falls back to not using one.
145     auto kps = std::vector<KeyParameter>({
146         KMV1::makeKeyParameter(KMV1::TAG_ALGORITHM, Algorithm::RSA),
147         KMV1::makeKeyParameter(KMV1::TAG_KEY_SIZE, 2048),
148         KMV1::makeKeyParameter(KMV1::TAG_RSA_PUBLIC_EXPONENT, 65537),
149         KMV1::makeKeyParameter(KMV1::TAG_DIGEST, Digest::SHA_2_256),
150         KMV1::makeKeyParameter(KMV1::TAG_PURPOSE, KeyPurpose::SIGN),
151         KMV1::makeKeyParameter(KMV1::TAG_CERTIFICATE_NOT_BEFORE, 0),
152         KMV1::makeKeyParameter(KMV1::TAG_CERTIFICATE_NOT_AFTER, 253402300799000),
153         KMV1::makeKeyParameter(KMV1::TAG_NO_AUTH_REQUIRED, true),
154     });
155     KeyCreationResult creationResult;
156     status = device->generateKey(kps, std::nullopt /* attest_key */, &creationResult);
157     ASSERT_TRUE(status.isOk());
158     // But generating a certificate with signCert does not use a slot.
159     kps.pop_back();
160     status = device->generateKey(kps, std::nullopt /* attest_key */, &creationResult);
161     ASSERT_TRUE(status.isOk());
162 
163     // Destructing operations should free up their slots.
164     operations.clear();
165     result = begin(device, true);
166     ASSERT_TRUE(std::holds_alternative<BeginResult>(result));
167 }
168