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