2 * Copyright (c) 2015-2020 Samsung Electronics Co., Ltd. All rights reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 * @file scheme-test.cpp
18 * @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
21 #include "scheme-test.h"
23 #include <sys/smack.h>
24 #include <sys/types.h>
26 #include <sys/sendfile.h>
37 #include <boost/test/unit_test.hpp>
39 #include <db-crypto.h>
40 #include <file-system.h>
41 #include <key-provider.h>
43 #include <dpl/errno_string.h>
44 #include "smack-access.h"
50 const uid_t UID = 7654;
51 const gid_t GID = 7654;
52 const char *const DBPASS = "db-pass";
53 const char *const LABEL = "my-label";
54 const ClientId OWNER = "/" + string(LABEL);
55 const int ENC_SCHEME_OFFSET = 24;
56 const string TEST_DATA_STR = "test-data";
57 RawBuffer TEST_DATA(TEST_DATA_STR.begin(), TEST_DATA_STR.end());
58 const Password TEST_PASS = "custom user password";
59 const size_t IV_LEN = 16;
60 const size_t CHAIN_LEN = 3;
61 const mode_t MODE_0644 = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
73 // [password][exportable]
74 Policy policy[2][2] = {
75 {{ Password(), false }, { Password(), true }},
76 {{ TEST_PASS, false }, { TEST_PASS, true }},
92 Item("data-alias1", DataType::BINARY_DATA, policy[NO_PASS][EXP])
97 Item("data-alias2", DataType::BINARY_DATA, policy[PASS][EXP])
103 Group::KEY_PAIR_RSA, {
104 Item("key-rsa-alias-prv1", DataType::KEY_RSA_PRIVATE, policy[NO_PASS][NO_EXP]),
105 Item("key-rsa-alias-pub1", DataType::KEY_RSA_PUBLIC, policy[NO_PASS][NO_EXP])
109 Group::KEY_PAIR_RSA, {
110 Item("key-rsa-alias-prv2", DataType::KEY_RSA_PRIVATE, policy[NO_PASS][EXP]),
111 Item("key-rsa-alias-pub2", DataType::KEY_RSA_PUBLIC, policy[NO_PASS][EXP]),
115 Group::KEY_PAIR_RSA, {
116 Item("key-rsa-alias-prv3", DataType::KEY_RSA_PRIVATE, policy[PASS][NO_EXP]),
117 Item("key-rsa-alias-pub3", DataType::KEY_RSA_PUBLIC, policy[PASS][NO_EXP]),
121 Group::KEY_PAIR_RSA, {
122 Item("key-rsa-alias-prv4", DataType::KEY_RSA_PRIVATE, policy[PASS][EXP]),
123 Item("key-rsa-alias-pub4", DataType::KEY_RSA_PUBLIC, policy[PASS][EXP]),
126 // different policies
128 Group::KEY_PAIR_RSA, {
129 Item("key-rsa-alias-prv5", DataType::KEY_RSA_PRIVATE, policy[PASS][NO_EXP]),
130 Item("key-rsa-alias-pub5", DataType::KEY_RSA_PUBLIC, policy[NO_PASS][EXP]),
136 Group::SINGLE_ITEM, {
137 Item("key-aes-alias1", DataType::KEY_AES, policy[NO_PASS][NO_EXP]),
141 Group::SINGLE_ITEM, {
142 Item("key-aes-alias2", DataType::KEY_AES, policy[NO_PASS][EXP]),
146 Group::SINGLE_ITEM, {
147 Item("key-aes-alias3", DataType::KEY_AES, policy[PASS][NO_EXP]),
151 Group::SINGLE_ITEM, {
152 Item("key-aes-alias4", DataType::KEY_AES, policy[PASS][EXP]),
159 Item("cert-root-alias1", DataType::CERTIFICATE, policy[NO_PASS][NO_EXP]),
160 Item("cert-im-ca-alias1", DataType::CERTIFICATE, policy[NO_PASS][NO_EXP]),
161 Item("cert-leaf-alias1", DataType::CERTIFICATE, policy[NO_PASS][NO_EXP]),
166 Item("cert-root-alias2", DataType::CERTIFICATE, policy[NO_PASS][EXP]),
167 Item("cert-im-ca-alias2", DataType::CERTIFICATE, policy[NO_PASS][EXP]),
168 Item("cert-leaf-alias2", DataType::CERTIFICATE, policy[NO_PASS][EXP]),
173 Item("cert-root-alias3", DataType::CERTIFICATE, policy[PASS][NO_EXP]),
174 Item("cert-im-ca-alias3", DataType::CERTIFICATE, policy[PASS][NO_EXP]),
175 Item("cert-leaf-alias3", DataType::CERTIFICATE, policy[PASS][NO_EXP]),
180 Item("cert-root-alias4", DataType::CERTIFICATE, policy[PASS][EXP]),
181 Item("cert-im-ca-alias4", DataType::CERTIFICATE, policy[PASS][EXP]),
182 Item("cert-leaf-alias4", DataType::CERTIFICATE, policy[PASS][EXP]),
188 Group::SINGLE_ITEM, {
189 Item("pkcs-alias1", DataType::CHAIN_CERT_0, policy[NO_PASS][NO_EXP]),
193 Group::SINGLE_ITEM, {
194 Item("pkcs-alias2", DataType::CHAIN_CERT_0, policy[NO_PASS][EXP]),
197 #ifndef TZ_BACKEND_ENABLED // TZ does not support importing asymmetric keys with password
199 Group::SINGLE_ITEM, {
200 Item("pkcs-alias3", DataType::CHAIN_CERT_0, policy[PASS][NO_EXP]),
205 Group::SINGLE_ITEM, {
206 Item("pkcs-alias4", DataType::CHAIN_CERT_0, policy[PASS][EXP]),
211 const size_t CHAIN_SIZE = 3;
213 // TEST_ROOT_CA, expires 2035
214 std::string TEST_ROOT_CA =
215 "-----BEGIN CERTIFICATE-----\n"
216 "MIIDnzCCAoegAwIBAgIJAMH/ADkC5YSTMA0GCSqGSIb3DQEBBQUAMGYxCzAJBgNV\n"
217 "BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0wCwYDVQQKDARBQ01FMRAwDgYD\n"
218 "VQQLDAdUZXN0aW5nMSEwHwYDVQQDDBhUZXN0IHJvb3QgY2EgY2VydGlmaWNhdGUw\n"
219 "HhcNMTQxMjMwMTcyMTUyWhcNMjQxMjI3MTcyMTUyWjBmMQswCQYDVQQGEwJBVTET\n"
220 "MBEGA1UECAwKU29tZS1TdGF0ZTENMAsGA1UECgwEQUNNRTEQMA4GA1UECwwHVGVz\n"
221 "dGluZzEhMB8GA1UEAwwYVGVzdCByb290IGNhIGNlcnRpZmljYXRlMIIBIjANBgkq\n"
222 "hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0EJRdUtd2th0vTVF7QxvDKzyFCF3w9vC\n"
223 "9IDE/Yr12w+a9jd0s7/eG96qTHIYffS3B7x2MB+d4n+SR3W0qmYh7xk8qfEgH3da\n"
224 "eDoV59IZ9r543KM+g8jm6KffYGX1bIJVVY5OhBRbO9nY6byYpd5kbCIUB6dCf7/W\n"
225 "rQl1aIdLGFIegAzPGFPXDcU6F192686x54bxt/itMX4agHJ9ZC/rrTBIZghVsjJo\n"
226 "5/AH5WZpasv8sfrGiiohAxtieoYoJkv5MOYP4/2lPlOY+Cgw1Yoz+HHv31AllgFs\n"
227 "BquBb/kJVmCCNsAOcnvQzTZUsW/TXz9G2nwRdqI1nSy2JvVjZGsqGQIDAQABo1Aw\n"
228 "TjAdBgNVHQ4EFgQUt6pkzFt1PZlfYRL/HGnufF4frdwwHwYDVR0jBBgwFoAUt6pk\n"
229 "zFt1PZlfYRL/HGnufF4frdwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC\n"
230 "AQEAld7Qwq0cdzDQ51w1RVLwTR8Oy25PB3rzwEHcSGJmdqlMi3xOdaz80S1R1BBX\n"
231 "ldvGBG5Tn0vT7xSuhmSgI2/HnBpy9ocHVOmhtNB4473NieEpfTYrnGXrFxu46Wus\n"
232 "9m/ZnugcQ2G6C54A/NFtvgLmaC8uH8M7gKdS6uYUwJFQEofkjmd4UpOYSqmcRXhS\n"
233 "Jzd5FYFWkJhKJYp3nlENSOD8CUFFVGekm05nFN2gRVc/qaqQkEX77+XYvhodLRsV\n"
234 "qMn7nf7taidDKLO2T4bhujztnTYOhhaXKgPy7AtZ28N2wvX96VyAPB/vrchGmyBK\n"
235 "kOg11TpPdNDkhb1J4ZCh2gupDg==\n"
236 "-----END CERTIFICATE-----\n";
238 // TEST_IM_CA, signed by TEST_ROOT_CA, expires 2035
239 std::string TEST_IM_CA =
240 "-----BEGIN CERTIFICATE-----\n"
241 "MIIDljCCAn6gAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwZjELMAkGA1UEBhMCQVUx\n"
242 "EzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAoMBEFDTUUxEDAOBgNVBAsMB1Rl\n"
243 "c3RpbmcxITAfBgNVBAMMGFRlc3Qgcm9vdCBjYSBjZXJ0aWZpY2F0ZTAeFw0xNTAx\n"
244 "MTYxNjQ1MzRaFw0zNTAxMTExNjQ1MzRaMGQxCzAJBgNVBAYTAkFVMRMwEQYDVQQI\n"
245 "DApTb21lLVN0YXRlMQ0wCwYDVQQKDARBQ01FMRAwDgYDVQQLDAdUZXN0aW5nMR8w\n"
246 "HQYDVQQDDBZUZXN0IElNIENBIGNlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEF\n"
247 "AAOCAQ8AMIIBCgKCAQEAzmBF78qClgoKfnLAncMXZwZ14TW+5kags1+QCYeg3c7j\n"
248 "L9+RvDxIaX2tKf1sukJcwQfYqUlQkwt+58LMOb2ORtkpj8Or6WCWCZ0BzneT8ug7\n"
249 "nxJT4m9+bohMF0JoKjjB2H4KNMHamLIwUxRKt6nyfk81kVhJOi2vzzxd+UCPi6Pc\n"
250 "UAbJNH48eNgOIg55nyFovVzYj8GIo/9GvHJj83PPa/KlJZ+Z1qZASZZ/VYorplVT\n"
251 "thsHXKfejhFy5YJ9t7n/vyAQsyBsagZsvX19xnH41fbYXHKf8UbXG23rNaZlchs6\n"
252 "XJVLQdzOpj3WTj/lCocVHqLaZISLhNQ3aI7kUBUdiwIDAQABo1AwTjAdBgNVHQ4E\n"
253 "FgQUoCYNaCBP4jl/3SYQuK8Ka+6i3QEwHwYDVR0jBBgwFoAUt6pkzFt1PZlfYRL/\n"
254 "HGnufF4frdwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjRzWiD97\n"
255 "Htv4Kxpm3P+C+xP9AEteCJfO+7p8MWgtWEJOknJyt55zeKS2JwZIq57KcbqD8U7v\n"
256 "vAUx1ymtUhlFPFd7J1mJ3pou+3aFYmGShYhGHpbrmUwjp7HVP588jrW1NoZVHdMc\n"
257 "4OgJWFrViXeu9+maIcekjMB/+9Y0dUgQuK5ZuT5H/Jwet7Th/o9uufTUZjBzRvrB\n"
258 "pbXgQpqgME2av4Q/6LuldPCTHLtWXgFUU2R+yCGmuGilvhFJnKoQryAbYnIQNWE8\n"
259 "SLoHQ9s1i7Zyb7HU6UAaqMOz15LBkyAqtNyJcO2p7Q/p5YK0xfD4xisI5qXucqVm\n"
261 "-----END CERTIFICATE-----\n";
263 // TEST_LEAF, signed by TEST_IM_CA, expires 2035
264 std::string TEST_LEAF =
265 "-----BEGIN CERTIFICATE-----\n"
266 "MIIDOzCCAiMCAQEwDQYJKoZIhvcNAQEFBQAwZDELMAkGA1UEBhMCQVUxEzARBgNV\n"
267 "BAgMClNvbWUtU3RhdGUxDTALBgNVBAoMBEFDTUUxEDAOBgNVBAsMB1Rlc3Rpbmcx\n"
268 "HzAdBgNVBAMMFlRlc3QgSU0gQ0EgY2VydGlmaWNhdGUwHhcNMTUwMTE2MTY0ODE0\n"
269 "WhcNMzUwMTExMTY0ODE0WjBjMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1T\n"
270 "dGF0ZTENMAsGA1UECgwEQUNNRTEQMA4GA1UECwwHVGVzdGluZzEeMBwGA1UEAwwV\n"
271 "VGVzdCBsZWFmIGNlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\n"
272 "CgKCAQEAzTdDIa2tDmRxFnIgiG+mBz8GoSVODs0ImNQGbqj+pLhBOFRH8fsah4Jl\n"
273 "z5YF9KwhMVLknnHGFLE/Nb7Ac35kEzhMQMpTRxohW83oxw3eZ8zN/FBoKqg4qHRq\n"
274 "QR8kS10YXTgrBR0ex/Vp+OUKEw6h7yL2r4Tpvrn9/qHwsxtLxqWbDIVf1O9b1Lfc\n"
275 "bllYMdmV5E62yN5tcwrDP8gvHjFnVeLzrG8wTpc9FR90/0Jkfp5jAJcArOBLrT0E\n"
276 "4VRqs+4HuwT8jAwFAmNnc7IYX5qSjtSWkmmHe73K/lzB+OiI0JEc/3eWUTWqwTSk\n"
277 "4tNCiQGBKJ39LXPTBBJdzmxVH7CUDQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQAp\n"
278 "UdDOGu3hNiG+Vn10aQ6B1ZmOj3t+45gUV3sC+y8hB8EK1g4P5Ke9bVDts0T5eOnj\n"
279 "CSc+6VoND5O4adI0IFFRFljHNVnvjeosHfUZNnowsmA2ptQBtC1g5ZKRvKXlkC5/\n"
280 "i5BGgRqPFA7y9WB9Y05MrJHf3E+Oz/RBsLeeNiNN+rF5X1vYExvGHpo0M0zS0ze9\n"
281 "HtC0aOy8ocsTrQkf3ceHTAXx2i8ftoSSD4klojtWFpWMrNQa52F7wB9nU6FfKRuF\n"
282 "Zj/T1JkYXKkEwZU6nAR2jdZp3EP9xj3o15V/tyFcXHx6l8NTxn4cJb+Xe4VquQJz\n"
283 "6ON7PVe0ABN/AlwVQiFE\n"
284 "-----END CERTIFICATE-----\n";
289 void operator()(int *fd)
296 typedef std::unique_ptr<int, FdCloser> FdPtr;
298 uid_t getUid(const char *name)
301 struct passwd *result = nullptr;
302 int bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
305 bufsize = 16384; /* should be more than enough */
307 memset(&pwd, 0x00, sizeof(pwd));
309 std::vector<char> buf(bufsize, 0);
311 int ret = getpwnam_r(name, &pwd, buf.data(), bufsize, &result);
312 BOOST_REQUIRE_MESSAGE(ret == 0 && result, "getpwnam_r failed");
317 gid_t getGid(const char *name)
320 struct group *result = nullptr;
321 size_t bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
324 bufsize = 16384; /* should be more than enough */
326 memset(&grp, 0x00, sizeof(grp));
328 std::vector<char> buf(bufsize, 0);
330 int ret = getgrnam_r(name, &grp, buf.data(), bufsize, &result);
331 BOOST_REQUIRE_MESSAGE(ret == 0 && result, "getgrnam_r failed");
336 void restoreFile(const string &filename)
338 static uid_t CKM_UID = getUid(USER_NAME);
339 static gid_t CKM_GID = getGid(GROUP_NAME);
340 string sourcePath = string(MISC_DIR) + "/" + filename;
341 string targetPath = string(RW_DATA_DIR) + "/" + filename;
345 int sourceFd = TEMP_FAILURE_RETRY(open(sourcePath.c_str(), O_RDONLY));
347 BOOST_REQUIRE_MESSAGE(sourceFd > 0,
348 "Opening " << sourcePath << " failed: " << GetErrnoString(err));
350 FdPtr sourceFdPtr(&sourceFd);
352 int targetFd = TEMP_FAILURE_RETRY(creat(targetPath.c_str(), MODE_0644));
354 BOOST_REQUIRE_MESSAGE(targetFd > 0,
355 "Creating " << targetPath << " failed: " << GetErrnoString(err));
357 ret = fchown(targetFd, CKM_UID, CKM_GID);
359 BOOST_REQUIRE_MESSAGE(ret != -1, "fchown() failed: " << GetErrnoString(err));
361 FdPtr targetFdPtr(&targetFd);
363 struct stat sourceStat;
364 ret = fstat(sourceFd, &sourceStat);
366 BOOST_REQUIRE_MESSAGE(ret != -1, "fstat() failed: " << GetErrnoString(err));
368 ret = sendfile(targetFd, sourceFd, 0, sourceStat.st_size);
370 BOOST_REQUIRE_MESSAGE(ret != -1, "sendfile() failed: " << GetErrnoString(err));
372 ret = fsync(targetFd);
374 BOOST_REQUIRE_MESSAGE(ret != -1, "fsync() failed: " << GetErrnoString(err));
377 void generateRandom(size_t random_bytes, unsigned char *output)
379 if (random_bytes <= 0 || !output)
380 throw runtime_error("Invalid param");
382 std::ifstream is("/dev/urandom", std::ifstream::binary);
385 throw runtime_error("Failed to read /dev/urandom");
387 is.read(reinterpret_cast<char *>(output), random_bytes);
389 if (static_cast<std::streamsize>(random_bytes) != is.gcount())
390 throw runtime_error("Not enough bytes read from /dev/urandom");
393 RawBuffer createRandomBuffer(size_t random_bytes)
395 RawBuffer buffer(random_bytes);
396 generateRandom(buffer.size(), buffer.data());
399 } // namespace anonymous
402 SchemeTest::SchemeTest() : m_userChanged(false), m_directAccessEnabled(false)
404 m_control = Control::create();
405 m_mgr = Manager::create();
408 sa.add("System", LABEL, "rwx");
409 sa.add(LABEL, "System", "rwx");
410 sa.add(LABEL, "System::Run", "x");
414 SchemeTest::~SchemeTest()
421 void SchemeTest::RemoveUserData()
423 if (CKM_API_SUCCESS != m_control->lockUserKey(UID))
424 throw runtime_error("lockUserKey failed");
426 if (CKM_API_SUCCESS != m_control->removeUserData(UID))
427 throw runtime_error("removeUserData failed");
430 void SchemeTest::SwitchToUser()
435 if (CKM_API_SUCCESS != m_control->unlockUserKey(UID, DBPASS))
436 throw runtime_error("unlockUserKey failed");
441 if (smack_new_label_from_self(&label) <= 0)
442 throw runtime_error("smack_new_label_from_self failed");
444 m_origLabel = string(label);
447 if (0 > smack_set_label_for_self(LABEL))
448 throw runtime_error("smack_set_label_for_self failed");
450 if (0 > setegid(GID))
451 throw runtime_error("setegid failed");
453 if (0 > seteuid(UID))
454 throw runtime_error("seteuid failed");
456 m_userChanged = true;
459 void SchemeTest::SwitchToRoot()
465 throw runtime_error("seteuid failed");
468 throw runtime_error("setegid failed");
470 if (0 > smack_set_label_for_self(m_origLabel.c_str()))
471 throw runtime_error("smack_set_label_for_self failed");
473 if (m_control->lockUserKey(UID) != CKM_API_SUCCESS)
474 throw runtime_error("lockUserKey failed");
477 void SchemeTest::FillDb()
480 ifstream is(MISC_DIR "/encryption-scheme.p12");
483 throw runtime_error("Failed to read pkcs");
485 istreambuf_iterator<char> begin(is), end;
486 RawBuffer pkcsBuffer(begin, end);
487 auto pkcs = PKCS12::create(pkcsBuffer, Password());
489 if (!pkcs || pkcs->empty())
490 throw runtime_error("Empty pkcs");
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);
505 for (const auto &g : GROUPS) {
507 case Group::KEY_PAIR_RSA:
508 if (g.items.size() != 2)
509 throw runtime_error("Wrong number of keys");
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");
515 if (CKM_API_SUCCESS != m_mgr->createKeyPairRSA(1024,
520 throw runtime_error("createKeyPair failed");
524 case Group::CERT_CHAIN:
525 if (g.items.size() != CHAIN_SIZE)
526 throw runtime_error("Wrong number of certificates");
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");
533 if (CKM_API_SUCCESS != m_mgr->saveCertificate(g.items[0].alias, rootCa,
535 throw runtime_error("saveCertificate failed");
537 if (CKM_API_SUCCESS != m_mgr->saveCertificate(g.items[1].alias, imCa,
539 throw runtime_error("saveCertificate failed");
541 if (CKM_API_SUCCESS != m_mgr->saveCertificate(g.items[2].alias, leaf,
543 throw runtime_error("saveCertificate failed");
548 for (const auto &i : g.items) {
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");
556 case DataType::KEY_AES:
557 if (CKM_API_SUCCESS != m_mgr->createKeyAES(256, i.alias, i.policy))
558 throw runtime_error("createKeyAES failed");
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");
569 throw runtime_error("unsupported data type");
578 void SchemeTest::CheckAliasInfo()
581 for (const auto &g : GROUPS) {
582 for (const auto &i : g.items) {
584 bool encStatus = false;
585 Password pass = i.policy.password;
593 case DataType::BINARY_DATA: {
594 ret = m_mgr->getDataEncryptionStatus(i.alias, encStatus);
595 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
596 "can not get data encryption status, ret: " +
597 std::to_string(ret));
601 case DataType::KEY_AES:
602 case DataType::KEY_RSA_PRIVATE:
603 case DataType::KEY_RSA_PUBLIC: {
604 ret = m_mgr->getKeyEncryptionStatus(i.alias, encStatus);
605 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
606 "can not get key encryption status, ret: " +
607 std::to_string(ret));
611 case DataType::CERTIFICATE: {
612 ret = m_mgr->getCertificateEncryptionStatus(i.alias, encStatus);
613 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
614 "can not get certificate encryption status, ret: " +
615 std::to_string(ret));
619 case DataType::CHAIN_CERT_0: {
620 ret = m_mgr->getCertificateEncryptionStatus(i.alias, encStatus);
621 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
622 "can not get certificate encryption status, ret: " +
623 std::to_string(ret));
624 ret = m_mgr->getKeyEncryptionStatus(i.alias, encStatus);
625 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
626 "can not get key encryption status, ret: " +
627 std::to_string(ret));
632 BOOST_FAIL("Unsupported data type " << i.type);
634 BOOST_REQUIRE_MESSAGE(encStatus == !i.policy.password.empty(), "item: " <<
635 i.alias << " has wrong encryption status: " << encStatus);
642 void SchemeTest::ReadAll(bool useWrongPass)
646 for (const auto &g : GROUPS) {
647 for (const auto &i : g.items) {
649 Password pass = i.policy.password;
659 case DataType::BINARY_DATA: {
660 RawBuffer receivedData;
661 ret = m_mgr->getData(i.alias, pass, receivedData);
662 BOOST_REQUIRE_MESSAGE(useWrongPass || receivedData == TEST_DATA,
663 "Received data is different for " << i.alias);
667 case DataType::KEY_AES:
668 case DataType::KEY_RSA_PRIVATE:
669 case DataType::KEY_RSA_PUBLIC: {
670 KeyShPtr receivedKey;
671 ret = m_mgr->getKey(i.alias, pass, receivedKey);
675 case DataType::CERTIFICATE: {
676 CertificateShPtr receivedCert;
677 ret = m_mgr->getCertificate(i.alias, pass, receivedCert);
681 case DataType::CHAIN_CERT_0: { // pkcs
683 ret = m_mgr->getPKCS12(i.alias, pass, pass, pkcs);
688 BOOST_FAIL("Unsupported data type " << i.type);
691 if (i.policy.extractable) {
693 BOOST_REQUIRE_MESSAGE(ret == CKM_API_ERROR_AUTHENTICATION_FAILED,
694 "Reading item " << i.alias << " should fail with " <<
695 CKM_API_ERROR_AUTHENTICATION_FAILED << " got: " << ret);
697 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS, "Reading item " << i.alias <<
698 " failed with " << ret);
700 BOOST_REQUIRE_MESSAGE(ret == CKM_API_ERROR_NOT_EXPORTABLE, "Item " << i.alias <<
701 " should not be exportable");
707 void SchemeTest::SignVerify()
711 for (const auto &g : GROUPS) {
712 if (g.type == Group::KEY_PAIR_RSA) {
713 BOOST_REQUIRE_MESSAGE(g.items.size() == 2, "Wrong number of keys");
714 BOOST_REQUIRE_MESSAGE(g.items[0].type == DataType::KEY_RSA_PRIVATE &&
715 g.items[1].type == DataType::KEY_RSA_PUBLIC, "Wrong key");
717 SignVerifyItem(g.items[0], g.items[1]);
719 for (const auto &i : g.items) {
721 case DataType::CHAIN_CERT_0:
722 SignVerifyItem(i, i);
733 void SchemeTest::EncryptDecrypt()
737 for (const auto &g : GROUPS) {
738 if (g.type == Group::KEY_PAIR_RSA) {
739 BOOST_REQUIRE_MESSAGE(g.items.size() == 2, "Wrong number of keys");
740 BOOST_REQUIRE_MESSAGE(g.items[0].type == DataType::KEY_RSA_PRIVATE &&
741 g.items[1].type == DataType::KEY_RSA_PUBLIC, "Wrong key");
743 EncryptDecryptItem(g.items[0], g.items[1]);
745 for (const auto &i : g.items) {
747 case DataType::KEY_AES:
748 EncryptDecryptItem(i);
751 case DataType::CHAIN_CERT_0:
752 EncryptDecryptItem(i, i);
763 void SchemeTest::CreateChain()
767 for (const auto &g : GROUPS) {
768 if (g.type == Group::CERT_CHAIN) {
769 BOOST_REQUIRE_MESSAGE(g.items.size() == CHAIN_SIZE, "Not enough certificates");
771 for (const auto &c : g.items)
772 BOOST_REQUIRE_MESSAGE(c.type == DataType::CERTIFICATE, "Wrong item type");
774 Items trusted(CHAIN_SIZE - 1);
775 std::copy(g.items.begin(), g.items.begin() + CHAIN_SIZE - 1, trusted.begin());
777 // last one is ee (leaf)
778 CreateChainItem(g.items.back(), trusted);
780 for (const auto &i : g.items) {
781 if (i.type == DataType::CHAIN_CERT_0) // PKCS
782 CreateChainItem(i, { i });
788 void SchemeTest::RemoveAll()
792 for (const auto &g : GROUPS) {
793 for (const auto &i : g.items) {
794 int ret = m_mgr->removeAlias(i.alias);
795 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
796 "removeAlias() failed with " << ret << " for " << i.alias);
800 size_t SchemeTest::CountObjects()
802 EnableDirectDbAccess();
806 for (const auto &g : GROUPS) {
807 for (const auto &i : g.items) {
809 // it is assumed that aliases are different
810 m_db->getRows(i.alias, OWNER, DataType::DB_FIRST, DataType::DB_LAST, rows);
818 void SchemeTest::RestoreDb()
821 restoreFile("key-7654");
822 restoreFile("db-key-7654");
823 restoreFile("db-7654");
824 m_directAccessEnabled = false;
827 void SchemeTest::CheckSchemeVersion(const ItemFilter &filter, int version)
829 EnableDirectDbAccess();
831 for (const auto &g : GROUPS) {
832 for (const auto &i : g.items) {
833 if (!filter.Matches(i))
837 m_db->getRows(i.alias, OWNER, filter.typeFrom, filter.typeTo, rows);
838 BOOST_REQUIRE_MESSAGE(rows.size() > 0, "No rows found for " << i.alias);
840 for (const auto &r : rows) {
841 BOOST_REQUIRE_MESSAGE(
842 (r.encryptionScheme >> ENC_SCHEME_OFFSET) == version,
843 "Wrong encryption scheme for " << i.alias << ". Expected " << version <<
844 " got: " << (r.encryptionScheme >> ENC_SCHEME_OFFSET));
850 void SchemeTest::EnableDirectDbAccess()
854 if (m_directAccessEnabled)
857 // direct access to db
859 auto wrappedDKEK = fs.getDKEK();
860 auto keyProvider = KeyProvider(wrappedDKEK, DBPASS);
861 if (!keyProvider.isInitialized()) {
862 keyProvider.migrateDomainKEK(wrappedDKEK, DBPASS);
863 fs.saveDKEK(keyProvider.getWrappedDomainKEK(DBPASS));
864 LogInfo("DKEK migrated");
867 auto wrappedDatabaseDEK = fs.getDBDEK();
868 RawBuffer key = keyProvider.getPureDEK(wrappedDatabaseDEK);
870 m_db.reset(new DB::Crypto(fs.getLegacyDBPath(), fs.getDBPath(), key));
871 m_directAccessEnabled = true;
873 // Legacy db files of the form db-$uid are incompatible with upstream sqlcipher.
874 // DB::Crypto(...) converts them to db0-$uid upstream-compatible, then deletes them.
875 // This function runs DB::Crypto(...) as root so db0-$uid are root-owned.
876 // However, database files need to be accessible to USER_NAME/GROUP_NAME (ex. ReadAll()).
877 // Thus the need to fix up ownership, much like restoreFile() does.
878 BOOST_REQUIRE(!chown(RW_DATA_DIR "/db0-7654", getUid(USER_NAME), getGid(GROUP_NAME)));
881 void SchemeTest::SignVerifyItem(const Item &itemPrv, const Item &itemPub)
884 KeyShPtr receivedKey;
886 // create/verify signature
887 ret = m_mgr->createSignature(itemPrv.alias,
888 itemPrv.policy.password,
890 HashAlgorithm::SHA512,
891 RSAPaddingAlgorithm::X931,
893 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
894 "createSignature() failed with " << ret <<
895 " for " << itemPrv.alias);
896 ret = m_mgr->verifySignature(itemPub.alias,
897 itemPub.policy.password,
900 HashAlgorithm::SHA512,
901 RSAPaddingAlgorithm::X931);
902 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
903 "verifySignature() failed with " << ret <<
904 " for " << itemPub.alias);
907 void SchemeTest::EncryptDecryptItem(const Item &item)
909 CryptoAlgorithm algo;
910 RawBuffer iv = createRandomBuffer(IV_LEN);
911 RawBuffer encrypted, decrypted;
914 algo.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GCM);
915 algo.setParam(ParamName::ED_IV, iv);
917 ret = m_mgr->encrypt(algo, item.alias, item.policy.password, TEST_DATA,
919 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
920 "encrypt() failed iwth " << ret << " for " <<
923 ret = m_mgr->decrypt(algo, item.alias, item.policy.password, encrypted,
925 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
926 "decrypt() failed iwth " << ret << " for " <<
929 BOOST_REQUIRE_MESSAGE(decrypted == TEST_DATA,
930 "Decrypted data not equal to original");
933 void SchemeTest::EncryptDecryptItem(const Item &itemPrv, const Item &itemPub)
935 CryptoAlgorithm algo;
936 RawBuffer encrypted, decrypted;
939 algo.setParam(ParamName::ALGO_TYPE, AlgoType::RSA_OAEP);
941 ret = m_mgr->encrypt(algo, itemPub.alias, itemPub.policy.password, TEST_DATA,
943 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
944 "encrypt() failed iwth " << ret << " for " <<
947 ret = m_mgr->decrypt(algo, itemPrv.alias, itemPrv.policy.password, encrypted,
949 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
950 "decrypt() failed iwth " << ret << " for " <<
953 BOOST_REQUIRE_MESSAGE(decrypted == TEST_DATA,
954 "Decrypted data not equal to original");
957 void SchemeTest::CreateChainItem(const Item &leaf, const Items &certs)
959 CertificateShPtrVector chain;
962 if (!leaf.policy.extractable || !leaf.policy.password.empty())
965 for (const auto &i : certs) {
966 if (!i.policy.extractable || !i.policy.password.empty())
969 trusted.push_back(i.alias);
972 CertificateShPtr leafCrt;
973 int ret = m_mgr->getCertificate(leaf.alias, leaf.policy.password, leafCrt);
974 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
975 "getCertificate failed with " << ret << " for " <<
978 ret = m_mgr->getCertificateChain(leafCrt, AliasVector(), trusted, false, chain);
979 BOOST_REQUIRE_MESSAGE(ret == CKM_API_SUCCESS,
980 "getCertificateChain() failed with " << ret);
981 BOOST_REQUIRE_MESSAGE(chain.size() == CHAIN_LEN,
982 "Wrong chain length: " << chain.size());