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