11c49b8525757f490fa396e5985c2ac9e3d168e6
[platform/core/security/ode.git] / server / upgrade-support.cpp
1 /*
2  *  Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
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 "upgrade-support.h"
18
19 #include <sys/types.h>
20 #include <dirent.h>
21 #include <dlfcn.h>
22 #include <fcntl.h>
23
24 #include <string>
25 #include <algorithm>
26 #include <memory>
27 #include <mutex>
28
29 #include <klay/filesystem.h>
30 #include <klay/exception.h>
31
32 #include <rmi/common.h>
33
34 #include <logger.h>
35 #include <ode-key-storage-plugin/ode-key-storage-plugin.h>
36
37 namespace ode {
38
39 namespace {
40
41 extern "C" {
42 typedef int(*KeyStoragePluginStoreFn)(const unsigned char*, size_t,
43                                                                           unsigned char**, size_t*);
44 typedef int(*KeyStoragePluginLoadFn)(const unsigned char*, size_t,
45                                                                          unsigned char**, size_t*);
46 typedef int(*KeyStoragePluginRemoveFn)(const unsigned char*, size_t);
47 }
48
49 std::mutex opGuard;
50
51 // not thread-safe because of static member
52 class KeyStoragePlugin {
53 public:
54         explicit KeyStoragePlugin();
55
56         KeyStoragePlugin(KeyStoragePlugin&&) = default;
57
58         KeyStoragePlugin(const KeyStoragePlugin&) = delete;
59         KeyStoragePlugin& operator=(const KeyStoragePlugin&) = delete;
60
61         ~KeyStoragePlugin();
62
63         static KeyStoragePlugin& Instance();
64
65         BinaryData store(const BinaryData& key);
66         BinaryData load(const BinaryData& token);
67         void remove(const BinaryData& token);
68
69 private:
70         void* so;
71         KeyStoragePluginStoreFn storeFn;
72         KeyStoragePluginLoadFn loadFn;
73         KeyStoragePluginRemoveFn removeFn;
74
75         static std::unique_ptr<KeyStoragePlugin> plugin;
76 };
77
78 std::unique_ptr<KeyStoragePlugin> KeyStoragePlugin::plugin;
79
80 KeyStoragePlugin& KeyStoragePlugin::Instance()
81 {
82         if (!plugin)
83                 plugin.reset(new KeyStoragePlugin());
84
85         return *plugin;
86 }
87
88 KeyStoragePlugin::KeyStoragePlugin() : so(NULL)
89 {
90         std::string path = std::string(KEY_STORAGE_PLUGIN_DIR) + "/" + KEY_STORAGE_PLUGIN_LIB;
91
92         so = ::dlopen(path.c_str(), RTLD_LAZY);
93         if (so == NULL)
94                 throw runtime::Exception(std::string("Failed to load library: ") +
95                                                                  path + ". Error: " + ::dlerror());
96
97         storeFn = reinterpret_cast<KeyStoragePluginStoreFn>(::dlsym(so, "ode_ksp_store"));
98         if (storeFn == NULL)
99                 throw runtime::Exception(
100                         std::string("ode_ksp_store() symbol not found. Error: ") + ::dlerror());
101
102         loadFn = reinterpret_cast<KeyStoragePluginLoadFn>(::dlsym(so, "ode_ksp_load"));
103         if (loadFn == NULL)
104                 throw runtime::Exception(
105                         std::string("ode_ksp_load() symbol not found. Error: ") + ::dlerror());
106
107         removeFn = reinterpret_cast<KeyStoragePluginRemoveFn>(::dlsym(so, "ode_ksp_remove"));
108         if (removeFn == NULL)
109                 throw runtime::Exception(
110                         std::string("ode_ksp_remove() symbol not found. Error: ") + ::dlerror());
111 }
112
113 KeyStoragePlugin::~KeyStoragePlugin()
114 {
115         ::dlclose(so);
116 }
117
118 BinaryData KeyStoragePlugin::store(const BinaryData& key)
119 {
120         unsigned char* token = NULL;
121         size_t token_len = 0;
122         int ret = storeFn(key.data(), key.size(), &token, &token_len);
123         if (ret != ODE_KSP_ERROR_NONE)
124                 throw runtime::Exception(std::string("Storing the key failed with ") +
125                                                                  std::to_string(ret));
126
127         BinaryData tokenVector(token, token + token_len);
128         free(token);
129         return tokenVector;
130 }
131
132 BinaryData KeyStoragePlugin::load(const BinaryData& token)
133 {
134         unsigned char* key = NULL;
135         size_t key_len = 0;
136         int ret = loadFn(token.data(), token.size(), &key, &key_len);
137         if (ret != ODE_KSP_ERROR_NONE)
138                 throw runtime::Exception(std::string("Loading the key failed with ") +
139                                                                  std::to_string(ret));
140
141         BinaryData keyVector(key, key + key_len);
142         free(key);
143         return keyVector;
144 }
145
146 void KeyStoragePlugin::remove(const BinaryData& token)
147 {
148         int ret = removeFn(token.data(), token.size());
149         if (ret == ODE_KSP_ERROR_NO_SUCH_FILE) {
150                 INFO(SINK, "Key storage plugin does not recognize the token. Ignoring.");
151                 return;
152         }
153         if (ret != ODE_KSP_ERROR_NONE)
154                 throw runtime::Exception(std::string("Removing the key failed with ") +
155                                                                  std::to_string(ret));
156 }
157
158 std::string getTokenFileName(const std::string &device)
159 {
160         std::string filename(device);
161         std::replace(filename.begin(), filename.end(), '/', '_');
162
163         return std::string("/opt/etc/.ode_token") + filename;
164 }
165
166 void readToken(runtime::File &file, BinaryData& token)
167 {
168         size_t tokenSize;
169
170         if (!file.exists()) {
171                 token.clear();
172                 return;
173         }
174         file.open(O_RDONLY);
175
176         file.read(&tokenSize, sizeof(tokenSize));
177         token.resize(tokenSize);
178         file.read(token.data(), tokenSize);
179
180         file.close();
181 }
182
183 void writeToken(runtime::File &file, const BinaryData& token)
184 {
185         size_t tokenSize(token.size());
186
187         file.create(0600);
188
189         file.write(&tokenSize, sizeof(tokenSize));
190         file.write(token.data(), token.size());
191
192         file.close();
193 }
194
195 } // anonymous namespace
196
197 namespace UpgradeSupport {
198
199 void storeMasterKey(const std::string &device, const BinaryData& key)
200 {
201         std::lock_guard<std::mutex> lock(opGuard);
202
203         BinaryData token;
204
205         runtime::File file(getTokenFileName(device));
206         readToken(file, token);
207
208         auto& up = KeyStoragePlugin::Instance();
209
210         // remove previous entry if necessary
211         if (!token.empty())
212                 up.remove(token);
213
214         token = up.store(key);
215
216         writeToken(file, token);
217 }
218
219 BinaryData loadMasterKey(const std::string &device)
220 {
221         BinaryData token;
222
223         std::lock_guard<std::mutex> lock(opGuard);
224
225         runtime::File file(getTokenFileName(device));
226         readToken(file, token);
227
228         if (token.empty())
229                 throw runtime::Exception("Token opening failed");
230
231         auto& up = KeyStoragePlugin::Instance();
232         return up.load(token);
233 }
234
235 void removeMasterKey(const std::string &device)
236 {
237         BinaryData token;
238
239         std::lock_guard<std::mutex> lock(opGuard);
240
241         runtime::File file(getTokenFileName(device));
242         readToken(file, token);
243
244         // already removed
245         if (token.empty()) {
246                 INFO(SINK, "Token for " + device + " does not exist. Ignoring.");
247                 return;
248         }
249
250         auto& up = KeyStoragePlugin::Instance();
251         up.remove(token);
252
253         file.remove();
254 }
255
256 } // namespace UpgradeSupport
257
258 } // namespace ode