1 /*
2 * Copyright (C) 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 // Utility functions for VtsKernelEncryptionTest.
18
19 #include <algorithm>
20 #include <fstream>
21
22 #include <LzmaLib.h>
23 #include <android-base/parseint.h>
24 #include <android-base/properties.h>
25 #include <android-base/strings.h>
26 #include <android-base/unique_fd.h>
27 #include <errno.h>
28 #include <ext4_utils/ext4.h>
29 #include <ext4_utils/ext4_sb.h>
30 #include <ext4_utils/ext4_utils.h>
31 #include <gtest/gtest.h>
32 #include <libdm/dm.h>
33 #include <linux/magic.h>
34 #include <mntent.h>
35 #include <openssl/cmac.h>
36 #include <unistd.h>
37
38 #include "Keymaster.h"
39 #include "vts_kernel_encryption.h"
40
41 using android::base::ParseInt;
42 using android::base::Split;
43 using android::base::StartsWith;
44 using namespace android::dm;
45
46 namespace android {
47 namespace kernel {
48
49 enum KdfVariant {
50 KDF_VARIANT_V1 = 0,
51 KDF_VARIANT_LEGACY = 1,
52 KDF_VARIANT_REARRANGED = 2,
53 KDF_VARIANT_COUNT,
54 };
55
56 // Context in fixed input string comprises of software provided context,
57 // padding to eight bytes (if required) and the key policy.
58 static const std::vector<std::vector<uint8_t>> HwWrappedEncryptionKeyContexts =
59 {
60 // "v1"
61 {'i', 'n', 'l', 'i', 'n', 'e', ' ', 'e', 'n', 'c', 'r', 'y',
62 'p', 't', 'i', 'o', 'n', ' ', 'k', 'e', 'y', 0x0, 0x0, 0x0,
63 0x00, 0x00, 0x00, 0x02, 0x43, 0x00, 0x82, 0x50, 0x0, 0x0, 0x0, 0x0},
64 // Below for "legacy && kdf tied to Trusted Execution
65 // Environment(TEE)".
66 // Where as above caters ( "all latest targets" || ("legacy && kdf
67 // not tied to TEE)).
68 // "legacykdf"
69 {'i', 'n', 'l', 'i', 'n', 'e', ' ', 'e', 'n', 'c', 'r', 'y',
70 'p', 't', 'i', 'o', 'n', ' ', 'k', 'e', 'y', 0x0, 0x0, 0x0,
71 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0x82, 0x18, 0x0, 0x0, 0x0, 0x0},
72 // "rearranged"
73 {
74 'i', 'n', 'l', 'i', 'n', 'e', ' ', 'e', 'n',
75 'c', 'r', 'y', 'p', 't', 'i', 'o', 'n', ' ',
76 's', 't', 'o', 'r', 'a', 'g', 'e', 'k', 'e',
77 'y', ' ', 'c', 't', 'x', 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x10, 0x70, 0x18, 0x72, 0x00, 0x00, 0x00, 0x00,
79 }};
80
81 static const std::vector<std::vector<uint8_t>> HwWrappedEncryptionKeyLabels = {
82 // "v1"
83 {0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20},
84 // "legacykdf"
85 {0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20},
86 // "rearranged"
87 {
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90 },
91 };
92
93 static const std::vector<std::vector<uint8_t>> SwSecretContexts = {
94 // "v1"
95 {
96 'r', 'a', 'w', ' ', 's', 'e', 'c', 'r', 'e', 't',
97 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x00, 0x00, 0x02,
98 0x17, 0x00, 0x80, 0x50, 0x0, 0x0, 0x0, 0x0,
99 },
100 // "legacykdf"
101 {
102 'r', 'a', 'w', ' ', 's', 'e', 'c', 'r', 'e', 't',
103 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x00, 0x00, 0x02,
104 0x17, 0x00, 0x80, 0x50, 0x0, 0x0, 0x0, 0x0,
105 },
106 // "rearranged"
107 {
108 'd', 'e', 'r', 'i', 'v', 'e', ' ', 'r', 'a', 'w', ' ',
109 's', 'e', 'c', 'r', 'e', 't', ' ', 'c', 'o', 'n', 't',
110 'e', 'x', 't', ' ', 'a', 'b', 'c', 'd', 'e', 'f',
111 }};
112
113 static const std::vector<std::vector<uint8_t>> SwSecretLabels = {
114 // "v1"
115 {0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20},
116 // "legacykdf"
117 {0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20},
118 // "rearranged"
119 {
120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 },
123 };
124
GetKdfVariantId(KdfVariant * kdf_id)125 static bool GetKdfVariantId(KdfVariant *kdf_id) {
126 std::string kdf =
127 android::base::GetProperty("ro.crypto.hw_wrapped_keys.kdf", "v1");
128
129 if (kdf == "v1") {
130 *kdf_id = KDF_VARIANT_V1;
131 } else if (kdf == "legacykdf") {
132 *kdf_id = KDF_VARIANT_LEGACY;
133 } else if (kdf == "rearranged") {
134 *kdf_id = KDF_VARIANT_REARRANGED;
135 } else {
136 ADD_FAILURE() << "Unknown KDF: " << kdf;
137 return false;
138 }
139 return true;
140 }
141
GetKdfContextLabelByKdfId(KdfVariant kdf_id,std::vector<uint8_t> * ctx,std::vector<uint8_t> * lbl)142 static void GetKdfContextLabelByKdfId(KdfVariant kdf_id,
143 std::vector<uint8_t> *ctx,
144 std::vector<uint8_t> *lbl) {
145 *ctx = HwWrappedEncryptionKeyContexts[kdf_id];
146 *lbl = HwWrappedEncryptionKeyLabels[kdf_id];
147 }
148
GetSwSecretContextLabelByKdfId(KdfVariant kdf_id,std::vector<uint8_t> * ctx,std::vector<uint8_t> * lbl)149 static void GetSwSecretContextLabelByKdfId(KdfVariant kdf_id,
150 std::vector<uint8_t> *ctx,
151 std::vector<uint8_t> *lbl) {
152 *ctx = SwSecretContexts[kdf_id];
153 *lbl = SwSecretLabels[kdf_id];
154 }
155
156 // Offset in bytes to the filesystem superblock, relative to the beginning of
157 // the block device
158 constexpr int kExt4SuperBlockOffset = 1024;
159 constexpr int kF2fsSuperBlockOffset = 1024;
160
161 // For F2FS: the offsets in bytes to the filesystem magic number and filesystem
162 // UUID, relative to the beginning of the block device
163 constexpr int kF2fsMagicOffset = kF2fsSuperBlockOffset;
164 constexpr int kF2fsUuidOffset = kF2fsSuperBlockOffset + 108;
165
166 // hw-wrapped key size in bytes
167 constexpr int kHwWrappedKeySize = 32;
168
Errno()169 std::string Errno() { return std::string(": ") + strerror(errno); }
170
171 // Recursively deletes the file or directory at |path|, if it exists.
DeleteRecursively(const std::string & path)172 void DeleteRecursively(const std::string &path) {
173 if (unlink(path.c_str()) == 0 || errno == ENOENT) return;
174 ASSERT_EQ(EISDIR, errno) << "Failed to unlink " << path << Errno();
175
176 std::unique_ptr<DIR, int (*)(DIR *)> dirp(opendir(path.c_str()), closedir);
177 // If the directory was assigned an encryption policy that the kernel lacks
178 // crypto API support for, then opening it will fail, and it will be empty.
179 // So, we have to allow opening the directory to fail.
180 if (dirp != nullptr) {
181 struct dirent *entry;
182 while ((entry = readdir(dirp.get())) != nullptr) {
183 std::string filename(entry->d_name);
184 if (filename != "." && filename != "..")
185 DeleteRecursively(path + "/" + filename);
186 }
187 }
188 ASSERT_EQ(0, rmdir(path.c_str()))
189 << "Failed to remove directory " << path << Errno();
190 }
191
192 // Generates some "random" bytes. Not secure; this is for testing only.
RandomBytesForTesting(std::vector<uint8_t> & bytes)193 void RandomBytesForTesting(std::vector<uint8_t> &bytes) {
194 for (size_t i = 0; i < bytes.size(); i++) {
195 bytes[i] = rand();
196 }
197 }
198
199 // Generates a "random" key. Not secure; this is for testing only.
GenerateTestKey(size_t size)200 std::vector<uint8_t> GenerateTestKey(size_t size) {
201 std::vector<uint8_t> key(size);
202 RandomBytesForTesting(key);
203 return key;
204 }
205
BytesToHex(const std::vector<uint8_t> & bytes)206 std::string BytesToHex(const std::vector<uint8_t> &bytes) {
207 std::ostringstream o;
208 for (uint8_t b : bytes) {
209 o << std::hex << std::setw(2) << std::setfill('0') << (int)b;
210 }
211 return o.str();
212 }
213
GetFirstApiLevel(int * first_api_level)214 bool GetFirstApiLevel(int *first_api_level) {
215 *first_api_level =
216 android::base::GetIntProperty("ro.product.first_api_level", 0);
217 if (*first_api_level == 0) {
218 ADD_FAILURE() << "ro.product.first_api_level is unset";
219 return false;
220 }
221 GTEST_LOG_(INFO) << "ro.product.first_api_level = " << *first_api_level;
222 return true;
223 }
224
225 // Gets the UUID of the filesystem that uses |fs_blk_device| as its main block
226 // device. |fs_type| gives the filesystem type.
227 //
228 // Unfortunately there's no kernel API to get the UUID; instead we have to read
229 // it from the filesystem superblock.
GetFilesystemUuid(const std::string & fs_blk_device,const std::string & fs_type,FilesystemUuid * fs_uuid)230 static bool GetFilesystemUuid(const std::string &fs_blk_device,
231 const std::string &fs_type,
232 FilesystemUuid *fs_uuid) {
233 android::base::unique_fd fd(
234 open(fs_blk_device.c_str(), O_RDONLY | O_CLOEXEC));
235 if (fd < 0) {
236 ADD_FAILURE() << "Failed to open fs block device " << fs_blk_device
237 << Errno();
238 return false;
239 }
240
241 if (fs_type == "ext4") {
242 struct ext4_super_block sb;
243
244 if (pread(fd, &sb, sizeof(sb), kExt4SuperBlockOffset) != sizeof(sb)) {
245 ADD_FAILURE() << "Error reading ext4 superblock from " << fs_blk_device
246 << Errno();
247 return false;
248 }
249 if (sb.s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) {
250 ADD_FAILURE() << "Failed to find ext4 superblock on " << fs_blk_device;
251 return false;
252 }
253 static_assert(sizeof(sb.s_uuid) == kFilesystemUuidSize);
254 memcpy(fs_uuid->bytes, sb.s_uuid, kFilesystemUuidSize);
255 } else if (fs_type == "f2fs") {
256 // Android doesn't have an f2fs equivalent of libext4_utils, so we have to
257 // hard-code the offset to the magic number and UUID.
258
259 __le32 magic;
260 if (pread(fd, &magic, sizeof(magic), kF2fsMagicOffset) != sizeof(magic)) {
261 ADD_FAILURE() << "Error reading f2fs superblock from " << fs_blk_device
262 << Errno();
263 return false;
264 }
265 if (magic != cpu_to_le32(F2FS_SUPER_MAGIC)) {
266 ADD_FAILURE() << "Failed to find f2fs superblock on " << fs_blk_device;
267 return false;
268 }
269 if (pread(fd, fs_uuid->bytes, kFilesystemUuidSize, kF2fsUuidOffset) !=
270 kFilesystemUuidSize) {
271 ADD_FAILURE() << "Failed to read f2fs filesystem UUID from "
272 << fs_blk_device << Errno();
273 return false;
274 }
275 } else {
276 ADD_FAILURE() << "Unknown filesystem type " << fs_type;
277 return false;
278 }
279 return true;
280 }
281
282 // Gets the raw block device corresponding to |fs_blk_device| that is one of a
283 // filesystem's mounted block devices. By "raw block device" we mean a block
284 // device from which we can read the encrypted file contents and filesystem
285 // metadata. When metadata encryption is disabled, this is simply
286 // |fs_blk_device|. When metadata encryption is enabled, then |fs_blk_device|
287 // is a dm-default-key device and the "raw block device" is the parent of this
288 // dm-default-key device.
289 //
290 // We don't just use the block device listed in the fstab, because (a) it can be
291 // a logical partition name which needs extra code to map to a block device, and
292 // (b) due to block-level checkpointing, there can be a dm-bow device between
293 // the fstab partition and dm-default-key. dm-bow can remap sectors, but for
294 // encryption testing we don't want any sector remapping. So the correct block
295 // device to read ciphertext from is the one directly underneath dm-default-key.
GetRawBlockDevice(const std::string & fs_blk_device,std::string * raw_blk_device)296 static bool GetRawBlockDevice(const std::string &fs_blk_device,
297 std::string *raw_blk_device) {
298 DeviceMapper &dm = DeviceMapper::Instance();
299
300 if (!dm.IsDmBlockDevice(fs_blk_device)) {
301 GTEST_LOG_(INFO)
302 << fs_blk_device
303 << " is not a device-mapper device; metadata encryption is disabled";
304 *raw_blk_device = fs_blk_device;
305 return true;
306 }
307 const std::optional<std::string> name =
308 dm.GetDmDeviceNameByPath(fs_blk_device);
309 if (!name) {
310 ADD_FAILURE() << "Failed to get name of device-mapper device "
311 << fs_blk_device;
312 return false;
313 }
314
315 std::vector<DeviceMapper::TargetInfo> table;
316 if (!dm.GetTableInfo(*name, &table)) {
317 ADD_FAILURE() << "Failed to get table of device-mapper device " << *name;
318 return false;
319 }
320 if (table.size() != 1) {
321 GTEST_LOG_(INFO) << fs_blk_device
322 << " has multiple device-mapper targets; assuming "
323 "metadata encryption is disabled";
324 *raw_blk_device = fs_blk_device;
325 return true;
326 }
327 const std::string target_type = dm.GetTargetType(table[0].spec);
328 if (target_type != "default-key") {
329 GTEST_LOG_(INFO) << fs_blk_device << " is a dm-" << target_type
330 << " device, not dm-default-key; assuming metadata "
331 "encryption is disabled";
332 *raw_blk_device = fs_blk_device;
333 return true;
334 }
335 std::optional<std::string> parent =
336 dm.GetParentBlockDeviceByPath(fs_blk_device);
337 if (!parent) {
338 ADD_FAILURE() << "Failed to get parent of dm-default-key device " << *name;
339 return false;
340 }
341 *raw_blk_device = *parent;
342 return true;
343 }
344
345 // Gets information about a filesystem's block devices
GetFsBlockDeviceList(FilesystemInfo * fs_info,const std::string & mnt_fsname)346 static bool GetFsBlockDeviceList(FilesystemInfo *fs_info,
347 const std::string &mnt_fsname) {
348 // Add a default block device
349 DiskMapEntry map_entry;
350 map_entry.start_blkaddr = 0;
351 map_entry.end_blkaddr = INT64_MAX - 1;
352 map_entry.fs_blk_device = mnt_fsname;
353
354 if (!GetRawBlockDevice(map_entry.fs_blk_device, &map_entry.raw_blk_device)) {
355 ADD_FAILURE() << "Broken block device path of the default disk";
356 return false;
357 }
358 fs_info->disk_map.push_back(map_entry);
359
360 if (fs_info->type != "f2fs") return true;
361
362 // This requires a kernel patch, f238eff95f48 ("f2fs: add a proc entry show
363 // disk layout"), merged in v6.9
364 static constexpr std::string_view kDevBlockPrefix("/dev/block/");
365 const std::string proc_path = "/proc/fs/f2fs/" +
366 mnt_fsname.substr(kDevBlockPrefix.length()) +
367 "/disk_map";
368 std::ifstream proc_fs(proc_path.c_str());
369 if (!proc_fs.is_open()) {
370 GTEST_LOG_(INFO) << proc_path
371 << " does not exist (expected on pre-6.9 kernels)";
372 return true;
373 }
374
375 std::string line;
376 bool first_device = true;
377 while (std::getline(proc_fs, line)) {
378 if (!android::base::StartsWith(line, "Disk: ")) {
379 continue;
380 }
381 if (first_device) {
382 fs_info->disk_map.erase(fs_info->disk_map.begin());
383 first_device = false;
384 }
385 DiskMapEntry map_entry;
386 std::vector<std::string> data = Split(line, "\t ");
387 if (!ParseInt(data[3], &map_entry.start_blkaddr)) {
388 ADD_FAILURE() << "Broken first block address in the address range";
389 return false;
390 }
391 if (!ParseInt(data[5], &map_entry.end_blkaddr)) {
392 ADD_FAILURE() << "Broken last block address in the address range";
393 return false;
394 }
395 map_entry.fs_blk_device = data[7];
396 if (!GetRawBlockDevice(map_entry.fs_blk_device,
397 &map_entry.raw_blk_device)) {
398 ADD_FAILURE() << "Broken block device path in the disk map entry";
399 return false;
400 }
401 fs_info->disk_map.push_back(map_entry);
402 }
403 return true;
404 }
405
406 // Gets the block device list and type of the filesystem mounted on
407 // |mountpoint|. The block device list has all the block device information
408 // along with the address space ranges configured by the mounted filesystem.
GetFsBlockDeviceListAndType(const std::string & mountpoint,FilesystemInfo * fs_info)409 static bool GetFsBlockDeviceListAndType(const std::string &mountpoint,
410 FilesystemInfo *fs_info) {
411 std::unique_ptr<FILE, int (*)(FILE *)> mnts(setmntent("/proc/mounts", "re"),
412 endmntent);
413 if (!mnts) {
414 ADD_FAILURE() << "Failed to open /proc/mounts" << Errno();
415 return false;
416 }
417 struct mntent *mnt;
418 while ((mnt = getmntent(mnts.get())) != nullptr) {
419 if (mnt->mnt_dir == mountpoint) {
420 fs_info->type = mnt->mnt_type;
421 return GetFsBlockDeviceList(fs_info, mnt->mnt_fsname);
422 }
423 }
424 ADD_FAILURE() << "No /proc/mounts entry found for " << mountpoint;
425 return false;
426 }
427
428 // Gets information about the filesystem mounted on |mountpoint|.
GetFilesystemInfo(const std::string & mountpoint,FilesystemInfo * fs_info)429 bool GetFilesystemInfo(const std::string &mountpoint, FilesystemInfo *fs_info) {
430 if (!GetFsBlockDeviceListAndType(mountpoint, fs_info)) return false;
431
432 // This disk_map[0] always indicates the main block device which the
433 // filesystem contains its superblock.
434 if (!GetFilesystemUuid(fs_info->disk_map[0].fs_blk_device, fs_info->type,
435 &fs_info->uuid))
436 return false;
437
438 GTEST_LOG_(INFO) << " Filesystem mounted on " << mountpoint
439 << " has type: " << fs_info->type << ", UUID is "
440 << BytesToHex(fs_info->uuid.bytes);
441
442 for (const DiskMapEntry &map_entry : fs_info->disk_map) {
443 GTEST_LOG_(INFO) << "Block device: " << map_entry.fs_blk_device << " ("
444 << map_entry.raw_blk_device << ") ranging from "
445 << map_entry.start_blkaddr << " to "
446 << map_entry.end_blkaddr;
447 }
448 return true;
449 }
450
451 // Returns true if the given data seems to be random.
452 //
453 // Check compressibility rather than byte frequencies. Compressibility is a
454 // stronger test since it also detects repetitions.
455 //
456 // To check compressibility, use LZMA rather than DEFLATE/zlib/gzip because LZMA
457 // compression is stronger and supports a much larger dictionary. DEFLATE is
458 // limited to a 32 KiB dictionary. So, data repeating after 32 KiB (or more)
459 // would not be detected with DEFLATE. But LZMA can detect it.
VerifyDataRandomness(const std::vector<uint8_t> & bytes)460 bool VerifyDataRandomness(const std::vector<uint8_t> &bytes) {
461 // To avoid flakiness, allow the data to be compressed a tiny bit by chance.
462 // There is at most a 2^-32 chance that random data can be compressed to be 4
463 // bytes shorter. In practice it's even lower due to compression overhead.
464 size_t destLen = bytes.size() - std::min<size_t>(4, bytes.size());
465 std::vector<uint8_t> dest(destLen);
466 uint8_t outProps[LZMA_PROPS_SIZE];
467 size_t outPropsSize = LZMA_PROPS_SIZE;
468 int ret;
469
470 ret = LzmaCompress(dest.data(), &destLen, bytes.data(), bytes.size(),
471 outProps, &outPropsSize,
472 6, // compression level (0 <= level <= 9)
473 bytes.size(), // dictionary size
474 -1, -1, -1, -1, // lc, lp, bp, fb (-1 selects the default)
475 1); // number of threads
476
477 if (ret == SZ_ERROR_OUTPUT_EOF) return true; // incompressible
478
479 if (ret == SZ_OK) {
480 ADD_FAILURE() << "Data is not random! Compressed " << bytes.size()
481 << " to " << destLen << " bytes";
482 } else {
483 ADD_FAILURE() << "LZMA compression error: ret=" << ret;
484 }
485 return false;
486 }
487
TryPrepareHwWrappedKey(Keymaster & keymaster,const std::string & master_key_string,std::string * exported_key_string,bool rollback_resistance)488 static bool TryPrepareHwWrappedKey(Keymaster &keymaster,
489 const std::string &master_key_string,
490 std::string *exported_key_string,
491 bool rollback_resistance) {
492 // This key is used to drive a CMAC-based KDF
493 auto paramBuilder =
494 km::AuthorizationSetBuilder().AesEncryptionKey(kHwWrappedKeySize * 8);
495 if (rollback_resistance) {
496 paramBuilder.Authorization(km::TAG_ROLLBACK_RESISTANCE);
497 }
498 paramBuilder.Authorization(km::TAG_STORAGE_KEY);
499
500 std::string wrapped_key_blob;
501 if (keymaster.importKey(paramBuilder, master_key_string, &wrapped_key_blob) &&
502 keymaster.exportKey(wrapped_key_blob, exported_key_string)) {
503 return true;
504 }
505 // It's fine for Keymaster not to support hardware-wrapped keys, but
506 // if generateKey works, importKey must too.
507 if (keymaster.generateKey(paramBuilder, &wrapped_key_blob) &&
508 keymaster.exportKey(wrapped_key_blob, exported_key_string)) {
509 ADD_FAILURE() << "generateKey succeeded but importKey failed";
510 }
511 return false;
512 }
513
CreateHwWrappedKey(std::vector<uint8_t> * master_key,std::vector<uint8_t> * exported_key)514 bool CreateHwWrappedKey(std::vector<uint8_t> *master_key,
515 std::vector<uint8_t> *exported_key) {
516 *master_key = GenerateTestKey(kHwWrappedKeySize);
517
518 Keymaster keymaster;
519 if (!keymaster) {
520 ADD_FAILURE() << "Unable to find keymaster";
521 return false;
522 }
523 std::string master_key_string(master_key->begin(), master_key->end());
524 std::string exported_key_string;
525 // Make two attempts to create a key, first with and then without
526 // rollback resistance.
527 if (TryPrepareHwWrappedKey(keymaster, master_key_string, &exported_key_string,
528 true) ||
529 TryPrepareHwWrappedKey(keymaster, master_key_string, &exported_key_string,
530 false)) {
531 exported_key->assign(exported_key_string.begin(),
532 exported_key_string.end());
533 return true;
534 }
535 GTEST_LOG_(INFO) << "Skipping test because device doesn't support "
536 "hardware-wrapped keys";
537 return false;
538 }
539
PushBigEndian32(uint32_t val,std::vector<uint8_t> * vec)540 static void PushBigEndian32(uint32_t val, std::vector<uint8_t> *vec) {
541 for (int i = 24; i >= 0; i -= 8) {
542 vec->push_back((val >> i) & 0xFF);
543 }
544 }
545
RearrangeFixedInputString(KdfVariant kdf_id,std::vector<uint8_t> * fixed_input_string)546 static void RearrangeFixedInputString(
547 KdfVariant kdf_id, std::vector<uint8_t> *fixed_input_string) {
548 if (kdf_id != KDF_VARIANT_REARRANGED) {
549 return;
550 }
551
552 // Rearrange the fixed-input string, reversing the order that the blocks are
553 // processed:
554 // ABCD-EFGH-IJKL-MNO
555 // into
556 // LMNO-HIJK-DEFG-ABC
557 size_t len = fixed_input_string->size();
558 std::vector<uint8_t> tmp(len);
559 for (size_t j = 0; j < len; j += kAesBlockSize) {
560 size_t to_copy = std::min((size_t)kAesBlockSize, len - j);
561 std::copy(fixed_input_string->cbegin() + len - j - to_copy,
562 fixed_input_string->cbegin() + len - j, tmp.begin() + j);
563 }
564 std::copy(tmp.cbegin(), tmp.cend(), fixed_input_string->begin());
565 }
566
GetFixedInputString(KdfVariant kdf_id,uint32_t counter,const std::vector<uint8_t> & label,const std::vector<uint8_t> & context,uint32_t derived_key_len,std::vector<uint8_t> * fixed_input_string)567 static void GetFixedInputString(KdfVariant kdf_id, uint32_t counter,
568 const std::vector<uint8_t> &label,
569 const std::vector<uint8_t> &context,
570 uint32_t derived_key_len,
571 std::vector<uint8_t> *fixed_input_string) {
572 PushBigEndian32(counter, fixed_input_string);
573 fixed_input_string->insert(fixed_input_string->end(), label.begin(),
574 label.end());
575 fixed_input_string->push_back(0);
576 fixed_input_string->insert(fixed_input_string->end(), context.begin(),
577 context.end());
578 PushBigEndian32(derived_key_len, fixed_input_string);
579
580 // If applicable, rearrange the fixed-input string
581 RearrangeFixedInputString(kdf_id, fixed_input_string);
582 }
583
AesCmacKdfHelper(KdfVariant kdf_id,const std::vector<uint8_t> & key,const std::vector<uint8_t> & label,const std::vector<uint8_t> & context,uint32_t output_key_size,std::vector<uint8_t> * output_data)584 static bool AesCmacKdfHelper(KdfVariant kdf_id, const std::vector<uint8_t> &key,
585 const std::vector<uint8_t> &label,
586 const std::vector<uint8_t> &context,
587 uint32_t output_key_size,
588 std::vector<uint8_t> *output_data) {
589 GTEST_LOG_(INFO) << "KDF ID = " << kdf_id;
590 output_data->resize(output_key_size);
591 for (size_t count = 0; count < (output_key_size / kAesBlockSize); count++) {
592 std::vector<uint8_t> fixed_input_string;
593 GetFixedInputString(kdf_id, count + 1, label, context,
594 (output_key_size * 8), &fixed_input_string);
595 GTEST_LOG_(INFO) << "Fixed Input (block: " << count
596 << "): " << BytesToHex(fixed_input_string);
597 if (!AES_CMAC(output_data->data() + (kAesBlockSize * count), key.data(),
598 key.size(), fixed_input_string.data(),
599 fixed_input_string.size())) {
600 ADD_FAILURE()
601 << "AES_CMAC failed while deriving subkey from HW wrapped key";
602 return false;
603 }
604 }
605 return true;
606 }
607
DeriveHwWrappedEncryptionKeyByKdfId(KdfVariant kdf_id,const std::vector<uint8_t> & master_key,std::vector<uint8_t> * enc_key)608 static bool DeriveHwWrappedEncryptionKeyByKdfId(
609 KdfVariant kdf_id, const std::vector<uint8_t> &master_key,
610 std::vector<uint8_t> *enc_key) {
611 std::vector<uint8_t> ctx;
612 std::vector<uint8_t> label;
613 GetKdfContextLabelByKdfId(kdf_id, &ctx, &label);
614 return AesCmacKdfHelper(kdf_id, master_key, label, ctx, kAes256XtsKeySize,
615 enc_key);
616 }
617
DeriveHwWrappedEncryptionKey(const std::vector<uint8_t> & master_key,std::vector<uint8_t> * enc_key)618 bool DeriveHwWrappedEncryptionKey(const std::vector<uint8_t> &master_key,
619 std::vector<uint8_t> *enc_key) {
620 KdfVariant kdf_id;
621 if (!GetKdfVariantId(&kdf_id)) {
622 return false;
623 }
624 return DeriveHwWrappedEncryptionKeyByKdfId(kdf_id, master_key, enc_key);
625 }
626
DeriveHwWrappedRawSecretByKdfId(KdfVariant kdf_id,const std::vector<uint8_t> & master_key,std::vector<uint8_t> * secret)627 static bool DeriveHwWrappedRawSecretByKdfId(
628 KdfVariant kdf_id, const std::vector<uint8_t> &master_key,
629 std::vector<uint8_t> *secret) {
630 std::vector<uint8_t> ctx;
631 std::vector<uint8_t> label;
632 GetSwSecretContextLabelByKdfId(kdf_id, &ctx, &label);
633 return AesCmacKdfHelper(kdf_id, master_key, label, ctx, kAes256KeySize,
634 secret);
635 }
636
DeriveHwWrappedRawSecret(const std::vector<uint8_t> & master_key,std::vector<uint8_t> * secret)637 bool DeriveHwWrappedRawSecret(const std::vector<uint8_t> &master_key,
638 std::vector<uint8_t> *secret) {
639 KdfVariant kdf_id;
640 if (!GetKdfVariantId(&kdf_id)) {
641 return false;
642 }
643 return DeriveHwWrappedRawSecretByKdfId(kdf_id, master_key, secret);
644 }
645
TEST(UtilsTest,TestKdfVariants)646 TEST(UtilsTest, TestKdfVariants) {
647 std::vector<KdfVariant> kdf_ids = {
648 KDF_VARIANT_V1,
649 KDF_VARIANT_LEGACY,
650 KDF_VARIANT_REARRANGED,
651 };
652
653 std::vector<std::vector<uint8_t>> expected_keys = {
654 // "v1"
655 {
656 0xcb, 0xe5, 0xdb, 0x40, 0x21, 0x5a, 0x3d, 0x38, 0x6d, 0x61, 0xe5,
657 0x4e, 0xf2, 0xf8, 0xa7, 0x81, 0x4b, 0x00, 0xba, 0xcf, 0x35, 0xb3,
658 0x16, 0xf8, 0x8e, 0x68, 0xe8, 0x9a, 0x47, 0xab, 0xba, 0xb4, 0x83,
659 0x4c, 0x27, 0xda, 0xc8, 0xa9, 0x1a, 0xe1, 0xc3, 0x30, 0x4f, 0x31,
660 0xb5, 0xf2, 0x20, 0x2c, 0x14, 0x98, 0x96, 0x61, 0xba, 0xfc, 0xcc,
661 0x56, 0xcf, 0x62, 0x12, 0xd8, 0xb1, 0xf7, 0x26, 0x91,
662 },
663 // "legacykdf"
664 {
665 0x63, 0x61, 0xf8, 0x02, 0xb3, 0x7a, 0xa6, 0x4a, 0x07, 0x57, 0x84,
666 0xbe, 0xde, 0x23, 0x41, 0xf1, 0xd9, 0x23, 0x6e, 0x64, 0x6c, 0x70,
667 0x46, 0x0f, 0x15, 0xb3, 0x7c, 0xe5, 0xff, 0x43, 0xa5, 0x4f, 0x15,
668 0xd9, 0x56, 0x93, 0x34, 0x3d, 0x52, 0x8b, 0x67, 0x37, 0x2a, 0x7f,
669 0x38, 0x3e, 0xd8, 0xe7, 0xc4, 0x5e, 0xd0, 0x89, 0x9e, 0x02, 0x82,
670 0x54, 0x53, 0xc9, 0x41, 0x9a, 0xaf, 0xa3, 0x69, 0x5f,
671 },
672 // "rearranged"
673 {
674 0xdb, 0xa0, 0xa6, 0x7e, 0x47, 0x1b, 0xe3, 0x9f, 0xd1, 0xec, 0x28,
675 0x99, 0x45, 0xf5, 0x21, 0x45, 0xdf, 0x12, 0x93, 0x7a, 0x0b, 0x42,
676 0x91, 0x5f, 0x7c, 0x71, 0x1f, 0xeb, 0x47, 0x40, 0x3e, 0x6a, 0xe5,
677 0xb7, 0xb5, 0x29, 0x68, 0xa8, 0xcc, 0x63, 0x5d, 0x10, 0xab, 0x8b,
678 0x87, 0x24, 0xef, 0x5d, 0xec, 0x62, 0x36, 0xd8, 0x1a, 0x1b, 0x38,
679 0x78, 0x08, 0xc4, 0x07, 0xce, 0x01, 0xc5, 0x63, 0x88,
680 },
681 };
682
683 std::vector<std::vector<uint8_t>> expected_secrets = {
684 // "v1"
685 {
686 0xe2, 0x6f, 0xb1, 0x9b, 0x4f, 0xb6, 0x26, 0x6f, 0xc7, 0xc5, 0xfc,
687 0x96, 0x54, 0xef, 0xad, 0x64, 0x3c, 0xfe, 0xbc, 0x64, 0xc0, 0x97,
688 0x34, 0x11, 0x55, 0x19, 0x55, 0x95, 0xc2, 0x8d, 0x5e, 0xc9,
689 },
690 // "legacykdf"
691 {
692 0xe2, 0x6f, 0xb1, 0x9b, 0x4f, 0xb6, 0x26, 0x6f, 0xc7, 0xc5, 0xfc,
693 0x96, 0x54, 0xef, 0xad, 0x64, 0x3c, 0xfe, 0xbc, 0x64, 0xc0, 0x97,
694 0x34, 0x11, 0x55, 0x19, 0x55, 0x95, 0xc2, 0x8d, 0x5e, 0xc9,
695 },
696 // "rearranged"
697 {
698 0x4e, 0xf0, 0x6e, 0x6a, 0xa9, 0x84, 0x10, 0x46, 0x67, 0x86, 0x3f,
699 0x15, 0x08, 0x7c, 0x12, 0xbb, 0xfb, 0x8e, 0x47, 0x15, 0x14, 0x5b,
700 0xc0, 0x6b, 0x59, 0x82, 0xab, 0xd4, 0x19, 0x83, 0x85, 0xb4,
701 },
702 };
703
704 ASSERT_EQ(kdf_ids.size(), KDF_VARIANT_COUNT);
705 ASSERT_EQ(expected_keys.size(), KDF_VARIANT_COUNT);
706 ASSERT_EQ(expected_secrets.size(), KDF_VARIANT_COUNT);
707
708 const std::vector<uint8_t> master_key = {
709 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
710 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
711 };
712
713 GTEST_LOG_(INFO) << "Master Key: " << BytesToHex(master_key);
714 for (size_t i = 0; i < KDF_VARIANT_COUNT; i++) {
715 std::vector<uint8_t> out_key;
716 EXPECT_TRUE(
717 DeriveHwWrappedEncryptionKeyByKdfId(kdf_ids[i], master_key, &out_key));
718 GTEST_LOG_(INFO) << "Key (id: " << i << "): " << BytesToHex(out_key);
719 GTEST_LOG_(INFO) << "Exp Key (id: " << i
720 << "): " << BytesToHex(expected_keys[i]);
721 EXPECT_EQ(out_key, expected_keys[i]);
722 std::vector<uint8_t> out_sec;
723 EXPECT_TRUE(
724 DeriveHwWrappedRawSecretByKdfId(kdf_ids[i], master_key, &out_sec));
725 GTEST_LOG_(INFO) << "Secret (id: " << i << "): " << BytesToHex(out_sec);
726 GTEST_LOG_(INFO) << "Exp Secret (id: " << i
727 << "): " << BytesToHex(expected_secrets[i]);
728 EXPECT_EQ(out_sec, expected_secrets[i]);
729 }
730 }
731
732 } // namespace kernel
733 } // namespace android
734