1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "fscrypt_key_v1.h"
17
18 #include <openssl/sha.h>
19
20 #include "libfscrypt/key_control.h"
21 #include "storage_service_log.h"
22
23 namespace OHOS {
24 namespace StorageDaemon {
25 static const std::string CRYPTO_NAME_PREFIXES[] = {"ext4", "f2fs", "fscrypt"};
26
ActiveKey(uint32_t flag,const std::string & mnt)27 bool FscryptKeyV1::ActiveKey(uint32_t flag, const std::string &mnt)
28 {
29 (void)mnt;
30 LOGD("enter");
31 if (!GenerateKeyDesc()) {
32 LOGE("GenerateKeyDesc failed");
33 return false;
34 }
35
36 if (!fscryptV1Ext.ActiveKeyExt(flag, keyInfo_.key.data.get(), keyInfo_.key.size)) {
37 LOGE("fscryptV1Ext ActiveKeyExtfailed");
38 return false;
39 }
40 if (!InstallKeyToKeyring()) {
41 LOGE("InstallKeyToKeyring failed");
42 return false;
43 }
44 LOGD("success");
45 return true;
46 }
47
InstallKeyToKeyring()48 bool FscryptKeyV1::InstallKeyToKeyring()
49 {
50 fscrypt_key fskey;
51 fskey.mode = FS_ENCRYPTION_MODE_AES_256_XTS;
52 fskey.size = keyInfo_.key.size;
53 auto err = memcpy_s(fskey.raw, FS_MAX_KEY_SIZE, keyInfo_.key.data.get(), keyInfo_.key.size);
54 if (err != EOK) {
55 LOGE("memcpy failed ret %{public}d", err);
56 return false;
57 }
58
59 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
60 if (krid == -1) {
61 LOGI("no session keyring for fscrypt");
62 krid = KeyCtrlAddKey("keyring", "fscrypt", KEY_SPEC_SESSION_KEYRING);
63 if (krid == -1) {
64 LOGE("failed to add session keyring");
65 return false;
66 }
67 }
68 for (auto prefix : CRYPTO_NAME_PREFIXES) {
69 std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
70 key_serial_t ks =
71 KeyCtrlAddKeyEx("logon", keyref.c_str(), &fskey, krid);
72 if (ks == -1) {
73 // Addkey failed, need to process the error
74 LOGE("Failed to AddKey %{public}s into keyring %{public}d, errno %{public}d", keyref.c_str(), krid,
75 errno);
76 }
77 }
78 if (!SaveKeyBlob(keyInfo_.keyDesc, dir_ + PATH_KEYDESC)) {
79 return false;
80 }
81 keyInfo_.key.Clear();
82 LOGD("success");
83 return true;
84 }
85
InactiveKey(uint32_t flag,const std::string & mnt)86 bool FscryptKeyV1::InactiveKey(uint32_t flag, const std::string &mnt)
87 {
88 (void)mnt;
89 LOGD("enter");
90 bool ret = true;
91
92 if (!UninstallKeyToKeyring()) {
93 LOGE("UninstallKeyToKeyring failed");
94 ret = false;
95 }
96 if (!fscryptV1Ext.InactiveKeyExt(flag)) {
97 LOGE("fscryptV1Ext InactiveKeyExt failed");
98 ret = false;
99 }
100 LOGD("finish");
101 return ret;
102 }
103
UninstallKeyToKeyring()104 bool FscryptKeyV1::UninstallKeyToKeyring()
105 {
106 if (keyInfo_.keyDesc.IsEmpty()) {
107 LOGE("keyDesc is null, key not installed?");
108 return false;
109 }
110
111 key_serial_t krid = KeyCtrlSearch(KEY_SPEC_SESSION_KEYRING, "keyring", "fscrypt", 0);
112 if (krid == -1) {
113 LOGE("Error searching session keyring for fscrypt-provisioning key for fscrypt");
114 return false;
115 }
116 for (auto prefix : CRYPTO_NAME_PREFIXES) {
117 std::string keyref = prefix + ":" + keyInfo_.keyDesc.ToString();
118 key_serial_t ks = KeyCtrlSearch(krid, "logon", keyref.c_str(), 0);
119 if (KeyCtrlUnlink(ks, krid) != 0) {
120 LOGE("Failed to unlink key with serial %{public}d ref %{public}s", krid, keyref.c_str());
121 }
122 }
123
124 LOGD("success");
125 return true;
126 }
127
GenerateKeyDesc()128 bool FscryptKeyV1::GenerateKeyDesc()
129 {
130 if (keyInfo_.key.IsEmpty()) {
131 LOGE("key is empty");
132 return false;
133 }
134 SHA512_CTX c;
135
136 SHA512_Init(&c);
137 SHA512_Update(&c, keyInfo_.key.data.get(), keyInfo_.key.size);
138 uint8_t keyRef1[SHA512_DIGEST_LENGTH] = { 0 };
139 SHA512_Final(keyRef1, &c);
140
141 SHA512_Init(&c);
142 SHA512_Update(&c, keyRef1, SHA512_DIGEST_LENGTH);
143 uint8_t keyRef2[SHA512_DIGEST_LENGTH] = { 0 };
144 SHA512_Final(keyRef2, &c);
145
146 static_assert(SHA512_DIGEST_LENGTH >= CRYPTO_KEY_DESC_SIZE, "Hash too short for descriptor");
147 keyInfo_.keyDesc.Alloc(CRYPTO_KEY_DESC_SIZE);
148 auto err = memcpy_s(keyInfo_.keyDesc.data.get(), keyInfo_.keyDesc.size, keyRef2, CRYPTO_KEY_DESC_SIZE);
149 if (err != EOK) {
150 LOGE("memcpy failed ret %{public}d", err);
151 return false;
152 }
153 return true;
154 }
155 } // namespace StorageDaemon
156 } // namespace OHOS
157