Coding style applied according to style checker
[platform/core/security/key-manager.git] / tests / encryption-scheme / scheme-test.cpp
1 /*
2  *  Copyright (c) 2015 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  * @file       scheme-test.cpp
18  * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
19  * @version    1.0
20  */
21 #include <scheme-test.h>
22
23 #include <sys/smack.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/sendfile.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <grp.h>
31 #include <pwd.h>
32
33 #include <fstream>
34 #include <stdexcept>
35 #include <vector>
36
37 #include <boost/test/unit_test.hpp>
38
39 #include <smack-access.h>
40
41 #include <db-crypto.h>
42 #include <file-system.h>
43 #include <key-provider.h>
44 #include <db-row.h>
45 #include <crypto-init.h>
46 #include <dpl/errno_string.h>
47
48 using namespace CKM;
49 using namespace std;
50
51 namespace {
52 const uid_t UID = 7654;
53 const gid_t GID = 7654;
54 const char *const DBPASS = "db-pass";
55 const char *const LABEL = "my-label";
56 const Label DB_LABEL = "/" + string(LABEL);
57 const int ENC_SCHEME_OFFSET = 24;
58 const string TEST_DATA_STR = "test-data";
59 RawBuffer TEST_DATA(TEST_DATA_STR.begin(), TEST_DATA_STR.end());
60 const Password TEST_PASS = "custom user password";
61 const size_t IV_LEN = 16;
62 const size_t CHAIN_LEN = 3;
63
64 enum {
65         NO_PASS = 0,
66         PASS = 1
67 };
68
69 enum {
70         NO_EXP = 0,
71         EXP = 1
72 };
73
74 // [password][exportable]
75 Policy policy[2][2] = {
76         {{ Password(), false }, { Password(), true }},
77         {{ TEST_PASS,  false }, { TEST_PASS,  true }},
78 };
79
80 struct Group {
81         enum {
82                 SINGLE_ITEM,
83                 KEY_PAIR_RSA,
84                 CERT_CHAIN
85         } type;
86         Items items;
87 };
88
89 Group GROUPS[] = {
90         // Data
91         {
92                 Group::SINGLE_ITEM, {
93                         Item("data-alias1", DataType::BINARY_DATA,  policy[NO_PASS][EXP])
94                 }
95         },
96         {
97                 Group::SINGLE_ITEM, {
98                         Item("data-alias2", DataType::BINARY_DATA,  policy[PASS][EXP])
99                 }
100         },
101
102         // RSA keys
103         {
104                 Group::KEY_PAIR_RSA, {
105                         Item("key-rsa-alias-prv1", DataType::KEY_RSA_PRIVATE,  policy[NO_PASS][NO_EXP]),
106                         Item("key-rsa-alias-pub1", DataType::KEY_RSA_PUBLIC,   policy[NO_PASS][NO_EXP])
107                 }
108         },
109         {
110                 Group::KEY_PAIR_RSA, {
111                         Item("key-rsa-alias-prv2", DataType::KEY_RSA_PRIVATE,  policy[NO_PASS][EXP]),
112                         Item("key-rsa-alias-pub2", DataType::KEY_RSA_PUBLIC,   policy[NO_PASS][EXP]),
113                 }
114         },
115         {
116                 Group::KEY_PAIR_RSA, {
117                         Item("key-rsa-alias-prv3", DataType::KEY_RSA_PRIVATE,  policy[PASS][NO_EXP]),
118                         Item("key-rsa-alias-pub3", DataType::KEY_RSA_PUBLIC,   policy[PASS][NO_EXP]),
119                 }
120         },
121         {
122                 Group::KEY_PAIR_RSA, {
123                         Item("key-rsa-alias-prv4", DataType::KEY_RSA_PRIVATE,  policy[PASS][EXP]),
124                         Item("key-rsa-alias-pub4", DataType::KEY_RSA_PUBLIC,   policy[PASS][EXP]),
125                 }
126         },
127         // different policies
128         {
129                 Group::KEY_PAIR_RSA, {
130                         Item("key-rsa-alias-prv5", DataType::KEY_RSA_PRIVATE,  policy[PASS][NO_EXP]),
131                         Item("key-rsa-alias-pub5", DataType::KEY_RSA_PUBLIC,   policy[NO_PASS][EXP]),
132                 }
133         },
134
135         // AES
136         {
137                 Group::SINGLE_ITEM, {
138                         Item("key-aes-alias1",     DataType::KEY_AES,          policy[NO_PASS][NO_EXP]),
139                 }
140         },
141         {
142                 Group::SINGLE_ITEM, {
143                         Item("key-aes-alias2",     DataType::KEY_AES,          policy[NO_PASS][EXP]),
144                 }
145         },
146         {
147                 Group::SINGLE_ITEM, {
148                         Item("key-aes-alias3",     DataType::KEY_AES,          policy[PASS][NO_EXP]),
149                 }
150         },
151         {
152                 Group::SINGLE_ITEM, {
153                         Item("key-aes-alias4",     DataType::KEY_AES,          policy[PASS][EXP]),
154                 }
155         },
156
157         // Certificates
158         {
159                 Group::CERT_CHAIN, {
160                         Item("cert-root-alias1",   DataType::CERTIFICATE,      policy[NO_PASS][NO_EXP]),
161                         Item("cert-im-ca-alias1",  DataType::CERTIFICATE,      policy[NO_PASS][NO_EXP]),
162                         Item("cert-leaf-alias1",   DataType::CERTIFICATE,      policy[NO_PASS][NO_EXP]),
163                 }
164         },
165         {
166                 Group::CERT_CHAIN, {
167                         Item("cert-root-alias2",   DataType::CERTIFICATE,      policy[NO_PASS][EXP]),
168                         Item("cert-im-ca-alias2",  DataType::CERTIFICATE,      policy[NO_PASS][EXP]),
169                         Item("cert-leaf-alias2",   DataType::CERTIFICATE,      policy[NO_PASS][EXP]),
170                 }
171         },
172         {
173                 Group::CERT_CHAIN, {
174                         Item("cert-root-alias3",   DataType::CERTIFICATE,      policy[PASS][NO_EXP]),
175                         Item("cert-im-ca-alias3",  DataType::CERTIFICATE,      policy[PASS][NO_EXP]),
176                         Item("cert-leaf-alias3",   DataType::CERTIFICATE,      policy[PASS][NO_EXP]),
177                 }
178         },
179         {
180                 Group::CERT_CHAIN, {
181                         Item("cert-root-alias4",   DataType::CERTIFICATE,      policy[PASS][EXP]),
182                         Item("cert-im-ca-alias4",  DataType::CERTIFICATE,      policy[PASS][EXP]),
183                         Item("cert-leaf-alias4",   DataType::CERTIFICATE,      policy[PASS][EXP]),
184                 }
185         },
186
187         // PKCS
188         {
189                 Group::SINGLE_ITEM, {
190                         Item("pkcs-alias1",        DataType::CHAIN_CERT_0,     policy[NO_PASS][NO_EXP]),
191                 }
192         },
193         {
194                 Group::SINGLE_ITEM, {
195                         Item("pkcs-alias2",        DataType::CHAIN_CERT_0,     policy[NO_PASS][EXP]),
196                 }
197         },
198         {
199                 Group::SINGLE_ITEM, {
200                         Item("pkcs-alias3",        DataType::CHAIN_CERT_0,     policy[PASS][NO_EXP]),
201                 }
202         },
203         {
204                 Group::SINGLE_ITEM, {
205                         Item("pkcs-alias4",        DataType::CHAIN_CERT_0,     policy[PASS][EXP]),
206                 }
207         },
208 };
209
210 const size_t CHAIN_SIZE = 3;
211
212 // TEST_ROOT_CA, expires 2035
213 std::string TEST_ROOT_CA =
214         "-----BEGIN CERTIFICATE-----\n"
215         "MIIDnzCCAoegAwIBAgIJAMH/ADkC5YSTMA0GCSqGSIb3DQEBBQUAMGYxCzAJBgNV\n"
216         "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQKDARBQ01FMRAwDgYD\n"
217         "VQQLDAdUZXN0aW5nMSEwHwYDVQQDDBhUZXN0IHJvb3QgY2EgY2VydGlmaWNhdGUw\n"
218         "HhcNMTQxMjMwMTcyMTUyWhcNMjQxMjI3MTcyMTUyWjBmMQswCQYDVQQGEwJBVTET\n"
219         "MBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UECgwEQUNNRTEQMA4GA1UECwwHVGVz\n"
220         "dGluZzEhMB8GA1UEAwwYVGVzdCByb290IGNhIGNlcnRpZmljYXRlMIIBIjANBgkq\n"
221         "hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0EJRdUtd2th0vTVF7QxvDKzyFCF3w9vC\n"
222         "9IDE/Yr12w+a9jd0s7/eG96qTHIYffS3B7x2MB+d4n+SR3W0qmYh7xk8qfEgH3da\n"
223         "eDoV59IZ9r543KM+g8jm6KffYGX1bIJVVY5OhBRbO9nY6byYpd5kbCIUB6dCf7/W\n"
224         "rQl1aIdLGFIegAzPGFPXDcU6F192686x54bxt/itMX4agHJ9ZC/rrTBIZghVsjJo\n"
225         "5/AH5WZpasv8sfrGiiohAxtieoYoJkv5MOYP4/2lPlOY+Cgw1Yoz+HHv31AllgFs\n"
226         "BquBb/kJVmCCNsAOcnvQzTZUsW/TXz9G2nwRdqI1nSy2JvVjZGsqGQIDAQABo1Aw\n"
227         "TjAdBgNVHQ4EFgQUt6pkzFt1PZlfYRL/HGnufF4frdwwHwYDVR0jBBgwFoAUt6pk\n"
228         "zFt1PZlfYRL/HGnufF4frdwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC\n"
229         "AQEAld7Qwq0cdzDQ51w1RVLwTR8Oy25PB3rzwEHcSGJmdqlMi3xOdaz80S1R1BBX\n"
230         "ldvGBG5Tn0vT7xSuhmSgI2/HnBpy9ocHVOmhtNB4473NieEpfTYrnGXrFxu46Wus\n"
231         "9m/ZnugcQ2G6C54A/NFtvgLmaC8uH8M7gKdS6uYUwJFQEofkjmd4UpOYSqmcRXhS\n"
232         "Jzd5FYFWkJhKJYp3nlENSOD8CUFFVGekm05nFN2gRVc/qaqQkEX77+XYvhodLRsV\n"
233         "qMn7nf7taidDKLO2T4bhujztnTYOhhaXKgPy7AtZ28N2wvX96VyAPB/vrchGmyBK\n"
234         "kOg11TpPdNDkhb1J4ZCh2gupDg==\n"
235         "-----END CERTIFICATE-----\n";
236
237 // TEST_IM_CA, signed by TEST_ROOT_CA, expires 2035
238 std::string TEST_IM_CA =
239         "-----BEGIN CERTIFICATE-----\n"
240         "MIIDljCCAn6gAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwZjELMAkGA1UEBhMCQVUx\n"
241         "EzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAoMBEFDTUUxEDAOBgNVBAsMB1Rl\n"
242         "c3RpbmcxITAfBgNVBAMMGFRlc3Qgcm9vdCBjYSBjZXJ0aWZpY2F0ZTAeFw0xNTAx\n"
243         "MTYxNjQ1MzRaFw0zNTAxMTExNjQ1MzRaMGQxCzAJBgNVBAYTAkFVMRMwEQYDVQQI\n"
244         "DApTb21lLVN0YXRlMQ0wCwYDVQQKDARBQ01FMRAwDgYDVQQLDAdUZXN0aW5nMR8w\n"
245         "HQYDVQQDDBZUZXN0IElNIENBIGNlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEF\n"
246         "AAOCAQ8AMIIBCgKCAQEAzmBF78qClgoKfnLAncMXZwZ14TW+5kags1+QCYeg3c7j\n"
247         "L9+RvDxIaX2tKf1sukJcwQfYqUlQkwt+58LMOb2ORtkpj8Or6WCWCZ0BzneT8ug7\n"
248         "nxJT4m9+bohMF0JoKjjB2H4KNMHamLIwUxRKt6nyfk81kVhJOi2vzzxd+UCPi6Pc\n"
249         "UAbJNH48eNgOIg55nyFovVzYj8GIo/9GvHJj83PPa/KlJZ+Z1qZASZZ/VYorplVT\n"
250         "thsHXKfejhFy5YJ9t7n/vyAQsyBsagZsvX19xnH41fbYXHKf8UbXG23rNaZlchs6\n"
251         "XJVLQdzOpj3WTj/lCocVHqLaZISLhNQ3aI7kUBUdiwIDAQABo1AwTjAdBgNVHQ4E\n"
252         "FgQUoCYNaCBP4jl/3SYQuK8Ka+6i3QEwHwYDVR0jBBgwFoAUt6pkzFt1PZlfYRL/\n"
253         "HGnufF4frdwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjRzWiD97\n"
254         "Htv4Kxpm3P+C+xP9AEteCJfO+7p8MWgtWEJOknJyt55zeKS2JwZIq57KcbqD8U7v\n"
255         "vAUx1ymtUhlFPFd7J1mJ3pou+3aFYmGShYhGHpbrmUwjp7HVP588jrW1NoZVHdMc\n"
256         "4OgJWFrViXeu9+maIcekjMB/+9Y0dUgQuK5ZuT5H/Jwet7Th/o9uufTUZjBzRvrB\n"
257         "pbXgQpqgME2av4Q/6LuldPCTHLtWXgFUU2R+yCGmuGilvhFJnKoQryAbYnIQNWE8\n"
258         "SLoHQ9s1i7Zyb7HU6UAaqMOz15LBkyAqtNyJcO2p7Q/p5YK0xfD4xisI5qXucqVm\n"
259         "F2obL5qJSTN/RQ==\n"
260         "-----END CERTIFICATE-----\n";
261
262 // TEST_LEAF, signed by TEST_IM_CA, expires 2035
263 std::string TEST_LEAF =
264         "-----BEGIN CERTIFICATE-----\n"
265         "MIIDOzCCAiMCAQEwDQYJKoZIhvcNAQEFBQAwZDELMAkGA1UEBhMCQVUxEzARBgNV\n"
266         "BAgMClNvbWUtU3RhdGUxDTALBgNVBAoMBEFDTUUxEDAOBgNVBAsMB1Rlc3Rpbmcx\n"
267         "HzAdBgNVBAMMFlRlc3QgSU0gQ0EgY2VydGlmaWNhdGUwHhcNMTUwMTE2MTY0ODE0\n"
268         "WhcNMzUwMTExMTY0ODE0WjBjMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1T\n"
269         "dGF0ZTENMAsGA1UECgwEQUNNRTEQMA4GA1UECwwHVGVzdGluZzEeMBwGA1UEAwwV\n"
270         "VGVzdCBsZWFmIGNlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"
271         "CgKCAQEAzTdDIa2tDmRxFnIgiG+mBz8GoSVODs0ImNQGbqj+pLhBOFRH8fsah4Jl\n"
272         "z5YF9KwhMVLknnHGFLE/Nb7Ac35kEzhMQMpTRxohW83oxw3eZ8zN/FBoKqg4qHRq\n"
273         "QR8kS10YXTgrBR0ex/Vp+OUKEw6h7yL2r4Tpvrn9/qHwsxtLxqWbDIVf1O9b1Lfc\n"
274         "bllYMdmV5E62yN5tcwrDP8gvHjFnVeLzrG8wTpc9FR90/0Jkfp5jAJcArOBLrT0E\n"
275         "4VRqs+4HuwT8jAwFAmNnc7IYX5qSjtSWkmmHe73K/lzB+OiI0JEc/3eWUTWqwTSk\n"
276         "4tNCiQGBKJ39LXPTBBJdzmxVH7CUDQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQAp\n"
277         "UdDOGu3hNiG+Vn10aQ6B1ZmOj3t+45gUV3sC+y8hB8EK1g4P5Ke9bVDts0T5eOnj\n"
278         "CSc+6VoND5O4adI0IFFRFljHNVnvjeosHfUZNnowsmA2ptQBtC1g5ZKRvKXlkC5/\n"
279         "i5BGgRqPFA7y9WB9Y05MrJHf3E+Oz/RBsLeeNiNN+rF5X1vYExvGHpo0M0zS0ze9\n"
280         "HtC0aOy8ocsTrQkf3ceHTAXx2i8ftoSSD4klojtWFpWMrNQa52F7wB9nU6FfKRuF\n"
281         "Zj/T1JkYXKkEwZU6nAR2jdZp3EP9xj3o15V/tyFcXHx6l8NTxn4cJb+Xe4VquQJz\n"
282         "6ON7PVe0ABN/AlwVQiFE\n"
283         "-----END CERTIFICATE-----\n";
284
285
286
287 struct FdCloser {
288         void operator()(int *fd)
289         {
290                 if (fd)
291                         close(*fd);
292         }
293 };
294
295 typedef std::unique_ptr<int, FdCloser> FdPtr;
296
297 uid_t getUid(const char *name)
298 {
299         struct passwd pwd;
300         struct passwd *result = nullptr;
301         int bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
302
303         if (bufsize <= 0)
304                 bufsize = 16384; /* should be more than enough */
305
306         memset(&pwd, 0x00, sizeof(pwd));
307
308         std::vector<char> buf(bufsize, 0);
309
310         int ret = getpwnam_r(name, &pwd, buf.data(), bufsize, &result);
311         BOOST_REQUIRE_MESSAGE(ret == 0 && result, "getpwnam_r failed");
312
313         return pwd.pw_uid;
314 }
315
316 gid_t getGid(const char *name)
317 {
318         struct group grp;
319         struct group *result = nullptr;
320         size_t bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
321
322         if (bufsize <= 0)
323                 bufsize = 16384; /* should be more than enough */
324
325         memset(&grp, 0x00, sizeof(grp));
326
327         std::vector<char> buf(bufsize, 0);
328
329         int ret = getgrnam_r(name, &grp, buf.data(), bufsize, &result);
330         BOOST_REQUIRE_MESSAGE(ret == 0 && result, "getgrnam_r failed");
331
332         return grp.gr_gid;
333 }
334
335 void restoreFile(const string &filename)
336 {
337         static uid_t CKM_UID = getUid(USER_NAME);
338         static gid_t CKM_GID = getGid(GROUP_NAME);
339         string sourcePath = string(DB_TEST_DIR) + "/" + filename;
340         string targetPath = string(RW_DATA_DIR) + "/" + filename;
341
342         int err, ret;
343
344         int sourceFd = TEMP_FAILURE_RETRY(open(sourcePath.c_str(), O_RDONLY));
345         err = errno;
346         BOOST_REQUIRE_MESSAGE(sourceFd > 0,
347                                                   "Opening " << sourcePath << " failed: " << GetErrnoString(err));
348
349         FdPtr sourceFdPtr(&sourceFd);
350
351         int targetFd = TEMP_FAILURE_RETRY(creat(targetPath.c_str(), 0644));
352         err = errno;
353         BOOST_REQUIRE_MESSAGE(targetFd > 0,
354                                                   "Creating " << targetPath << " failed: " << GetErrnoString(err));
355
356         ret = fchown(targetFd, CKM_UID, CKM_GID);
357         err = errno;
358         BOOST_REQUIRE_MESSAGE(ret != -1, "fchown() failed: " << GetErrnoString(err));
359
360         FdPtr targetFdPtr(&targetFd);
361
362         struct stat sourceStat;
363         ret = fstat(sourceFd, &sourceStat);
364         err = errno;
365         BOOST_REQUIRE_MESSAGE(ret != -1, "fstat() failed: " << GetErrnoString(err));
366
367         ret = sendfile(targetFd, sourceFd, 0, sourceStat.st_size);
368         err = errno;
369         BOOST_REQUIRE_MESSAGE(ret != -1, "sendfile() failed: " << GetErrnoString(err));
370
371         ret = fsync(targetFd);
372         err = errno;
373         BOOST_REQUIRE_MESSAGE(ret != -1, "fsync() failed: " << GetErrnoString(err));
374 }
375
376 void generateRandom(size_t random_bytes, unsigned char *output)
377 {
378         if (random_bytes <= 0 || !output)
379                 throw runtime_error("Invalid param");
380
381         std::ifstream is("/dev/urandom", std::ifstream::binary);
382
383         if (!is)
384                 throw runtime_error("Failed to read /dev/urandom");
385
386         is.read(reinterpret_cast<char *>(output), random_bytes);
387
388         if (static_cast<std::streamsize>(random_bytes) != is.gcount())
389                 throw runtime_error("Not enough bytes read from /dev/urandom");
390 }
391
392 RawBuffer createRandomBuffer(size_t random_bytes)
393 {
394         RawBuffer buffer(random_bytes);
395         generateRandom(buffer.size(), buffer.data());
396         return buffer;
397 }
398 } // namespace anonymous
399
400
401 SchemeTest::SchemeTest() : m_userChanged(false), m_directAccessEnabled(false)
402 {
403         m_control = Control::create();
404         m_mgr = Manager::create();
405         initOpenSsl();
406
407         SmackAccess sa;
408         sa.add("System", LABEL, "rwx");
409         sa.add(LABEL, "System", "rwx");
410         sa.add(LABEL, "System::Run", "x");
411         sa.apply();
412 }
413
414 SchemeTest::~SchemeTest()
415 {
416         try {
417                 SwitchToRoot();
418         } catch (...) {}
419 }
420
421 void SchemeTest::RemoveUserData()
422 {
423         if (CKM_API_SUCCESS != m_control->lockUserKey(UID))
424                 throw runtime_error("lockUserKey failed");
425
426         if (CKM_API_SUCCESS != m_control->removeUserData(UID))
427                 throw runtime_error("removeUserData failed");
428 }
429
430 void SchemeTest::SwitchToUser()
431 {
432         if (m_userChanged)
433                 return;
434
435         if (CKM_API_SUCCESS != m_control->unlockUserKey(UID, DBPASS))
436                 throw runtime_error("unlockUserKey failed");
437
438         // get calling label
439         char *label = NULL;
440
441         if (smack_new_label_from_self(&label) <= 0)
442                 throw runtime_error("smack_new_label_from_self failed");
443
444         m_origLabel = string(label);
445         free(label);
446
447         if (0 > smack_set_label_for_self(LABEL))
448                 throw runtime_error("smack_set_label_for_self failed");
449
450         if (0 > setegid(GID))
451                 throw runtime_error("setegid failed");
452
453         if (0 > seteuid(UID))
454                 throw runtime_error("seteuid failed");
455
456         m_userChanged = true;
457 }
458
459 void SchemeTest::SwitchToRoot()
460 {
461         if (!m_userChanged)
462                 return;
463
464         if (0 > seteuid(0))
465                 throw runtime_error("seteuid failed");
466
467         if (0 > setegid(0))
468                 throw runtime_error("setegid failed");
469
470         if (0 > smack_set_label_for_self(m_origLabel.c_str()))
471                 throw runtime_error("smack_set_label_for_self failed");
472
473         if (m_control->lockUserKey(UID) != CKM_API_SUCCESS)
474                 throw runtime_error("lockUserKey failed");
475 }
476
477 void SchemeTest::FillDb()
478 {
479         // pkcs
480         ifstream is(DB_TEST_DIR "/encryption-scheme.p12");
481
482         if (!is)
483                 throw runtime_error("Failed to read pkcs");
484
485         istreambuf_iterator<char> begin(is), end;
486         RawBuffer pkcsBuffer(begin, end);
487         auto pkcs = PKCS12::create(pkcsBuffer, Password());
488
489         if (pkcs->empty())
490                 throw runtime_error("Empty pkcs");
491
492         SwitchToUser();
493
494         // certificates
495         RawBuffer rootCaBuffer(TEST_ROOT_CA.begin(), TEST_ROOT_CA.end());
496         CertificateShPtr rootCa = CKM::Certificate::create(rootCaBuffer,
497                                                           CKM::DataFormat::FORM_PEM);
498         RawBuffer imCaBuffer(TEST_IM_CA.begin(), TEST_IM_CA.end());
499         CertificateShPtr imCa = CKM::Certificate::create(imCaBuffer,
500                                                         CKM::DataFormat::FORM_PEM);
501         RawBuffer leafBuffer(TEST_LEAF.begin(), TEST_LEAF.end());
502         CertificateShPtr leaf = CKM::Certificate::create(leafBuffer,
503                                                         CKM::DataFormat::FORM_PEM);
504
505         for (const auto &g : GROUPS) {
506                 switch (g.type) {
507                 case Group::KEY_PAIR_RSA:
508                         if (g.items.size() != 2)
509                                 throw runtime_error("Wrong number of keys");
510
511                         if (g.items[0].type != DataType::KEY_RSA_PRIVATE ||
512                                         g.items[1].type != DataType::KEY_RSA_PUBLIC)
513                                 throw runtime_error("Invalid item type");
514
515                         if (CKM_API_SUCCESS != m_mgr->createKeyPairRSA(1024,
516                                         g.items[0].alias,
517                                         g.items[1].alias,
518                                         g.items[0].policy,
519                                         g.items[1].policy))
520                                 throw runtime_error("createKeyPair failed");
521
522                         break;
523
524                 case Group::CERT_CHAIN:
525                         if (g.items.size() != CHAIN_SIZE)
526                                 throw runtime_error("Wrong number of certificates");
527
528                         if (g.items[0].type != DataType::CERTIFICATE ||
529                                         g.items[1].type != DataType::CERTIFICATE ||
530                                         g.items[2].type != DataType::CERTIFICATE)
531                                 throw runtime_error("Invalid item type");
532
533                         if (CKM_API_SUCCESS != m_mgr->saveCertificate(g.items[0].alias, rootCa,
534                                         g.items[0].policy))
535                                 throw runtime_error("saveCertificate failed");
536
537                         if (CKM_API_SUCCESS != m_mgr->saveCertificate(g.items[1].alias, imCa,
538                                         g.items[1].policy))
539                                 throw runtime_error("saveCertificate failed");
540
541                         if (CKM_API_SUCCESS != m_mgr->saveCertificate(g.items[2].alias, leaf,
542                                         g.items[2].policy))
543                                 throw runtime_error("saveCertificate failed");
544
545                         break;
546
547                 default:
548                         for (const auto &i : g.items) {
549                                 switch (i.type) {
550                                 case DataType::BINARY_DATA:
551                                         if (CKM_API_SUCCESS != m_mgr->saveData(i.alias, TEST_DATA, i.policy))
552                                                 throw runtime_error("saveData failed");
553
554                                         break;
555
556                                 case DataType::KEY_AES:
557                                         if (CKM_API_SUCCESS != m_mgr->createKeyAES(256, i.alias, i.policy))
558                                                 throw runtime_error("createKeyAES failed");
559
560                                         break;
561
562                                 case DataType::CHAIN_CERT_0:    // PKCS
563                                         if (CKM_API_SUCCESS != m_mgr->savePKCS12(i.alias, pkcs, i.policy, i.policy))
564                                                 throw runtime_error("savePkcs12 failed");
565
566                                         break;
567
568                                 default:
569                                         throw runtime_error("unsupported data type");
570                                 }
571                         }
572
573                         break;
574                 }
575         }
576 }
577
578 void SchemeTest::ReadAll(bool useWrongPass)
579 {
580         SwitchToUser();
581
582         for (const auto &g : GROUPS) {
583                 for (const auto &i : g.items) {
584                         int ret;
585                         Password pass = i.policy.password;
586
587                         if (useWrongPass) {
588                                 if (pass.empty())
589                                         pass = TEST_PASS;
590                                 else
591                                         pass = Password();
592                         }
593
594                         switch (i.type) {
595                         case DataType::BINARY_DATA: {
596                                 RawBuffer receivedData;
597                                 ret = m_mgr->getData(i.alias, pass, receivedData);
598                                 BOOST_REQUIRE_MESSAGE(useWrongPass || receivedData == TEST_DATA,
599                                                                           "Received data is different for " << i.alias);
600                                 break;
601                         }
602
603                         case DataType::KEY_AES:
604                         case DataType::KEY_RSA_PRIVATE:
605                         case DataType::KEY_RSA_PUBLIC: {
606                                 KeyShPtr receivedKey;
607                                 ret = m_mgr->getKey(i.alias, pass, receivedKey);
608                                 break;
609                         }
610
611                         case DataType::CERTIFICATE: {
612                                 CertificateShPtr receivedCert;
613                                 ret = m_mgr->getCertificate(i.alias, pass, receivedCert);
614                                 break;
615                         }
616
617                         case DataType::CHAIN_CERT_0: { // pkcs
618                                 PKCS12ShPtr pkcs;
619                                 ret = m_mgr->getPKCS12(i.alias, pass, pass, pkcs);
620                                 break;
621                         }
622
623                         default:
624                                 BOOST_FAIL("Unsupported data type " << i.type);
625                         }
626
627                         if (i.policy.extractable) {
628                                 if (useWrongPass)
629                                         BOOST_REQUIRE_MESSAGE(ret == CKM_API_ERROR_AUTHENTICATION_FAILED,
630                                                                                   "Reading item " << i.alias << " should fail with " <<
631                                                                                   CKM_API_ERROR_AUTHENTICATION_FAILED << " got: " << ret);
632                                 else
633                                         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "Reading item " << i.alias <<
634                                                                                   " failed with " << ret);
635                         } else {
636                                 BOOST_REQUIRE_MESSAGE(ret == CKM_API_ERROR_NOT_EXPORTABLE, "Item " << i.alias <<
637                                                                           " should not be exportable");
638                         }
639                 }
640         }
641 }
642
643 void SchemeTest::SignVerify()
644 {
645         SwitchToUser();
646
647         for (const auto &g : GROUPS) {
648                 if (g.type == Group::KEY_PAIR_RSA) {
649                         BOOST_REQUIRE_MESSAGE(g.items.size() == 2, "Wrong number of keys");
650                         BOOST_REQUIRE_MESSAGE(g.items[0].type == DataType::KEY_RSA_PRIVATE &&
651                                                                   g.items[1].type == DataType::KEY_RSA_PUBLIC, "Wrong key");
652
653                         SignVerifyItem(g.items[0], g.items[1]);
654                 } else {
655                         for (const auto &i : g.items) {
656                                 switch (i.type) {
657                                 case DataType::CHAIN_CERT_0:
658                                         SignVerifyItem(i, i);
659                                         break;
660
661                                 default:
662                                         break;
663                                 }
664                         }
665                 }
666         }
667 }
668
669 void SchemeTest::EncryptDecrypt()
670 {
671         SwitchToUser();
672
673         for (const auto &g : GROUPS) {
674                 if (g.type == Group::KEY_PAIR_RSA) {
675                         BOOST_REQUIRE_MESSAGE(g.items.size() == 2, "Wrong number of keys");
676                         BOOST_REQUIRE_MESSAGE(g.items[0].type == DataType::KEY_RSA_PRIVATE &&
677                                                                   g.items[1].type == DataType::KEY_RSA_PUBLIC, "Wrong key");
678
679                         EncryptDecryptItem(g.items[0], g.items[1]);
680                 } else {
681                         for (const auto &i : g.items) {
682                                 switch (i.type) {
683                                 case DataType::KEY_AES:
684                                         EncryptDecryptItem(i);
685                                         break;
686
687                                 case DataType::CHAIN_CERT_0:
688                                         EncryptDecryptItem(i, i);
689                                         break;
690
691                                 default:
692                                         break;
693                                 }
694                         }
695                 }
696         }
697 }
698
699 void SchemeTest::CreateChain()
700 {
701         SwitchToUser();
702
703         for (const auto &g : GROUPS) {
704                 if (g.type == Group::CERT_CHAIN) {
705                         BOOST_REQUIRE_MESSAGE(g.items.size() == CHAIN_SIZE, "Not enough certificates");
706
707                         for (const auto &c : g.items)
708                                 BOOST_REQUIRE_MESSAGE(c.type == DataType::CERTIFICATE, "Wrong item type");
709
710                         Items trusted(CHAIN_SIZE - 1);
711                         std::copy(g.items.begin(), g.items.begin() + CHAIN_SIZE - 1, trusted.begin());
712
713                         // last one is ee (leaf)
714                         CreateChainItem(g.items.back(), trusted);
715                 } else {
716                         for (const auto &i : g.items) {
717                                 if (i.type == DataType::CHAIN_CERT_0) // PKCS
718                                         CreateChainItem(i, { i });
719                         }
720                 }
721         }
722 }
723
724 void SchemeTest::RemoveAll()
725 {
726         SwitchToUser();
727
728         for (const auto &g : GROUPS) {
729                 for (const auto &i : g.items) {
730                         int ret = m_mgr->removeAlias(i.alias);
731                         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
732                                                                   "removeAlias() failed with " << ret << " for " << i.alias);
733                 }
734         }
735 }
736 size_t SchemeTest::CountObjects()
737 {
738         EnableDirectDbAccess();
739
740         size_t ret = 0;
741
742         for (const auto &g : GROUPS) {
743                 for (const auto &i : g.items) {
744                         DB::RowVector rows;
745                         // it is assumed that aliases are different
746                         m_db->getRows(i.alias, DB_LABEL, DataType::DB_FIRST, DataType::DB_LAST, rows);
747                         ret += rows.size();
748                 }
749         }
750
751         return ret;
752 }
753
754 void SchemeTest::RestoreDb()
755 {
756         restoreFile("key-7654");
757         restoreFile("db-key-7654");
758         restoreFile("db-7654");
759         m_db.reset();
760         m_directAccessEnabled = false;
761 }
762
763 void SchemeTest::CheckSchemeVersion(const ItemFilter &filter, int version)
764 {
765         EnableDirectDbAccess();
766
767         for (const auto &g : GROUPS) {
768                 for (const auto &i : g.items) {
769                         if (!filter.Matches(i))
770                                 continue;
771
772                         DB::RowVector rows;
773                         m_db->getRows(i.alias, DB_LABEL, filter.typeFrom, filter.typeTo, rows);
774                         BOOST_REQUIRE_MESSAGE(rows.size() > 0, "No rows found for " << i.alias);
775
776                         for (const auto &r : rows) {
777                                 BOOST_REQUIRE_MESSAGE(
778                                         (r.encryptionScheme >> ENC_SCHEME_OFFSET) == version,
779                                         "Wrong encryption scheme for " << i.alias << ". Expected " << version <<
780                                         " got: " << (r.encryptionScheme >> ENC_SCHEME_OFFSET));
781                         }
782                 }
783         }
784 }
785
786 void SchemeTest::EnableDirectDbAccess()
787 {
788         SwitchToRoot();
789
790         if (m_directAccessEnabled)
791                 return;
792
793         // direct access to db
794         FileSystem fs(UID);
795         auto wrappedDKEK = fs.getDKEK();
796         auto keyProvider = KeyProvider(wrappedDKEK, DBPASS);
797
798         auto wrappedDatabaseDEK = fs.getDBDEK();
799         RawBuffer key = keyProvider.getPureDEK(wrappedDatabaseDEK);
800
801         m_db.reset(new DB::Crypto(fs.getDBPath(), key));
802         m_directAccessEnabled = true;
803 }
804
805 void SchemeTest::SignVerifyItem(const Item &itemPrv, const Item &itemPub)
806 {
807         int ret;
808         KeyShPtr receivedKey;
809         RawBuffer signature;
810         // create/verify signature
811         ret = m_mgr->createSignature(itemPrv.alias,
812                                                                  itemPrv.policy.password,
813                                                                  TEST_DATA,
814                                                                  HashAlgorithm::SHA512,
815                                                                  RSAPaddingAlgorithm::X931,
816                                                                  signature);
817         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
818                                                   "createSignature() failed with " << ret <<
819                                                   " for " << itemPrv.alias);
820         ret = m_mgr->verifySignature(itemPub.alias,
821                                                                  itemPub.policy.password,
822                                                                  TEST_DATA,
823                                                                  signature,
824                                                                  HashAlgorithm::SHA512,
825                                                                  RSAPaddingAlgorithm::X931);
826         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
827                                                   "verifySignature() failed with " << ret <<
828                                                   " for " << itemPub.alias);
829 }
830
831 void SchemeTest::EncryptDecryptItem(const Item &item)
832 {
833         CryptoAlgorithm algo;
834         RawBuffer iv = createRandomBuffer(IV_LEN);
835         RawBuffer encrypted, decrypted;
836         int ret;
837
838         algo.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GCM);
839         algo.setParam(ParamName::ED_IV, iv);
840
841         ret = m_mgr->encrypt(algo, item.alias, item.policy.password, TEST_DATA,
842                                                  encrypted);
843         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
844                                                   "encrypt() failed iwth " << ret << " for " <<
845                                                   item.alias);
846
847         ret = m_mgr->decrypt(algo, item.alias, item.policy.password, encrypted,
848                                                  decrypted);
849         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
850                                                   "decrypt() failed iwth " << ret << " for " <<
851                                                   item.alias);
852
853         BOOST_REQUIRE_MESSAGE(decrypted == TEST_DATA,
854                                                   "Decrypted data not equal to original");
855 }
856
857 void SchemeTest::EncryptDecryptItem(const Item &itemPrv, const Item &itemPub)
858 {
859         CryptoAlgorithm algo;
860         RawBuffer encrypted, decrypted;
861         int ret;
862
863         algo.setParam(ParamName::ALGO_TYPE, AlgoType::RSA_OAEP);
864
865         ret = m_mgr->encrypt(algo, itemPub.alias, itemPub.policy.password, TEST_DATA,
866                                                  encrypted);
867         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
868                                                   "encrypt() failed iwth " << ret << " for " <<
869                                                   itemPub.alias);
870
871         ret = m_mgr->decrypt(algo, itemPrv.alias, itemPrv.policy.password, encrypted,
872                                                  decrypted);
873         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
874                                                   "decrypt() failed iwth " << ret << " for " <<
875                                                   itemPrv.alias);
876
877         BOOST_REQUIRE_MESSAGE(decrypted == TEST_DATA,
878                                                   "Decrypted data not equal to original");
879 }
880
881 void SchemeTest::CreateChainItem(const Item &leaf, const Items &certs)
882 {
883         CertificateShPtrVector chain;
884         AliasVector trusted;
885
886         if (!leaf.policy.extractable || !leaf.policy.password.empty())
887                 return;
888
889         for (const auto &i : certs) {
890                 if (!i.policy.extractable || !i.policy.password.empty())
891                         return;
892
893                 trusted.push_back(i.alias);
894         }
895
896         CertificateShPtr leafCrt;
897         int ret = m_mgr->getCertificate(leaf.alias, leaf.policy.password, leafCrt);
898         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
899                                                   "getCertificate failed with " << ret << " for " <<
900                                                   leaf.alias);
901
902         ret = m_mgr->getCertificateChain(leafCrt, AliasVector(), trusted, false, chain);
903         BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
904                                                   "getCertificateChain() failed with " << ret);
905         BOOST_REQUIRE_MESSAGE(chain.size() == CHAIN_LEN,
906                                                   "Wrong chain length: " << chain.size());
907 }