blob: 8d4b41a3ca43c17b8675c7892302a88d5eb5eb15 [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/*
laqinfancf0baa22019-06-03 15:33:58 -05003 * Copyright (c) 2013-2019 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
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/security/tpm/back-end.hpp"
Davide Pesavento13fffa32018-09-30 16:21:33 -040023
Davide Pesavento7e780642018-11-24 15:51:34 -050024#include "ndn-cxx/encoding/buffer-stream.hpp"
25#include "ndn-cxx/security/pib/key.hpp"
Davide Pesavento7e780642018-11-24 15:51:34 -050026#include "ndn-cxx/security/transform/bool-sink.hpp"
27#include "ndn-cxx/security/transform/buffer-source.hpp"
28#include "ndn-cxx/security/transform/private-key.hpp"
29#include "ndn-cxx/security/transform/public-key.hpp"
30#include "ndn-cxx/security/transform/verifier-filter.hpp"
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070031
Davide Pesavento7e780642018-11-24 15:51:34 -050032#include "tests/unit/security/tpm/back-end-wrapper-file.hpp"
33#include "tests/unit/security/tpm/back-end-wrapper-mem.hpp"
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050034#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
Davide Pesavento7e780642018-11-24 15:51:34 -050035#include "tests/unit/security/tpm/back-end-wrapper-osx.hpp"
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050036#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS
Davide Pesaventocafa4022017-09-15 23:20:20 -040037
Davide Pesavento7e780642018-11-24 15:51:34 -050038#include "tests/boost-test.hpp"
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070039
Davide Pesaventocafa4022017-09-15 23:20:20 -040040#include <boost/mpl/vector.hpp>
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070041#include <set>
42
43namespace ndn {
44namespace security {
45namespace tpm {
46namespace tests {
47
48BOOST_AUTO_TEST_SUITE(Security)
49BOOST_AUTO_TEST_SUITE(Tpm)
50BOOST_AUTO_TEST_SUITE(TestBackEnd)
51
52using tpm::Tpm;
53
Davide Pesaventocafa4022017-09-15 23:20:20 -040054using TestBackEnds = boost::mpl::vector<
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050055#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070056 BackEndWrapperOsx,
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050057#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070058 BackEndWrapperMem,
Davide Pesaventocafa4022017-09-15 23:20:20 -040059 BackEndWrapperFile>;
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070060
61BOOST_AUTO_TEST_CASE_TEMPLATE(KeyManagement, T, TestBackEnds)
62{
63 T wrapper;
64 BackEnd& tpm = wrapper.getTpm();
65
66 Name identity("/Test/KeyName");
67 name::Component keyId("1");
68 Name keyName = v2::constructKeyName(identity, keyId);
69
70 // key should not exist
71 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
72 BOOST_CHECK(tpm.getKeyHandle(keyName) == nullptr);
73
74 // create key, should exist
75 BOOST_CHECK(tpm.createKey(identity, RsaKeyParams(keyId)) != nullptr);
76 BOOST_CHECK(tpm.hasKey(keyName));
77 BOOST_CHECK(tpm.getKeyHandle(keyName) != nullptr);
78
79 // create a key with the same name, should throw error
80 BOOST_CHECK_THROW(tpm.createKey(identity, RsaKeyParams(keyId)), Tpm::Error);
81
82 // delete key, should not exist
83 tpm.deleteKey(keyName);
84 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
85 BOOST_CHECK(tpm.getKeyHandle(keyName) == nullptr);
86}
87
laqinfan56a812d2019-06-03 15:33:58 -050088BOOST_AUTO_TEST_CASE(CreateHmacKey)
89{
90 Name identity("/Test/Identity/HMAC");
91
92 BackEndWrapperMem mem;
93 BackEnd& memTpm = mem.getTpm();
94 auto key = memTpm.createKey(identity, HmacKeyParams());
95 BOOST_REQUIRE(key != nullptr);
96 BOOST_CHECK(!key->getKeyName().empty());
97 BOOST_CHECK(memTpm.hasKey(key->getKeyName()));
98
99 BackEndWrapperFile file;
100 BackEnd& fileTpm = file.getTpm();
Davide Pesavento12cef872019-10-31 02:24:03 -0400101 BOOST_CHECK_THROW(fileTpm.createKey(identity, HmacKeyParams()), std::invalid_argument);
laqinfan56a812d2019-06-03 15:33:58 -0500102
103#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
104 BackEndWrapperOsx osx;
105 BackEnd& osxTpm = osx.getTpm();
Davide Pesavento12cef872019-10-31 02:24:03 -0400106 BOOST_CHECK_THROW(osxTpm.createKey(identity, HmacKeyParams()), std::invalid_argument);
laqinfan56a812d2019-06-03 15:33:58 -0500107#endif // NDN_CXX_HAVE_OSX_FRAMEWORKS
108}
109
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700110BOOST_AUTO_TEST_CASE_TEMPLATE(RsaSigning, T, TestBackEnds)
111{
112 T wrapper;
113 BackEnd& tpm = wrapper.getTpm();
114
Davide Pesavento13fffa32018-09-30 16:21:33 -0400115 // create an RSA key
laqinfancf0baa22019-06-03 15:33:58 -0500116 Name identity("/Test/RSA/KeyName");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700117 unique_ptr<KeyHandle> key = tpm.createKey(identity, RsaKeyParams());
118 Name keyName = key->getKeyName();
119
120 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
laqinfancf0baa22019-06-03 15:33:58 -0500121 auto sigValue = key->sign(DigestAlgorithm::SHA256, content, sizeof(content));
122 BOOST_REQUIRE(sigValue != nullptr);
123 Block sigBlock(tlv::SignatureValue, sigValue);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700124
125 transform::PublicKey pubKey;
126 ConstBufferPtr pubKeyBits = key->derivePublicKey();
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400127 pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700128
129 bool result;
130 {
131 using namespace transform;
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400132 bufferSource(content, sizeof(content)) >>
133 verifierFilter(DigestAlgorithm::SHA256, pubKey, sigBlock.value(), sigBlock.value_size()) >>
134 boolSink(result);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700135 }
136 BOOST_CHECK_EQUAL(result, true);
137
138 tpm.deleteKey(keyName);
139 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
140}
141
142BOOST_AUTO_TEST_CASE_TEMPLATE(RsaDecryption, T, TestBackEnds)
143{
144 T wrapper;
145 BackEnd& tpm = wrapper.getTpm();
146
Davide Pesavento13fffa32018-09-30 16:21:33 -0400147 // create an RSA key
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700148 Name identity("/Test/KeyName");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700149 unique_ptr<KeyHandle> key = tpm.createKey(identity, RsaKeyParams());
150 Name keyName = key->getKeyName();
151
152 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
153
154 transform::PublicKey pubKey;
155 ConstBufferPtr pubKeyBits = key->derivePublicKey();
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400156 pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700157
158 ConstBufferPtr cipherText = pubKey.encrypt(content, sizeof(content));
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400159 ConstBufferPtr plainText = key->decrypt(cipherText->data(), cipherText->size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700160
161 BOOST_CHECK_EQUAL_COLLECTIONS(content, content + sizeof(content),
162 plainText->begin(), plainText->end());
163
164 tpm.deleteKey(keyName);
165 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
166}
167
168BOOST_AUTO_TEST_CASE_TEMPLATE(EcdsaSigning, T, TestBackEnds)
169{
170 T wrapper;
171 BackEnd& tpm = wrapper.getTpm();
172
Davide Pesavento13fffa32018-09-30 16:21:33 -0400173 // create an EC key
laqinfancf0baa22019-06-03 15:33:58 -0500174 Name identity("/Test/EC/KeyName");
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700175 unique_ptr<KeyHandle> key = tpm.createKey(identity, EcKeyParams());
176 Name ecKeyName = key->getKeyName();
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700177
178 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
laqinfancf0baa22019-06-03 15:33:58 -0500179 auto sigValue = key->sign(DigestAlgorithm::SHA256, content, sizeof(content));
180 BOOST_REQUIRE(sigValue != nullptr);
181 Block sigBlock(tlv::SignatureValue, sigValue);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700182
183 transform::PublicKey pubKey;
184 ConstBufferPtr pubKeyBits = key->derivePublicKey();
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400185 pubKey.loadPkcs8(pubKeyBits->data(), pubKeyBits->size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700186
187 bool result;
188 {
189 using namespace transform;
laqinfancf0baa22019-06-03 15:33:58 -0500190 bufferSource(content, sizeof(content)) >>
191 verifierFilter(DigestAlgorithm::SHA256, pubKey, sigBlock.value(), sigBlock.value_size()) >>
192 boolSink(result);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700193 }
194 BOOST_CHECK_EQUAL(result, true);
195
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700196 tpm.deleteKey(ecKeyName);
197 BOOST_CHECK_EQUAL(tpm.hasKey(ecKeyName), false);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700198}
199
laqinfancf0baa22019-06-03 15:33:58 -0500200BOOST_AUTO_TEST_CASE(HmacSigningAndVerifying)
201{
202 BackEndWrapperMem wrapper;
203 BackEnd& tpm = wrapper.getTpm();
204
205 // create an HMAC key
206 Name identity("/Test/HMAC/KeyName");
207 unique_ptr<KeyHandle> key = tpm.createKey(identity, HmacKeyParams());
208 Name hmacKeyName = key->getKeyName();
209
210 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
211 auto sigValue = key->sign(DigestAlgorithm::SHA256, content, sizeof(content));
212 BOOST_REQUIRE(sigValue != nullptr);
213 Block sigBlock(tlv::SignatureValue, sigValue);
214
215 bool result = key->verify(DigestAlgorithm::SHA256, content, sizeof(content),
216 sigBlock.value(), sigBlock.value_size());
217 BOOST_CHECK_EQUAL(result, true);
218
219 tpm.deleteKey(hmacKeyName);
220 BOOST_CHECK_EQUAL(tpm.hasKey(hmacKeyName), false);
221}
222
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700223BOOST_AUTO_TEST_CASE_TEMPLATE(ImportExport, T, TestBackEnds)
224{
Davide Pesavento13fffa32018-09-30 16:21:33 -0400225 const std::string privKeyPkcs1 =
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700226 "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n"
227 "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n"
228 "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n"
229 "c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9gZwIL5PuE9BiO6I39cL9z7EK1SfZh\n"
230 "OWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA9rH58ynaAix0tcR/nBMRLUX+e3rU\n"
231 "RHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0ywIDAQABAoIBADQkckOIl4IZMUTn\n"
232 "W8LFv6xOdkJwMKC8G6bsPRFbyY+HvC2TLt7epSvfS+f4AcYWaOPcDu2E49vt2sNr\n"
233 "cASly8hgwiRRAB3dHH9vcsboiTo8bi2RFvMqvjv9w3tK2yMxVDtmZamzrrnaV3YV\n"
234 "Q+5nyKo2F/PMDjQ4eUAKDOzjhBuKHsZBTFnA1MFNI+UKj5X4Yp64DFmKlxTX/U2b\n"
235 "wzVywo5hzx2Uhw51jmoLls4YUvMJXD0wW5ZtYRuPogXvXb/of9ef/20/wU11WFKg\n"
236 "Xb4gfR8zUXaXS1sXcnVm3+24vIs9dApUwykuoyjOqxWqcHRec2QT2FxVGkFEraze\n"
237 "CPa4rMECgYEA5Y8CywomIcTgerFGFCeMHJr8nQGqY2V/owFb3k9maczPnC9p4a9R\n"
238 "c5szLxA9FMYFxurQZMBWSEG2JS1HR2mnjigx8UKjYML/A+rvvjZOMe4M6Sy2ggh4\n"
239 "SkLZKpWTzjTe07ByM/j5v/SjNZhWAG7sw4/LmPGRQkwJv+KZhGojuOkCgYEA2cOF\n"
240 "T6cJRv6kvzTz9S0COZOVm+euJh/BXp7oAsAmbNfOpckPMzqHXy8/wpdKl6AAcB57\n"
241 "OuztlNfV1D7qvbz7JuRlYwQ0cEfBgbZPcz1p18HHDXhwn57ZPb8G33Yh9Omg0HNA\n"
242 "Imb4LsVuSqxA6NwSj7cpRekgTedrhLFPJ+Ydb5MCgYEAsM3Q7OjILcIg0t6uht9e\n"
243 "vrlwTsz1mtCV2co2I6crzdj9HeI2vqf1KAElDt6G7PUHhglcr/yjd8uEqmWRPKNX\n"
244 "ddnnfVZB10jYeP/93pac6z/Zmc3iU4yKeUe7U10ZFf0KkiiYDQd59CpLef/2XScS\n"
245 "HB0oRofnxRQjfjLc4muNT+ECgYEAlcDk06MOOTly+F8lCc1bA1dgAmgwFd2usDBd\n"
246 "Y07a3e0HGnGLN3Kfl7C5i0tZq64HvxLnMd2vgLVxQlXGPpdQrC1TH+XLXg+qnlZO\n"
247 "ivSH7i0/gx75bHvj75eH1XK65V8pDVDEoSPottllAIs21CxLw3N1ObOZWJm2EfmR\n"
248 "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n"
249 "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n"
250 "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n";
Davide Pesavento13fffa32018-09-30 16:21:33 -0400251 const std::string password("password");
252 const std::string wrongPassword("wrong");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700253
254 T wrapper;
255 BackEnd& tpm = wrapper.getTpm();
256
257 Name keyName("/Test/KeyName/KEY/1");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700258 tpm.deleteKey(keyName);
Davide Pesavento13fffa32018-09-30 16:21:33 -0400259 BOOST_REQUIRE_EQUAL(tpm.hasKey(keyName), false);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700260
261 transform::PrivateKey sKey;
Davide Pesavento13fffa32018-09-30 16:21:33 -0400262 sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privKeyPkcs1.data()), privKeyPkcs1.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700263 OBufferStream os;
Davide Pesavento13fffa32018-09-30 16:21:33 -0400264 sKey.savePkcs8(os, password.data(), password.size());
265 auto pkcs8 = os.buf();
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700266
Davide Pesavento13fffa32018-09-30 16:21:33 -0400267 // import with wrong password
268 BOOST_CHECK_THROW(tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), wrongPassword.data(), wrongPassword.size()),
Davide Pesavento12cef872019-10-31 02:24:03 -0400269 Tpm::Error);
Davide Pesavento13fffa32018-09-30 16:21:33 -0400270 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
271
272 // import with correct password
273 tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), password.data(), password.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700274 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
Davide Pesavento13fffa32018-09-30 16:21:33 -0400275
276 // import already present key
277 BOOST_CHECK_THROW(tpm.importKey(keyName, pkcs8->data(), pkcs8->size(), password.data(), password.size()),
Davide Pesavento12cef872019-10-31 02:24:03 -0400278 Tpm::Error);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700279
Davide Pesavento13fffa32018-09-30 16:21:33 -0400280 // test derivePublicKey with the imported key
281 auto keyHdl = tpm.getKeyHandle(keyName);
282 auto pubKey = keyHdl->derivePublicKey();
283 BOOST_CHECK(pubKey != nullptr);
284
285 // export
286 auto exportedKey = tpm.exportKey(keyName, password.data(), password.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700287 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
288
289 transform::PrivateKey sKey2;
Davide Pesavento13fffa32018-09-30 16:21:33 -0400290 sKey2.loadPkcs8(exportedKey->data(), exportedKey->size(), password.data(), password.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700291 OBufferStream os2;
292 sKey.savePkcs1Base64(os2);
Davide Pesavento13fffa32018-09-30 16:21:33 -0400293 auto pkcs1 = os2.buf();
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700294
Davide Pesavento13fffa32018-09-30 16:21:33 -0400295 // verify that the exported key is identical to the key that was imported
296 BOOST_CHECK_EQUAL_COLLECTIONS(privKeyPkcs1.begin(), privKeyPkcs1.end(),
297 pkcs1->begin(), pkcs1->end());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700298
Davide Pesavento13fffa32018-09-30 16:21:33 -0400299 // export nonexistent key
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700300 tpm.deleteKey(keyName);
301 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
Davide Pesavento12cef872019-10-31 02:24:03 -0400302 BOOST_CHECK_THROW(tpm.exportKey(keyName, password.data(), password.size()), Tpm::Error);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700303}
304
305BOOST_AUTO_TEST_CASE(RandomKeyId)
306{
307 BackEndWrapperMem wrapper;
308 BackEnd& tpm = wrapper.getTpm();
309 Name identity("/Test/KeyName");
310
311 std::set<Name> keyNames;
312 for (int i = 0; i < 100; i++) {
313 auto key = tpm.createKey(identity, RsaKeyParams());
314 Name keyName = key->getKeyName();
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700315 BOOST_CHECK(keyNames.insert(keyName).second);
316 }
317}
318
319BOOST_AUTO_TEST_SUITE_END() // TestBackEnd
320BOOST_AUTO_TEST_SUITE_END() // Tpm
321BOOST_AUTO_TEST_SUITE_END() // Security
322
323} // namespace tests
324} // namespace tpm
325} // namespace security
326} // namespace ndn