blob: 9f7104d544470c92272574bc6292f568ca61ce0e [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/*
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -07003 * Copyright (c) 2013-2017 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"
23#include "security/tpm/back-end-mem.hpp"
24#include "security/tpm/key-handle.hpp"
25#include "security/tpm/tpm.hpp"
26#include "security/transform.hpp"
27#include "security/transform/public-key.hpp"
28#include "security/transform/private-key.hpp"
29#include "encoding/buffer-stream.hpp"
30#include "security/pib/key.hpp"
31
32#include "back-end-wrapper-file.hpp"
33#include "back-end-wrapper-mem.hpp"
Alexander Afanasyev0cf887d2017-03-26 16:58:59 -050034#ifdef NDN_CXX_HAVE_OSX_FRAMEWORKS
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070035#include "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
Yingdi Yu0b60e7a2015-07-16 21:05:11 -070038#include "boost-test.hpp"
39
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
88BOOST_AUTO_TEST_CASE_TEMPLATE(RsaSigning, T, TestBackEnds)
89{
90 T wrapper;
91 BackEnd& tpm = wrapper.getTpm();
92
93 // create an rsa key
94 Name identity("/Test/KeyName");
95
96 unique_ptr<KeyHandle> key = tpm.createKey(identity, RsaKeyParams());
97 Name keyName = key->getKeyName();
98
99 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
100 Block sigBlock(tlv::SignatureValue, key->sign(DigestAlgorithm::SHA256, content, sizeof(content)));
101
102 transform::PublicKey pubKey;
103 ConstBufferPtr pubKeyBits = key->derivePublicKey();
104 pubKey.loadPkcs8(pubKeyBits->buf(), pubKeyBits->size());
105
106 bool result;
107 {
108 using namespace transform;
109 bufferSource(content, sizeof(content)) >> verifierFilter(DigestAlgorithm::SHA256, pubKey,
110 sigBlock.value(), sigBlock.value_size())
111 >> boolSink(result);
112 }
113 BOOST_CHECK_EQUAL(result, true);
114
115 tpm.deleteKey(keyName);
116 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
117}
118
119BOOST_AUTO_TEST_CASE_TEMPLATE(RsaDecryption, T, TestBackEnds)
120{
121 T wrapper;
122 BackEnd& tpm = wrapper.getTpm();
123
124 // create an rsa key
125 Name identity("/Test/KeyName");
126
127 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();
134 pubKey.loadPkcs8(pubKeyBits->buf(), pubKeyBits->size());
135
136 ConstBufferPtr cipherText = pubKey.encrypt(content, sizeof(content));
137
138 ConstBufferPtr plainText = key->decrypt(cipherText->buf(), cipherText->size());
139
140 BOOST_CHECK_EQUAL_COLLECTIONS(content, content + sizeof(content),
141 plainText->begin(), plainText->end());
142
143 tpm.deleteKey(keyName);
144 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
145}
146
147BOOST_AUTO_TEST_CASE_TEMPLATE(EcdsaSigning, T, TestBackEnds)
148{
149 T wrapper;
150 BackEnd& tpm = wrapper.getTpm();
151
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700152 // create an ec key
153 Name identity("/Test/Ec/KeyName");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700154
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700155 unique_ptr<KeyHandle> key = tpm.createKey(identity, EcKeyParams());
156 Name ecKeyName = key->getKeyName();
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700157
158 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
159 Block sigBlock(tlv::SignatureValue, key->sign(DigestAlgorithm::SHA256, content, sizeof(content)));
160
161 transform::PublicKey pubKey;
162 ConstBufferPtr pubKeyBits = key->derivePublicKey();
163 pubKey.loadPkcs8(pubKeyBits->buf(), pubKeyBits->size());
164
165 bool result;
166 {
167 using namespace transform;
168 bufferSource(content, sizeof(content)) >> verifierFilter(DigestAlgorithm::SHA256, pubKey,
169 sigBlock.value(), sigBlock.value_size())
170 >> boolSink(result);
171 }
172 BOOST_CHECK_EQUAL(result, true);
173
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700174 tpm.deleteKey(ecKeyName);
175 BOOST_CHECK_EQUAL(tpm.hasKey(ecKeyName), false);
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700176}
177
178BOOST_AUTO_TEST_CASE_TEMPLATE(ImportExport, T, TestBackEnds)
179{
Davide Pesaventocafa4022017-09-15 23:20:20 -0400180 const std::string privateKeyPkcs1 =
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700181 "MIIEpAIBAAKCAQEAw0WM1/WhAxyLtEqsiAJgWDZWuzkYpeYVdeeZcqRZzzfRgBQT\n"
182 "sNozS5t4HnwTZhwwXbH7k3QN0kRTV826Xobws3iigohnM9yTK+KKiayPhIAm/+5H\n"
183 "GT6SgFJhYhqo1/upWdueojil6RP4/AgavHhopxlAVbk6G9VdVnlQcQ5Zv0OcGi73\n"
184 "c+EnYD/YgURYGSngUi/Ynsh779p2U69/te9gZwIL5PuE9BiO6I39cL9z7EK1SfZh\n"
185 "OWvDe/qH7YhD/BHwcWit8FjRww1glwRVTJsA9rH58ynaAix0tcR/nBMRLUX+e3rU\n"
186 "RHg6UbSjJbdb9qmKM1fTGHKUzL/5pMG6uBU0ywIDAQABAoIBADQkckOIl4IZMUTn\n"
187 "W8LFv6xOdkJwMKC8G6bsPRFbyY+HvC2TLt7epSvfS+f4AcYWaOPcDu2E49vt2sNr\n"
188 "cASly8hgwiRRAB3dHH9vcsboiTo8bi2RFvMqvjv9w3tK2yMxVDtmZamzrrnaV3YV\n"
189 "Q+5nyKo2F/PMDjQ4eUAKDOzjhBuKHsZBTFnA1MFNI+UKj5X4Yp64DFmKlxTX/U2b\n"
190 "wzVywo5hzx2Uhw51jmoLls4YUvMJXD0wW5ZtYRuPogXvXb/of9ef/20/wU11WFKg\n"
191 "Xb4gfR8zUXaXS1sXcnVm3+24vIs9dApUwykuoyjOqxWqcHRec2QT2FxVGkFEraze\n"
192 "CPa4rMECgYEA5Y8CywomIcTgerFGFCeMHJr8nQGqY2V/owFb3k9maczPnC9p4a9R\n"
193 "c5szLxA9FMYFxurQZMBWSEG2JS1HR2mnjigx8UKjYML/A+rvvjZOMe4M6Sy2ggh4\n"
194 "SkLZKpWTzjTe07ByM/j5v/SjNZhWAG7sw4/LmPGRQkwJv+KZhGojuOkCgYEA2cOF\n"
195 "T6cJRv6kvzTz9S0COZOVm+euJh/BXp7oAsAmbNfOpckPMzqHXy8/wpdKl6AAcB57\n"
196 "OuztlNfV1D7qvbz7JuRlYwQ0cEfBgbZPcz1p18HHDXhwn57ZPb8G33Yh9Omg0HNA\n"
197 "Imb4LsVuSqxA6NwSj7cpRekgTedrhLFPJ+Ydb5MCgYEAsM3Q7OjILcIg0t6uht9e\n"
198 "vrlwTsz1mtCV2co2I6crzdj9HeI2vqf1KAElDt6G7PUHhglcr/yjd8uEqmWRPKNX\n"
199 "ddnnfVZB10jYeP/93pac6z/Zmc3iU4yKeUe7U10ZFf0KkiiYDQd59CpLef/2XScS\n"
200 "HB0oRofnxRQjfjLc4muNT+ECgYEAlcDk06MOOTly+F8lCc1bA1dgAmgwFd2usDBd\n"
201 "Y07a3e0HGnGLN3Kfl7C5i0tZq64HvxLnMd2vgLVxQlXGPpdQrC1TH+XLXg+qnlZO\n"
202 "ivSH7i0/gx75bHvj75eH1XK65V8pDVDEoSPottllAIs21CxLw3N1ObOZWJm2EfmR\n"
203 "cuHICmsCgYAtFJ1idqMoHxES3mlRpf2JxyQudP3SCm2WpGmqVzhRYInqeatY5sUd\n"
204 "lPLHm/p77RT7EyxQHTlwn8FJPuM/4ZH1rQd/vB+Y8qAtYJCexDMsbvLW+Js+VOvk\n"
205 "jweEC0nrcL31j9mF0vz5E6tfRu4hhJ6L4yfWs0gSejskeVB/w8QY4g==\n";
206
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);
212 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
213
214 transform::PrivateKey sKey;
Davide Pesaventocafa4022017-09-15 23:20:20 -0400215 sKey.loadPkcs1Base64(reinterpret_cast<const uint8_t*>(privateKeyPkcs1.c_str()), privateKeyPkcs1.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700216
217 std::string password("password");
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700218 OBufferStream os;
219 sKey.savePkcs8(os, password.c_str(), password.size());
220 ConstBufferPtr privateKeyBuffer = os.buf();
221
Davide Pesaventocafa4022017-09-15 23:20:20 -0400222 tpm.importKey(keyName, privateKeyBuffer->buf(), privateKeyBuffer->size(), password.c_str(), password.size());
Yingdi Yu0b60e7a2015-07-16 21:05:11 -0700223 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
224
225 ConstBufferPtr exportedKey = tpm.exportKey(keyName, password.c_str(), password.size());
226 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), true);
227
228 transform::PrivateKey sKey2;
229 sKey2.loadPkcs8(exportedKey->buf(), exportedKey->size(), password.c_str(), password.size());
230 OBufferStream os2;
231 sKey.savePkcs1Base64(os2);
232 ConstBufferPtr pkcs1Buffer = os2.buf();
233
234 BOOST_CHECK_EQUAL_COLLECTIONS(privateKeyPkcs1.begin(), privateKeyPkcs1.end(),
235 pkcs1Buffer->begin(), pkcs1Buffer->end());
236
237 tpm.deleteKey(keyName);
238 BOOST_CHECK_EQUAL(tpm.hasKey(keyName), false);
239}
240
241BOOST_AUTO_TEST_CASE(RandomKeyId)
242{
243 BackEndWrapperMem wrapper;
244 BackEnd& tpm = wrapper.getTpm();
245 Name identity("/Test/KeyName");
246
247 std::set<Name> keyNames;
248 for (int i = 0; i < 100; i++) {
249 auto key = tpm.createKey(identity, RsaKeyParams());
250 Name keyName = key->getKeyName();
251 tpm.deleteKey(keyName);
252 BOOST_CHECK(keyNames.insert(keyName).second);
253 }
254}
255
256BOOST_AUTO_TEST_SUITE_END() // TestBackEnd
257BOOST_AUTO_TEST_SUITE_END() // Tpm
258BOOST_AUTO_TEST_SUITE_END() // Security
259
260} // namespace tests
261} // namespace tpm
262} // namespace security
263} // namespace ndn