blob: 1e590afde8586ddb07a9f1f503a431c3ee02a632 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yingdi Yu28fd32f2014-01-28 19:03:03 -08002/**
Alexander Afanasyevaf99f462015-01-19 21:43:09 -08003 * Copyright (c) 2013-2015 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * 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.
Yingdi Yu28fd32f2014-01-28 19:03:03 -080020 */
21
Yingdi Yuf56c68f2014-04-24 21:50:13 -070022#include "security/sec-tpm-osx.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070023#include "security/cryptopp.hpp"
Yingdi Yu28fd32f2014-01-28 19:03:03 -080024
Yingdi Yuf56c68f2014-04-24 21:50:13 -070025#include "util/time.hpp"
26
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070027#include <boost/lexical_cast.hpp>
Yingdi Yu9d9d5992014-06-25 12:25:16 -070028#include <Availability.h>
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070029
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070030#include "boost-test.hpp"
31
Alexander Afanasyev0abb2da2014-01-30 18:07:57 -080032namespace ndn {
Spyridon Mastorakis429634f2015-02-19 17:35:33 -080033namespace tests {
Yingdi Yu28fd32f2014-01-28 19:03:03 -080034
Yingdi Yu41546342014-11-30 23:37:53 -080035class OsxKeyChainTestFixture
36{
37public:
38 OsxKeyChainTestFixture()
39 {
40 std::string oldHOME;
41 if (std::getenv("OLD_HOME"))
42 oldHOME = std::getenv("OLD_HOME");
43
44 if (std::getenv("HOME"))
45 m_HOME = std::getenv("HOME");
46
47 if (!oldHOME.empty())
48 setenv("HOME", oldHOME.c_str(), 1);
49 else
50 unsetenv("HOME");
51 }
52
53 ~OsxKeyChainTestFixture()
54 {
55 if (!m_HOME.empty())
56 setenv("HOME", m_HOME.c_str(), 1);
57 else
58 unsetenv("HOME");
59 }
60
61protected:
62 std::string m_HOME;
63};
64
Spyridon Mastorakis429634f2015-02-19 17:35:33 -080065BOOST_FIXTURE_TEST_SUITE(SecuritySecTpmOsx, OsxKeyChainTestFixture)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080066
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070067BOOST_AUTO_TEST_CASE(Delete)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080068{
69 SecTpmOsx tpm;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070070
Yingdi Yu5e96e002014-04-23 18:32:15 -070071 Name keyName("/TestSecTpmOsx/Delete/ksk-" +
Yingdi Yu7036ce22014-06-19 18:53:37 -070072 boost::lexical_cast<std::string>(
Yingdi Yu5e96e002014-04-23 18:32:15 -070073 time::toUnixTimestamp(time::system_clock::now()).count()));
Yingdi Yu7036ce22014-06-19 18:53:37 -070074 RsaKeyParams params(2048);
75 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070076
Yingdi Yu28fd32f2014-01-28 19:03:03 -080077 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
78 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070079
Yingdi Yu28fd32f2014-01-28 19:03:03 -080080 tpm.deleteKeyPairInTpm(keyName);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070081
Yingdi Yu28fd32f2014-01-28 19:03:03 -080082 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
83 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
84}
85
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070086BOOST_AUTO_TEST_CASE(SignVerify)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080087{
88 SecTpmOsx tpm;
89
Yingdi Yu5e96e002014-04-23 18:32:15 -070090 Name keyName("/TestSecTpmOsx/SignVerify/ksk-" +
Yingdi Yu7036ce22014-06-19 18:53:37 -070091 boost::lexical_cast<std::string>(
Yingdi Yu5e96e002014-04-23 18:32:15 -070092 time::toUnixTimestamp(time::system_clock::now()).count()));
Yingdi Yu7036ce22014-06-19 18:53:37 -070093 RsaKeyParams params(2048);
94 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070095
Yingdi Yube4150e2014-02-18 13:02:46 -080096 Data data("/TestSecTpmOsx/SignVaerify/Data/1");
Yingdi Yu28fd32f2014-01-28 19:03:03 -080097 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
98
Yingdi Yu2e57a582014-02-20 23:34:43 -080099 Block sigBlock;
Yingdi Yu5e96e002014-04-23 18:32:15 -0700100 BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
101 keyName, DIGEST_ALGORITHM_SHA256));
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800102
Yingdi Yu7036ce22014-06-19 18:53:37 -0700103 shared_ptr<PublicKey> publicKey;
104 BOOST_CHECK_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName));
Yingdi Yu2e57a582014-02-20 23:34:43 -0800105 try
106 {
107 using namespace CryptoPP;
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800108
Yingdi Yu7036ce22014-06-19 18:53:37 -0700109 RSA::PublicKey rsaPublicKey;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800110 ByteQueue queue;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700111 queue.Put(reinterpret_cast<const byte*>(publicKey->get().buf()), publicKey->get().size());
112 rsaPublicKey.Load(queue);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800113
Yingdi Yu7036ce22014-06-19 18:53:37 -0700114 RSASS<PKCS1v15, SHA256>::Verifier verifier(rsaPublicKey);
115 bool isVerified = verifier.VerifyMessage(content, sizeof(content),
116 sigBlock.value(), sigBlock.value_size());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700117
Yingdi Yu7036ce22014-06-19 18:53:37 -0700118 BOOST_CHECK_EQUAL(isVerified, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800119 }
Yingdi Yu5e96e002014-04-23 18:32:15 -0700120 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800121 {
122 BOOST_CHECK(false);
123 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800124
125 tpm.deleteKeyPairInTpm(keyName);
126}
127
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700128BOOST_AUTO_TEST_CASE(RandomGenerator)
Yingdi Yu4b752752014-02-18 12:24:03 -0800129{
130 SecTpmOsx tpm;
131
132 size_t scale = 1000;
133 size_t size = 256 * scale;
134 uint8_t* block = new uint8_t[size];
135 tpm.generateRandomBlock(block, size);
136
Yingdi Yu7036ce22014-06-19 18:53:37 -0700137 std::map<uint8_t, int> counter;
138 for (size_t i = 0; i < size; i++)
139 {
140 counter[block[i]] += 1;
141 }
Yingdi Yu4b752752014-02-18 12:24:03 -0800142
143 float dev = 0.0;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700144 for (size_t i = 0; i != 255; i++)
145 {
146 dev += ((counter[i] - scale) * (counter[i] - scale)) * 1.0 / (scale * scale);
147 }
Yingdi Yu4b752752014-02-18 12:24:03 -0800148
149 BOOST_CHECK_CLOSE(dev / 256, 0.001, 100);
150
151}
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800152
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700153BOOST_AUTO_TEST_CASE(ExportImportKey)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800154{
155 using namespace CryptoPP;
156
157 SecTpmOsx tpm;
158
Yingdi Yu5e96e002014-04-23 18:32:15 -0700159 Name keyName("/TestSecTpmOsx/ExportImportKey/ksk-" +
Yingdi Yu7036ce22014-06-19 18:53:37 -0700160 boost::lexical_cast<std::string>(
Yingdi Yu5e96e002014-04-23 18:32:15 -0700161 time::toUnixTimestamp(time::system_clock::now()).count()));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700162
Yingdi Yu7036ce22014-06-19 18:53:37 -0700163 RsaKeyParams params(2048);
164 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800165
Yingdi Yu7036ce22014-06-19 18:53:37 -0700166 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
167 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800168
Yingdi Yu2e57a582014-02-20 23:34:43 -0800169 ConstBufferPtr exported;
Yingdi Yu5e96e002014-04-23 18:32:15 -0700170 BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234"));
Yingdi Yu7036ce22014-06-19 18:53:37 -0700171 shared_ptr<PublicKey> publicKey;
172 BOOST_REQUIRE_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800173
174 tpm.deleteKeyPairInTpm(keyName);
175
Yingdi Yu7036ce22014-06-19 18:53:37 -0700176 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
177 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800178
Yingdi Yu5e96e002014-04-23 18:32:15 -0700179 BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName,
180 exported->buf(), exported->size(),
181 "1234"));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700182
Yingdi Yu7036ce22014-06-19 18:53:37 -0700183 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
184 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800185
186 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
Yingdi Yu2e57a582014-02-20 23:34:43 -0800187 Block sigBlock;
Yingdi Yu5e96e002014-04-23 18:32:15 -0700188 BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
189 keyName, DIGEST_ALGORITHM_SHA256));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800190
Yingdi Yu2e57a582014-02-20 23:34:43 -0800191 try
192 {
193 using namespace CryptoPP;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800194
Yingdi Yu7036ce22014-06-19 18:53:37 -0700195 RSA::PublicKey rsaPublicKey;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800196 ByteQueue queue;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700197 queue.Put(reinterpret_cast<const byte*>(publicKey->get().buf()), publicKey->get().size());
198 rsaPublicKey.Load(queue);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800199
Yingdi Yu7036ce22014-06-19 18:53:37 -0700200 RSASS<PKCS1v15, SHA256>::Verifier verifier(rsaPublicKey);
201 bool isVerified = verifier.VerifyMessage(content, sizeof(content),
202 sigBlock.value(), sigBlock.value_size());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700203
Yingdi Yu7036ce22014-06-19 18:53:37 -0700204 BOOST_CHECK_EQUAL(isVerified, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800205 }
Yingdi Yu5e96e002014-04-23 18:32:15 -0700206 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800207 {
208 BOOST_CHECK(false);
209 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700210
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800211 tpm.deleteKeyPairInTpm(keyName);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700212 // This is some problem related to Mac OS Key chain.
213 // On OSX 10.8, we cannot delete imported keys, but there is no such problem on OSX 10.9.
214#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
215#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9
216 BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
217 BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
218#endif
219#endif
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800220}
221
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700222BOOST_AUTO_TEST_CASE(NonExistingKey)
223{
224 using namespace CryptoPP;
225
226 SecTpmOsx tpm;
227
228 Name keyName("/TestSecTpmOsx/NonExistingKey");
229
230 BOOST_REQUIRE_THROW(tpm.getPublicKeyFromTpm(keyName), SecTpmOsx::Error);
231
232 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
233 BOOST_REQUIRE_THROW(tpm.signInTpm(content, sizeof(content), keyName, DIGEST_ALGORITHM_SHA256),
234 SecTpmOsx::Error);
235
236 BOOST_REQUIRE_THROW(tpm.signInTpm(0, 1, keyName, DIGEST_ALGORITHM_SHA256),
237 SecTpmOsx::Error);
238}
239
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700240BOOST_AUTO_TEST_CASE(EcdsaSigning)
241{
242 SecTpmOsx tpm;
243
244 Name keyName("/TestSecTpmOsx/EcdsaSigning/ksk-" +
245 boost::lexical_cast<std::string>(time::toUnixTimestamp(time::system_clock::now())));
246 EcdsaKeyParams params;
247 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
248
249 Data data("/TestSecTpmOsx/EcdsaSigning/Data/1");
250 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
251
252 Block sigBlock;
253 BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
254 keyName, DIGEST_ALGORITHM_SHA256));
255
256 shared_ptr<PublicKey> pubkeyPtr;
257 BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
258
259 try
260 {
261 using namespace CryptoPP;
262
263 ECDSA<ECP, SHA256>::PublicKey publicKey;
264 ByteQueue queue;
265 queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
266 publicKey.Load(queue);
267
268 uint8_t buffer[64];
269 size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
270 sigBlock.value(), sigBlock.value_size(), DSA_DER);
271
272 ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
273 bool result = verifier.VerifyMessage(content, sizeof(content),
274 buffer, usedSize);
275
276 BOOST_CHECK_EQUAL(result, true);
277 }
278 catch (CryptoPP::Exception& e)
279 {
280 BOOST_CHECK(false);
281 }
282
283 tpm.deleteKeyPairInTpm(keyName);
284}
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700285
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700286
287BOOST_AUTO_TEST_CASE(ExportImportEcdsaKey)
288{
289 using namespace CryptoPP;
290
291 SecTpmOsx tpm;
292
293 Name keyName("/TestSecTpmOsx/ExportImportEcdsaKey/ksk-" +
294 boost::lexical_cast<std::string>(
295 time::toUnixTimestamp(time::system_clock::now()).count()));
296
297 EcdsaKeyParams params;
298 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
299
300 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
301 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
302
303 ConstBufferPtr exported;
304 BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234"));
305
306 shared_ptr<PublicKey> publicKey;
307 BOOST_REQUIRE_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName));
308
309 tpm.deleteKeyPairInTpm(keyName);
310
311 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
312 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
313
314 BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName,
315 exported->buf(), exported->size(),
316 "1234"));
317
318 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
319 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
320
321 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
322 Block sigBlock;
323 BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
324 keyName, DIGEST_ALGORITHM_SHA256));
325
326 try
327 {
328 using namespace CryptoPP;
329
330 ECDSA<ECP, SHA256>::PublicKey ecdsaPublicKey;
331 ByteQueue queue;
332 queue.Put(reinterpret_cast<const byte*>(publicKey->get().buf()), publicKey->get().size());
333 ecdsaPublicKey.Load(queue);
334
335 uint8_t buffer[64];
336 size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
337 sigBlock.value(), sigBlock.value_size(),
338 DSA_DER);
339
340 ECDSA<ECP, SHA256>::Verifier verifier(ecdsaPublicKey);
341 bool isVerified = verifier.VerifyMessage(content, sizeof(content),
342 buffer, usedSize);
343
344 BOOST_CHECK_EQUAL(isVerified, true);
345 }
346 catch (CryptoPP::Exception& e)
347 {
348 BOOST_CHECK(false);
349 }
350
351 tpm.deleteKeyPairInTpm(keyName);
352 // This is some problem related to Mac OS Key chain.
353 // On OSX 10.8, we cannot delete imported keys, but there is no such problem on OSX 10.9.
354#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
355#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9
356 BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
357 BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
358#endif
359#endif
360}
361
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800362BOOST_AUTO_TEST_SUITE_END()
Alexander Afanasyev0abb2da2014-01-30 18:07:57 -0800363
Spyridon Mastorakis429634f2015-02-19 17:35:33 -0800364} // namespace tests
Alexander Afanasyev0abb2da2014-01-30 18:07:57 -0800365} // namespace ndn