1 /*
2 * Copyright (C) 2021 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 "VehicleBindingUtil.h"
18
19 #include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
20 #include <android/hardware/automotive/vehicle/2.0/types.h>
21 #include <gmock/gmock.h>
22 #include <gtest/gtest.h>
23 #include <hidl/Status.h>
24 #include <utils/SystemClock.h>
25
26 #include <iterator>
27
28 namespace android {
29 namespace automotive {
30 namespace security {
31 namespace {
32
33 using android::hardware::Void;
34 using android::hardware::automotive::vehicle::V2_0::IVehicle;
35 using android::hardware::automotive::vehicle::V2_0::IVehicleCallback;
36 using android::hardware::automotive::vehicle::V2_0::StatusCode;
37 using android::hardware::automotive::vehicle::V2_0::SubscribeOptions;
38 using android::hardware::automotive::vehicle::V2_0::VehicleProperty;
39 using android::hardware::automotive::vehicle::V2_0::VehiclePropValue;
40
41 template <typename T>
42 using hidl_vec = android::hardware::hidl_vec<T>;
43 template <typename T>
44 using VhalReturn = android::hardware::Return<T>;
45
46 using ::testing::_;
47 using ::testing::DoAll;
48 using ::testing::ElementsAreArray;
49 using ::testing::NotNull;
50 using ::testing::Return;
51 using ::testing::SetArgPointee;
52 using ::testing::Test;
53
54 class MockVehicle : public IVehicle {
55 public:
56 MOCK_METHOD(VhalReturn<void>, getAllPropConfigs, (getAllPropConfigs_cb), (override));
57
58 MOCK_METHOD(VhalReturn<void>, getPropConfigs, (const hidl_vec<int32_t>&, getPropConfigs_cb),
59 (override));
60
61 MOCK_METHOD(VhalReturn<void>, get, (const VehiclePropValue&, get_cb), (override));
62
63 MOCK_METHOD(VhalReturn<StatusCode>, set, (const VehiclePropValue&), (override));
64
65 MOCK_METHOD(VhalReturn<StatusCode>, subscribe,
66 (const sp<IVehicleCallback>&, const hidl_vec<SubscribeOptions>&), (override));
67
68 MOCK_METHOD(VhalReturn<StatusCode>, unsubscribe, (const sp<IVehicleCallback>&, int32_t),
69 (override));
70
71 MOCK_METHOD(VhalReturn<void>, debugDump, (debugDump_cb), (override));
72 };
73
74 class MockCsrng : public Csrng {
75 public:
76 MOCK_METHOD(bool, fill, (void*, size_t), (const override));
77 };
78
79 class MockExecutor : public Executor {
80 public:
81 MOCK_METHOD(int, run, (const std::vector<std::string>&, int*), (const override));
82 };
83
84 class VehicleBindingUtilTests : public Test {
85 protected:
setMockVhalPropertySupported()86 void setMockVhalPropertySupported() {
87 hidl_vec<int32_t> expectedProps = {toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED)};
88 EXPECT_CALL(*mMockVehicle, getPropConfigs(expectedProps, _))
89 .WillOnce([](const hidl_vec<int32_t>&, IVehicle::getPropConfigs_cb callback) {
90 callback(StatusCode::OK, {});
91 return Void();
92 });
93 }
94
setMockVhalPropertyValue(const std::vector<uint8_t> & seed)95 void setMockVhalPropertyValue(const std::vector<uint8_t>& seed) {
96 EXPECT_CALL(*mMockVehicle, get(_, _))
97 .WillOnce([seed](const VehiclePropValue& propValue, IVehicle::get_cb callback) {
98 EXPECT_EQ(propValue.prop,
99 toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED));
100 VehiclePropValue value;
101 value.prop = propValue.prop;
102 value.value.bytes = hidl_vec<uint8_t>{seed.begin(), seed.end()};
103 callback(StatusCode::OK, value);
104 return Void();
105 });
106 }
107
setTestRandomness(const char seed[SEED_BYTE_SIZE])108 void setTestRandomness(const char seed[SEED_BYTE_SIZE]) {
109 EXPECT_CALL(mMockCsrng, fill(NotNull(), SEED_BYTE_SIZE))
110 .WillOnce([seed](void* buf, size_t) {
111 memcpy(buf, seed, SEED_BYTE_SIZE);
112 return true;
113 });
114 }
115
toVector(const char seed[SEED_BYTE_SIZE])116 static std::vector<uint8_t> toVector(const char seed[SEED_BYTE_SIZE]) {
117 return {seed, seed + SEED_BYTE_SIZE};
118 }
119
makeVdcArgs()120 static std::vector<std::string> makeVdcArgs() {
121 return {"/system/bin/vdc", "cryptfs", "bindkeys"};
122 }
123
124 sp<MockVehicle> mMockVehicle{new MockVehicle};
125 MockExecutor mMockExecutor;
126 MockCsrng mMockCsrng;
127 };
128
129 // Verify that we fail as expected if the VHAL property is not supported. This
130 // is not necessarily an error, and is expected on platforms that don't
131 // implement the feature.
TEST_F(VehicleBindingUtilTests,VhalPropertyUnsupported)132 TEST_F(VehicleBindingUtilTests, VhalPropertyUnsupported) {
133 hidl_vec<int32_t> expectedProps = {toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED)};
134 EXPECT_CALL(*mMockVehicle, getPropConfigs(expectedProps, _))
135 .WillOnce([](const hidl_vec<int32_t>&, IVehicle::getPropConfigs_cb callback) {
136 callback(StatusCode::INVALID_ARG, {});
137 return Void();
138 });
139
140 EXPECT_EQ(BindingStatus::NOT_SUPPORTED,
141 setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
142 }
143
144 // Verify that we properly handle an attempt to generate a random seed.
TEST_F(VehicleBindingUtilTests,GetRandomnessFails)145 TEST_F(VehicleBindingUtilTests, GetRandomnessFails) {
146 setMockVhalPropertySupported();
147 setMockVhalPropertyValue({});
148 EXPECT_CALL(mMockCsrng, fill(_, SEED_BYTE_SIZE)).WillOnce(Return(false));
149 EXPECT_EQ(BindingStatus::ERROR, setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
150 }
151
152 // Verify that we properly handle an attempt to generate a random seed.
TEST_F(VehicleBindingUtilTests,GetSeedVhalPropertyFails)153 TEST_F(VehicleBindingUtilTests, GetSeedVhalPropertyFails) {
154 setMockVhalPropertySupported();
155 EXPECT_CALL(*mMockVehicle, get(_, _))
156 .WillOnce([&](const VehiclePropValue& propValue, IVehicle::get_cb callback) {
157 EXPECT_EQ(propValue.prop, toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED));
158 callback(StatusCode::NOT_AVAILABLE, {});
159 return Void();
160 });
161 EXPECT_EQ(BindingStatus::ERROR, setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
162 }
163
TEST_F(VehicleBindingUtilTests,SetSeedVhalPropertyFails)164 TEST_F(VehicleBindingUtilTests, SetSeedVhalPropertyFails) {
165 setMockVhalPropertySupported();
166 setMockVhalPropertyValue({});
167 setTestRandomness("I am not random");
168
169 EXPECT_CALL(*mMockVehicle, set(_)).WillOnce([](const VehiclePropValue&) {
170 return StatusCode::NOT_AVAILABLE;
171 });
172
173 EXPECT_EQ(BindingStatus::ERROR, setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
174 }
175
TEST_F(VehicleBindingUtilTests,SetSeedWithNewRandomSeed)176 TEST_F(VehicleBindingUtilTests, SetSeedWithNewRandomSeed) {
177 setMockVhalPropertySupported();
178 setMockVhalPropertyValue({});
179 constexpr char SEED[SEED_BYTE_SIZE] = "Seed Value Here";
180 setTestRandomness(SEED);
181
182 EXPECT_CALL(*mMockVehicle, set(_)).WillOnce([&](const VehiclePropValue& value) {
183 EXPECT_EQ(value.prop, toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED));
184 EXPECT_THAT(value.value.bytes, testing::ElementsAreArray(SEED));
185 return StatusCode::OK;
186 });
187
188 EXPECT_CALL(mMockExecutor, run(ElementsAreArray(makeVdcArgs()), _)).WillOnce(Return(0));
189
190 EXPECT_EQ(BindingStatus::OK, setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
191 }
192
TEST_F(VehicleBindingUtilTests,SetSeedWithExistingProperty)193 TEST_F(VehicleBindingUtilTests, SetSeedWithExistingProperty) {
194 setMockVhalPropertySupported();
195 const auto SEED = toVector("16 bytes of seed");
196 setMockVhalPropertyValue(SEED);
197 EXPECT_CALL(mMockExecutor, run(ElementsAreArray(makeVdcArgs()), _)).WillOnce(Return(0));
198 EXPECT_EQ(BindingStatus::OK, setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
199 }
200
TEST_F(VehicleBindingUtilTests,SetSeedVdcExecFails)201 TEST_F(VehicleBindingUtilTests, SetSeedVdcExecFails) {
202 setMockVhalPropertySupported();
203 const auto SEED = toVector("abcdefghijklmnop");
204 setMockVhalPropertyValue(SEED);
205 EXPECT_CALL(mMockExecutor, run(ElementsAreArray(makeVdcArgs()), _)).WillOnce(Return(-1));
206 EXPECT_EQ(BindingStatus::ERROR, setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
207 }
208
TEST_F(VehicleBindingUtilTests,SetSeedVdcExitsWithNonZeroStatus)209 TEST_F(VehicleBindingUtilTests, SetSeedVdcExitsWithNonZeroStatus) {
210 setMockVhalPropertySupported();
211 const auto SEED = toVector("1123581321345589");
212 setMockVhalPropertyValue(SEED);
213 EXPECT_CALL(mMockExecutor, run(ElementsAreArray(makeVdcArgs()), _))
214 .WillOnce(DoAll(SetArgPointee<1>(-1), Return(0)));
215 EXPECT_EQ(BindingStatus::ERROR, setVehicleBindingSeed(mMockVehicle, mMockExecutor, mMockCsrng));
216 }
217
218 } // namespace
219 } // namespace security
220 } // namespace automotive
221 } // namespace android
222