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