Release 0.1.66
[platform/core/security/key-manager.git] / unit-tests / test_key-provider.cpp
1 /*
2  *  Copyright (c) 2016 - 2020 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Kyungwook Tak <k.tak@samsung.com>
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  *
18  * @file        test_key-provider.cpp
19  * @author      Kyungwook Tak (k.tak@samsung.com)
20  * @version
21  * @brief
22  */
23
24 #include <boost_macros_wrapper.h>
25 #include <exception.h>
26 #include <key-provider.h>
27 #include <test_common.h>
28 #include <iostream>
29
30 #include "crypto-backend.h"
31
32 using namespace CKM;
33
34 namespace {
35 const Password PASSWORD = "12345TIZEN12345AAAAAAAAA";
36 const Password INCORRECT_PASSWORD = "AAAAAAAAAAAAAAAAAAAAA";
37 const Password NEW_PASSWORD = "NEW12345TIZEN12345NEW";
38
39 const std::string USERNAME = "SOFTWARE_CENTER_SYSTEM_SW_LAB";
40 const std::string CLIENT_ID = "SAMPLE_CLIENT_ID_1";
41
42 constexpr uint32_t KEYCOMPONENT_VERSION = 2; // keep it in sync with key-provider.cpp
43
44 template<typename T>
45 RawBuffer toRawBuffer(const T &data)
46 {
47         RawBuffer output;
48         const unsigned char *ptr = reinterpret_cast<const unsigned char *>(&data);
49         output.assign(ptr, ptr + sizeof(T));
50         return output;
51 }
52
53 RawBuffer makeDefaultWrappedDomainKEK()
54 {
55         RawBuffer wdkek;
56         BOOST_REQUIRE_NO_THROW(wdkek = KeyProvider::generateDomainKEK(USERNAME, PASSWORD));
57         BOOST_REQUIRE(!wdkek.empty());
58         return wdkek;
59 }
60
61 KeyProvider makeDefaultKeyProvider()
62 {
63         KeyProvider kp;
64         RawBuffer wdkek = makeDefaultWrappedDomainKEK();
65
66         BOOST_REQUIRE_NO_THROW(kp = KeyProvider(wdkek, PASSWORD));
67         BOOST_REQUIRE_MESSAGE(kp.isInitialized(), "KeyProvider created, but uninitialized");
68         return kp;
69 }
70
71 RawBuffer makeDefaultWrappedDomainKEK(CryptoBackend backend)
72 {
73         struct TestKeyProvider : public KeyProvider {
74                 using KeyProvider::KeyProvider;
75
76                 void setBackend(CryptoBackend backend) {
77                         BOOST_REQUIRE(m_domainKEK);
78                         m_domainKEK->info.backend = static_cast<uint32_t>(backend);
79                 }
80         };
81
82         auto wrappedDKEKbuffer = makeDefaultWrappedDomainKEK();
83         TestKeyProvider kp(wrappedDKEKbuffer, PASSWORD);
84         kp.setBackend(backend);
85         return kp.getWrappedDomainKEK(PASSWORD);
86 }
87
88 void checkVersionAndBackend(const RawBuffer& wrappedDomainKEKbuffer)
89 {
90         DomainKEKAndInfo wdkek(wrappedDomainKEKbuffer);
91         BOOST_REQUIRE(wdkek.info.version == KEYCOMPONENT_VERSION);
92 #if SE_BACKEND_ENABLED
93         BOOST_REQUIRE(wdkek.info.backend == static_cast<uint32_t>(CryptoBackend::SecureElement));
94 #else
95         BOOST_REQUIRE(wdkek.info.backend == static_cast<uint32_t>(CryptoBackend::OpenSSL));
96 #endif
97 }
98
99 RawBuffer convertToOldFormat(const RawBuffer& wrappedDKEKbuffer)
100 {
101         DomainKEKAndInfo wrappedDKEK(wrappedDKEKbuffer);
102         DEKAndInfo wrappedOldDKEK;
103
104         // hacky conversion to old key format
105         wrappedOldDKEK.setKeyInfo(static_cast<KeyInfo>(wrappedDKEK.info));
106         memcpy(wrappedOldDKEK.key, wrappedDKEK.key, wrappedDKEK.info.keyLength);
107
108         return toRawBuffer(wrappedOldDKEK);
109 }
110
111 } // anonymous namespace
112
113 BOOST_AUTO_TEST_SUITE(KEY_PROVIDER_TEST)
114
115 NEGATIVE_TEST_CASE(KeyAndInfo_ctor_wrong_size)
116 {
117         RawBuffer buffer(sizeof(DomainKEKAndInfo) + 1, 0);
118         BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer)), Exc::InternalError);
119         buffer.pop_back();
120         buffer.pop_back();
121         BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer)), Exc::InternalError);
122
123         buffer.resize(sizeof(DEKAndInfo) + 1, 0);
124         BOOST_REQUIRE_THROW((DEKAndInfo(buffer)), Exc::InternalError);
125         buffer.pop_back();
126         buffer.pop_back();
127         BOOST_REQUIRE_THROW((DEKAndInfo(buffer)), Exc::InternalError);
128 }
129
130 NEGATIVE_TEST_CASE(KeyAndInfo_ctor_wrong_key_length)
131 {
132         DomainKEKAndInfo dkek;
133         dkek.info.keyLength = MAX_KEY_SIZE+1;
134         auto buffer = toRawBuffer(dkek);
135
136         BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer)), Exc::InternalError);
137
138         DEKAndInfo dek;
139         dek.info.keyLength = MAX_KEY_SIZE+1;
140         auto buffer2 = toRawBuffer(dek);
141
142         BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer2)), Exc::InternalError);
143 }
144
145 NEGATIVE_TEST_CASE(KeyAndInfo_ctor_wrong_client)
146 {
147         DomainKEKAndInfo dkek;
148         memset(&dkek.info.client, 'a', MAX_CLIENT_ID_SIZE);
149         auto buffer = toRawBuffer(dkek);
150
151         BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer)), Exc::InternalError);
152
153         DEKAndInfo dek;
154         memset(&dek.info.client, 'a', MAX_CLIENT_ID_SIZE);
155         auto buffer2 = toRawBuffer(dek);
156
157         BOOST_REQUIRE_THROW((DomainKEKAndInfo(buffer2)), Exc::InternalError);
158 }
159
160 POSITIVE_TEST_CASE(KeyAndInfo_ctor)
161 {
162         BOOST_REQUIRE_NO_THROW(DomainKEKAndInfo(RawBuffer(sizeof(DomainKEKAndInfo), 0)));
163
164         BOOST_REQUIRE_NO_THROW(DEKAndInfo(RawBuffer(sizeof(DEKAndInfo), 0)));
165 }
166
167 NEGATIVE_TEST_CASE(KeyProvider_wrong_size)
168 {
169         RawBuffer wdkek = makeDefaultWrappedDomainKEK();
170         KeyProvider kp;
171
172         wdkek.push_back(0);
173         BOOST_REQUIRE_NO_THROW(kp = KeyProvider(wdkek, PASSWORD));
174         BOOST_REQUIRE(!kp.isInitialized());
175
176         wdkek.pop_back();
177         wdkek.pop_back();
178         BOOST_REQUIRE_NO_THROW(kp = KeyProvider(wdkek, PASSWORD));
179         BOOST_REQUIRE(!kp.isInitialized());
180 }
181
182 NEGATIVE_TEST_CASE(KeyProvider_garbage)
183 {
184         BOOST_REQUIRE_THROW(KeyProvider(RawBuffer(sizeof(DomainKEKAndInfo)), PASSWORD),
185                             Exc::InternalError);
186 }
187
188 NEGATIVE_TEST_CASE(KeyDomainKek_invalid_password)
189 {
190         KeyProvider kp;
191         RawBuffer wdkek = makeDefaultWrappedDomainKEK();
192
193         BOOST_REQUIRE_THROW(kp = KeyProvider(wdkek, INCORRECT_PASSWORD), Exc::AuthenticationFailed);
194         BOOST_REQUIRE_MESSAGE(!kp.isInitialized(), "KeyProvider not created, but initialized");
195 }
196
197 POSITIVE_TEST_CASE(KeygetPureDomainKEK)
198 {
199         KeyProvider kp = makeDefaultKeyProvider();
200         RawBuffer dkek;
201
202         BOOST_REQUIRE_NO_THROW(dkek = kp.getPureDomainKEK());
203         BOOST_REQUIRE(dkek.size() <= MAX_KEY_SIZE);
204
205         checkVersionAndBackend(kp.getWrappedDomainKEK("whatever"));
206 }
207
208 NEGATIVE_TEST_CASE(KeygetPureDomainKEK_uninitialized)
209 {
210         KeyProvider kp;
211
212         BOOST_REQUIRE_THROW(kp.getPureDomainKEK(), Exc::InternalError);
213 }
214
215 POSITIVE_TEST_CASE(KeyGetWrappedDomainKEK)
216 {
217         KeyProvider kp = makeDefaultKeyProvider();
218         RawBuffer wdkek;
219
220         BOOST_REQUIRE_NO_THROW(wdkek = kp.getWrappedDomainKEK("whatever"));
221         BOOST_REQUIRE(!wdkek.empty());
222 }
223
224 NEGATIVE_TEST_CASE(KeyGetWrappedDomainKEK_uninitialized)
225 {
226         KeyProvider kp;
227         BOOST_REQUIRE_THROW(kp.getWrappedDomainKEK("whatever"), Exc::InternalError);
228 }
229
230 POSITIVE_TEST_CASE(KeyGenerateDEK)
231 {
232         KeyProvider kp = makeDefaultKeyProvider();
233         RawBuffer wdek;
234
235         BOOST_REQUIRE_NO_THROW(wdek = kp.generateDEK(CLIENT_ID));
236         BOOST_REQUIRE(!wdek.empty());
237 }
238
239 NEGATIVE_TEST_CASE(KeyGenerateDEK_uninitialized)
240 {
241         KeyProvider kp;
242
243         BOOST_REQUIRE_THROW(kp.generateDEK(CLIENT_ID), Exc::InternalError);
244 }
245
246 POSITIVE_TEST_CASE(KeyGetPureDEK)
247 {
248         KeyProvider kp = makeDefaultKeyProvider();
249         RawBuffer wdek, dek;
250
251         BOOST_REQUIRE_NO_THROW(wdek = kp.generateDEK(CLIENT_ID));
252         BOOST_REQUIRE(!wdek.empty());
253
254         BOOST_REQUIRE_NO_THROW(dek = kp.getPureDEK(wdek));
255         BOOST_REQUIRE(dek.size() <= MAX_KEY_SIZE);
256 }
257
258 NEGATIVE_TEST_CASE(KeyGetPureDEK_uninitialized)
259 {
260         KeyProvider kp;
261         RawBuffer wdek(sizeof(DEKAndInfo));
262
263         BOOST_REQUIRE_THROW(kp.getPureDEK(wdek), Exc::InternalError);
264 }
265
266 NEGATIVE_TEST_CASE(KeyGetPureDEK_wrong_size)
267 {
268         KeyProvider kp = makeDefaultKeyProvider();
269         RawBuffer wdek;
270
271         BOOST_REQUIRE_NO_THROW(wdek = kp.generateDEK(CLIENT_ID));
272
273         wdek.push_back(0);
274         BOOST_REQUIRE_THROW(kp.getPureDEK(wdek), Exc::InternalError);
275
276         wdek.pop_back();
277         wdek.pop_back();
278         BOOST_REQUIRE_THROW(kp.getPureDEK(wdek), Exc::InternalError);
279 }
280
281 NEGATIVE_TEST_CASE(KeyGetPureDEK_garbage)
282 {
283         KeyProvider kp = makeDefaultKeyProvider();
284         RawBuffer wdek(sizeof(DEKAndInfo));
285
286         BOOST_REQUIRE_THROW(kp.getPureDEK(wdek), Exc::InternalError);
287 }
288
289 POSITIVE_TEST_CASE(WrappedDomainKEK)
290 {
291         RawBuffer wdkekBuffer = makeDefaultWrappedDomainKEK();
292
293         checkVersionAndBackend(wdkekBuffer);
294 }
295
296 POSITIVE_TEST_CASE(KeyReencrypt)
297 {
298         RawBuffer wdkek = makeDefaultWrappedDomainKEK();
299         RawBuffer wdkek2;
300         KeyProvider keyProvider;
301
302         BOOST_REQUIRE_NO_THROW(keyProvider = KeyProvider(wdkek, PASSWORD));
303         BOOST_REQUIRE_NO_THROW(wdkek2 = keyProvider.getWrappedDomainKEK(NEW_PASSWORD));
304         BOOST_REQUIRE(!wdkek2.empty());
305 }
306
307 POSITIVE_TEST_CASE(KeyGetPureDEK_after_reencrypt)
308 {
309         KeyProvider kp;
310         RawBuffer wdek, dek, wdkek2;
311         RawBuffer wdkek = makeDefaultWrappedDomainKEK();
312
313         BOOST_REQUIRE_NO_THROW(kp = KeyProvider(wdkek, PASSWORD));
314         BOOST_REQUIRE_NO_THROW(wdkek2 = kp.getWrappedDomainKEK(NEW_PASSWORD));
315         BOOST_REQUIRE(!wdkek2.empty());
316
317         BOOST_REQUIRE_NO_THROW(kp = KeyProvider(wdkek2, NEW_PASSWORD));
318
319         BOOST_REQUIRE_NO_THROW(wdek = kp.generateDEK(CLIENT_ID));
320         BOOST_REQUIRE(!wdek.empty());
321
322         BOOST_REQUIRE_NO_THROW(dek = kp.getPureDEK(wdek));
323         BOOST_REQUIRE(dek.size() <= MAX_KEY_SIZE);
324 }
325
326 POSITIVE_TEST_CASE(dek_and_info)
327 {
328         DEKAndInfo dai;
329
330         auto salt = createRandom(20);
331         memcpy(dai.info.salt, salt.data(), sizeof(dai.info.salt));
332         BOOST_REQUIRE_NO_THROW(dai.setKeyInfoClient("key_info_client"));
333         dai.info.keyLength = 10;
334
335         DEKAndInfo dai2;
336         BOOST_REQUIRE_NO_THROW(dai2.setKeyInfo(dai.info));
337
338         BOOST_REQUIRE(dai.info.keyLength == dai2.info.keyLength);
339         BOOST_REQUIRE(memcmp(dai.info.salt, dai2.info.salt, sizeof(dai.info.salt)) == 0);
340         BOOST_REQUIRE(memcmp(dai.info.client, dai2.info.client, sizeof(dai.info.client)) == 0);
341 }
342
343 NEGATIVE_TEST_CASE(dek_and_info)
344 {
345         DEKAndInfo dai;
346         BOOST_REQUIRE_THROW(dai.setKeyInfoClient("key_info_client_waaaaay_too_long"),
347                             Exc::InternalError);
348
349         DEKAndInfo dai2;
350         dai2.info.keyLength = MAX_KEY_SIZE + 1;
351         auto buffer = toRawBuffer(dai2);
352         BOOST_REQUIRE_THROW(new DEKAndInfo((buffer)), Exc::InternalError);
353
354         // missing NULL termination in dai3.info.client
355         RawBuffer garbage(0x01, sizeof(DEKAndInfo));
356         BOOST_REQUIRE_THROW(new DEKAndInfo((garbage)), Exc::InternalError);
357 }
358
359 POSITIVE_TEST_CASE(moves)
360 {
361         KeyProvider kp = makeDefaultKeyProvider();
362         RawBuffer dkek;
363
364         BOOST_REQUIRE_NO_THROW(dkek = kp.getPureDomainKEK());
365         BOOST_REQUIRE(dkek.size() <= MAX_KEY_SIZE);
366
367         try {
368                 KeyProvider kp2(std::move(kp));
369                 KeyProvider kp3 = std::move(kp2);
370
371                 BOOST_REQUIRE(!kp.isInitialized());
372                 BOOST_REQUIRE(!kp2.isInitialized());
373                 BOOST_REQUIRE(kp3.isInitialized());
374
375                 RawBuffer dkek3;
376                 BOOST_REQUIRE_NO_THROW(dkek3 = kp3.getPureDomainKEK());
377                 BOOST_REQUIRE(dkek == dkek3);
378         } catch (...) {
379                 BOOST_REQUIRE_MESSAGE(false, "Unknown exception on moving KeyProvider");
380         }
381 }
382
383 NEGATIVE_TEST_CASE(moves)
384 {
385         KeyProvider kp = makeDefaultKeyProvider();
386         KeyProvider kp2(std::move(kp));
387
388         BOOST_REQUIRE_THROW(kp.getPureDomainKEK(), Exc::InternalError);
389 }
390
391 NEGATIVE_TEST_CASE(migration)
392 {
393         // migration may only happen in case of openssl backend
394         auto wrappedDKEKbuffer = makeDefaultWrappedDomainKEK(CryptoBackend::OpenSSL);
395
396         KeyProvider kp(RawBuffer(), "whatever");
397         BOOST_REQUIRE(!kp.isInitialized());
398
399         // migration possible only from old shorter format
400         BOOST_REQUIRE_THROW(kp.migrateDomainKEK(wrappedDKEKbuffer, PASSWORD), Exc::InternalError);
401         BOOST_REQUIRE(!kp.isInitialized());
402
403         auto wrappedOldDKEKbuffer = convertToOldFormat(wrappedDKEKbuffer);
404
405         KeyProvider kp2(wrappedOldDKEKbuffer, PASSWORD);
406         BOOST_REQUIRE(!kp2.isInitialized());
407         BOOST_REQUIRE_THROW(kp2.migrateDomainKEK(wrappedOldDKEKbuffer, INCORRECT_PASSWORD),
408                             Exc::AuthenticationFailed);
409         BOOST_REQUIRE(!kp2.isInitialized());
410 }
411
412 POSITIVE_TEST_CASE(migration)
413 {
414         // migration may only happen in case of openssl backend
415         auto wrappedDKEKbuffer = makeDefaultWrappedDomainKEK(CryptoBackend::OpenSSL);
416         KeyProvider kp(wrappedDKEKbuffer, PASSWORD);
417
418         auto wrappedOldDKEKbuffer = convertToOldFormat(wrappedDKEKbuffer);
419
420         KeyProvider kp2;
421         BOOST_REQUIRE_NO_THROW(kp2 = KeyProvider(wrappedOldDKEKbuffer, PASSWORD));
422         BOOST_REQUIRE(!kp2.isInitialized());
423         BOOST_REQUIRE_NO_THROW(kp2.migrateDomainKEK(wrappedOldDKEKbuffer, PASSWORD));
424         BOOST_REQUIRE(kp2.isInitialized());
425
426         BOOST_REQUIRE(kp.getPureDomainKEK() == kp2.getPureDomainKEK());
427
428         checkVersionAndBackend(kp2.getWrappedDomainKEK("whatever"));
429 }
430
431 NEGATIVE_TEST_CASE(version)
432 {
433         auto wrappedDKEKbuffer = makeDefaultWrappedDomainKEK();
434         DomainKEKAndInfo wrappedDKEK(wrappedDKEKbuffer);
435         wrappedDKEK.info.version = 0;
436
437         auto wrappedWrongVersionBuffer = toRawBuffer(wrappedDKEK);
438         BOOST_REQUIRE_THROW(KeyProvider(wrappedWrongVersionBuffer, PASSWORD), Exc::InternalError);
439 }
440
441 NEGATIVE_TEST_CASE(backend)
442 {
443         auto throwForBackend = [](CryptoBackend backend){
444                 BOOST_REQUIRE_THROW(KeyProvider(makeDefaultWrappedDomainKEK(backend), PASSWORD),
445                                     Exc::InternalError);
446         };
447
448         throwForBackend(CryptoBackend::None);
449         throwForBackend(CryptoBackend::TrustZone);
450         throwForBackend(static_cast<CryptoBackend>(999));
451
452 #ifndef SE_BACKEND_ENABLED
453         throwForBackend(CryptoBackend::SecureElement);
454 #endif
455 }
456
457 #ifdef SE_BACKEND_ENABLED
458 POSITIVE_TEST_CASE(backend)
459 {
460         KeyProvider kp;
461         BOOST_REQUIRE_NO_THROW(
462                 kp = KeyProvider(makeDefaultWrappedDomainKEK(CryptoBackend::OpenSSL), PASSWORD));
463         DomainKEKAndInfo wdkek(kp.getWrappedDomainKEK("whatever"));
464         BOOST_REQUIRE(wdkek.info.backend == static_cast<uint32_t>(CryptoBackend::OpenSSL));
465 }
466 #endif
467
468 BOOST_AUTO_TEST_SUITE_END()