blob: 5512ebd08132d4816f18e33b35c92665ea01e30e [file] [log] [blame]
Yingdi Yu0b60e7a2015-07-16 21:05:11 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventocafa4022017-09-15 23:20:20 -04002/*
Junxiao Shi5c1c4442018-07-18 07:56:44 -06003 * Copyright (c) 2013-2018 Regents of the University of California.
Yingdi Yu0b60e7a2015-07-16 21:05:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "security/tpm/back-end.hpp"
Davide Pesavento13fffa32018-09-30 16:21:33 -040023
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070024#include "encoding/buffer-stream.hpp"
25#include "security/pib/key.hpp"
Davide Pesavento13fffa32018-09-30 16:21:33 -040026#include "security/tpm/key-handle.hpp"
27#include "security/tpm/tpm.hpp"
28#include "security/transform/bool-sink.hpp"
29#include "security/transform/buffer-source.hpp"
30#include "security/transform/private-key.hpp"
31#include "security/transform/public-key.hpp"
32#include "security/transform/verifier-filter.hpp"
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070033
34#include "back-end-wrapper-file.hpp"
35#include "back-end-wrapper-mem.hpp"
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050036#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070037#include "back-end-wrapper-osx.hpp"
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050038#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS
Davide Pesaventocafa4022017-09-15 23:20:20 -040039
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070040#include "boost-test.hpp"
41
Davide Pesaventocafa4022017-09-15 23:20:20 -040042#include <boost/mpl/vector.hpp>
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070043#include <set>
44
45namespace ndn {
46namespace security {
47namespace tpm {
48namespace tests {
49
50BOOST_AUTO_TEST_SUITE(Security)
51BOOST_AUTO_TEST_SUITE(Tpm)
52BOOST_AUTO_TEST_SUITE(TestBackEnd)
53
54using tpm::Tpm;
55
Davide Pesaventocafa4022017-09-15 23:20:20 -040056using TestBackEnds = boost::mpl::vector<
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050057#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070058 BackEndWrapperOsx,
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050059#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070060 BackEndWrapperMem,
Davide Pesaventocafa4022017-09-15 23:20:20 -040061 BackEndWrapperFile>;
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070062
63BOOST_AUTO_TEST_CASE_TEMPLATE(KeyManagement, T, TestBackEnds)
64{
65 T wrapper;
66 BackEnd& tpm = wrapper.getTpm();
67
68 Name identity("/Test/KeyName");
69 name::Component keyId("1");
70 Name keyName = v2::constructKeyName(identity, keyId);
71
72 // key should not exist
73 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
74 BOOST_CHECK(tpm.getKeyHandle(keyName) == nullptr);
75
76 // create key, should exist
77 BOOST_CHECK(tpm.createKey(identity, RsaKeyParams(keyId)) != nullptr);
78 BOOST_CHECK(tpm.hasKey(keyName));
79 BOOST_CHECK(tpm.getKeyHandle(keyName) != nullptr);
80
81 // create a key with the same name, should throw error
82 BOOST_CHECK_THROW(tpm.createKey(identity, RsaKeyParams(keyId)), Tpm::Error);
83
84 // delete key, should not exist
85 tpm.deleteKey(keyName);
86 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
87 BOOST_CHECK(tpm.getKeyHandle(keyName) == nullptr);
88}
89
90BOOST_AUTO_TEST_CASE_TEMPLATE(RsaSigning, T, TestBackEnds)
91{
92 T wrapper;
93 BackEnd& tpm = wrapper.getTpm();
94
Davide Pesavento13fffa32018-09-30 16:21:33 -040095 // create an RSA key
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070096 Name identity("/Test/KeyName");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070097 unique_ptr<KeyHandle> key = tpm.createKey(identity, RsaKeyParams());
98 Name keyName = key->getKeyName();
99
100 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
101 Block sigBlock(tlv::SignatureValue, key->sign(DigestAlgorithm::SHA256, content, sizeof(content)));
102
103 transform::PublicKey pubKey;
104 ConstBufferPtr pubKeyBits = key->derivePublicKey();
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400105 pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700106
107 bool result;
108 {
109 using namespace transform;
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400110 bufferSource(content, sizeof(content)) >>
111 verifierFilter(DigestAlgorithm::SHA256, pubKey, sigBlock.value(), sigBlock.value_size()) >>
112 boolSink(result);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700113 }
114 BOOST_CHECK_EQUAL(result, true);
115
116 tpm.deleteKey(keyName);
117 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
118}
119
120BOOST_AUTO_TEST_CASE_TEMPLATE(RsaDecryption, T, TestBackEnds)
121{
122 T wrapper;
123 BackEnd& tpm = wrapper.getTpm();
124
Davide Pesavento13fffa32018-09-30 16:21:33 -0400125 // create an RSA key
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700126 Name identity("/Test/KeyName");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700127 unique_ptr<KeyHandle> key = tpm.createKey(identity, RsaKeyParams());
128 Name keyName = key->getKeyName();
129
130 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
131
132 transform::PublicKey pubKey;
133 ConstBufferPtr pubKeyBits = key->derivePublicKey();
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400134 pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700135
136 ConstBufferPtr cipherText = pubKey.encrypt(content, sizeof(content));
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400137 ConstBufferPtr plainText = key->decrypt(cipherText->data(), cipherText->size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700138
139 BOOST_CHECK_EQUAL_COLLECTIONS(content, content + sizeof(content),
140 plainText->begin(), plainText->end());
141
142 tpm.deleteKey(keyName);
143 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
144}
145
146BOOST_AUTO_TEST_CASE_TEMPLATE(EcdsaSigning, T, TestBackEnds)
147{
148 T wrapper;
149 BackEnd& tpm = wrapper.getTpm();
150
Davide Pesavento13fffa32018-09-30 16:21:33 -0400151 // create an EC key
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700152 Name identity("/Test/Ec/KeyName");
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700153 unique_ptr<KeyHandle> key = tpm.createKey(identity, EcKeyParams());
154 Name ecKeyName = key->getKeyName();
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700155
156 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
157 Block sigBlock(tlv::SignatureValue, key->sign(DigestAlgorithm::SHA256, content, sizeof(content)));
158
159 transform::PublicKey pubKey;
160 ConstBufferPtr pubKeyBits = key->derivePublicKey();
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400161 pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700162
163 bool result;
164 {
165 using namespace transform;
166 bufferSource(content, sizeof(content)) >> verifierFilter(DigestAlgorithm::SHA256, pubKey,
167 sigBlock.value(), sigBlock.value_size())
168 >> boolSink(result);
169 }
170 BOOST_CHECK_EQUAL(result, true);
171
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700172 tpm.deleteKey(ecKeyName);
173 BOOST_CHECK_EQUAL(tpm.hasKey(ecKeyName), false);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700174}
175
176BOOST_AUTO_TEST_CASE_TEMPLATE(ImportExport, T, TestBackEnds)
177{
Davide Pesavento13fffa32018-09-30 16:21:33 -0400178 const std::string privKeyPkcs1 =
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700179 "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n"
180 "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n"
181 "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n"
182 "c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9gZwIL5PuE9BiO6I39cL9z7EK1SfZh\n"
183 "OWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA9rH58ynaAix0tcR/nBMRLUX+e3rU\n"
184 "RHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0ywIDAQABAoIBADQkckOIl4IZMUTn\n"
185 "W8LFv6xOdkJwMKC8G6bsPRFbyY+HvC2TLt7epSvfS+f4AcYWaOPcDu2E49vt2sNr\n"
186 "cASly8hgwiRRAB3dHH9vcsboiTo8bi2RFvMqvjv9w3tK2yMxVDtmZamzrrnaV3YV\n"
187 "Q+5nyKo2F/PMDjQ4eUAKDOzjhBuKHsZBTFnA1MFNI+UKj5X4Yp64DFmKlxTX/U2b\n"
188 "wzVywo5hzx2Uhw51jmoLls4YUvMJXD0wW5ZtYRuPogXvXb/of9ef/20/wU11WFKg\n"
189 "Xb4gfR8zUXaXS1sXcnVm3+24vIs9dApUwykuoyjOqxWqcHRec2QT2FxVGkFEraze\n"
190 "CPa4rMECgYEA5Y8CywomIcTgerFGFCeMHJr8nQGqY2V/owFb3k9maczPnC9p4a9R\n"
191 "c5szLxA9FMYFxurQZMBWSEG2JS1HR2mnjigx8UKjYML/A+rvvjZOMe4M6Sy2ggh4\n"
192 "SkLZKpWTzjTe07ByM/j5v/SjNZhWAG7sw4/LmPGRQkwJv+KZhGojuOkCgYEA2cOF\n"
193 "T6cJRv6kvzTz9S0COZOVm+euJh/BXp7oAsAmbNfOpckPMzqHXy8/wpdKl6AAcB57\n"
194 "OuztlNfV1D7qvbz7JuRlYwQ0cEfBgbZPcz1p18HHDXhwn57ZPb8G33Yh9Omg0HNA\n"
195 "Imb4LsVuSqxA6NwSj7cpRekgTedrhLFPJ+Ydb5MCgYEAsM3Q7OjILcIg0t6uht9e\n"
196 "vrlwTsz1mtCV2co2I6crzdj9HeI2vqf1KAElDt6G7PUHhglcr/yjd8uEqmWRPKNX\n"
197 "ddnnfVZB10jYeP/93pac6z/Zmc3iU4yKeUe7U10ZFf0KkiiYDQd59CpLef/2XScS\n"
198 "HB0oRofnxRQjfjLc4muNT+ECgYEAlcDk06MOOTly+F8lCc1bA1dgAmgwFd2usDBd\n"
199 "Y07a3e0HGnGLN3Kfl7C5i0tZq64HvxLnMd2vgLVxQlXGPpdQrC1TH+XLXg+qnlZO\n"
200 "ivSH7i0/gx75bHvj75eH1XK65V8pDVDEoSPottllAIs21CxLw3N1ObOZWJm2EfmR\n"
201 "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n"
202 "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n"
203 "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n";
Davide Pesavento13fffa32018-09-30 16:21:33 -0400204 const std::string password("password");
205 const std::string wrongPassword("wrong");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700206
207 T wrapper;
208 BackEnd& tpm = wrapper.getTpm();
209
210 Name keyName("/Test/KeyName/KEY/1");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700211 tpm.deleteKey(keyName);
Davide Pesavento13fffa32018-09-30 16:21:33 -0400212 BOOST_REQUIRE_EQUAL(tpm.hasKey(keyName), false);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700213
214 transform::PrivateKey sKey;
Davide Pesavento13fffa32018-09-30 16:21:33 -0400215 sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privKeyPkcs1.data()), privKeyPkcs1.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700216 OBufferStream os;
Davide Pesavento13fffa32018-09-30 16:21:33 -0400217 sKey.savePkcs8(os, password.data(), password.size());
218 auto pkcs8 = os.buf();
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700219
Davide Pesavento13fffa32018-09-30 16:21:33 -0400220 // import with wrong password
221 BOOST_CHECK_THROW(tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), wrongPassword.data(), wrongPassword.size()),
222 BackEnd::Error);
223 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
224
225 // import with correct password
226 tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), password.data(), password.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700227 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
Davide Pesavento13fffa32018-09-30 16:21:33 -0400228
229 // import already present key
230 BOOST_CHECK_THROW(tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), password.data(), password.size()),
Davide Pesavento82d6a4c2017-12-23 19:47:20 -0500231 BackEnd::Error);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700232
Davide Pesavento13fffa32018-09-30 16:21:33 -0400233 // test derivePublicKey with the imported key
234 auto keyHdl = tpm.getKeyHandle(keyName);
235 auto pubKey = keyHdl->derivePublicKey();
236 BOOST_CHECK(pubKey != nullptr);
237
238 // export
239 auto exportedKey = tpm.exportKey(keyName, password.data(), password.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700240 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
241
242 transform::PrivateKey sKey2;
Davide Pesavento13fffa32018-09-30 16:21:33 -0400243 sKey2.loadPkcs8(exportedKey->data(), exportedKey->size(), password.data(), password.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700244 OBufferStream os2;
245 sKey.savePkcs1Base64(os2);
Davide Pesavento13fffa32018-09-30 16:21:33 -0400246 auto pkcs1 = os2.buf();
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700247
Davide Pesavento13fffa32018-09-30 16:21:33 -0400248 // verify that the exported key is identical to the key that was imported
249 BOOST_CHECK_EQUAL_COLLECTIONS(privKeyPkcs1.begin(), privKeyPkcs1.end(),
250 pkcs1->begin(), pkcs1->end());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700251
Davide Pesavento13fffa32018-09-30 16:21:33 -0400252 // export nonexistent key
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700253 tpm.deleteKey(keyName);
254 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
Davide Pesavento13fffa32018-09-30 16:21:33 -0400255 BOOST_CHECK_THROW(tpm.exportKey(keyName, password.data(), password.size()), BackEnd::Error);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700256}
257
258BOOST_AUTO_TEST_CASE(RandomKeyId)
259{
260 BackEndWrapperMem wrapper;
261 BackEnd& tpm = wrapper.getTpm();
262 Name identity("/Test/KeyName");
263
264 std::set<Name> keyNames;
265 for (int i = 0; i < 100; i++) {
266 auto key = tpm.createKey(identity, RsaKeyParams());
267 Name keyName = key->getKeyName();
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700268 BOOST_CHECK(keyNames.insert(keyName).second);
269 }
270}
271
272BOOST_AUTO_TEST_SUITE_END() // TestBackEnd
273BOOST_AUTO_TEST_SUITE_END() // Tpm
274BOOST_AUTO_TEST_SUITE_END() // Security
275
276} // namespace tests
277} // namespace tpm
278} // namespace security
279} // namespace ndn