blob: 7b31a1a0b88047ec0f9df629f0c81eec2b6f34c4 [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 Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 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 {
Yingdi Yu28fd32f2014-01-28 19:03:03 -080033
Yingdi Yu41546342014-11-30 23:37:53 -080034class OsxKeyChainTestFixture
35{
36public:
37 OsxKeyChainTestFixture()
38 {
39 std::string oldHOME;
40 if (std::getenv("OLD_HOME"))
41 oldHOME = std::getenv("OLD_HOME");
42
43 if (std::getenv("HOME"))
44 m_HOME = std::getenv("HOME");
45
46 if (!oldHOME.empty())
47 setenv("HOME", oldHOME.c_str(), 1);
48 else
49 unsetenv("HOME");
50 }
51
52 ~OsxKeyChainTestFixture()
53 {
54 if (!m_HOME.empty())
55 setenv("HOME", m_HOME.c_str(), 1);
56 else
57 unsetenv("HOME");
58 }
59
60protected:
61 std::string m_HOME;
62};
63
64BOOST_FIXTURE_TEST_SUITE(SecurityTestSecTpmOsx, OsxKeyChainTestFixture)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080065
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070066BOOST_AUTO_TEST_CASE(Delete)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080067{
68 SecTpmOsx tpm;
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070069
Yingdi Yu5e96e002014-04-23 18:32:15 -070070 Name keyName("/TestSecTpmOsx/Delete/ksk-" +
Yingdi Yu7036ce22014-06-19 18:53:37 -070071 boost::lexical_cast<std::string>(
Yingdi Yu5e96e002014-04-23 18:32:15 -070072 time::toUnixTimestamp(time::system_clock::now()).count()));
Yingdi Yu7036ce22014-06-19 18:53:37 -070073 RsaKeyParams params(2048);
74 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070075
Yingdi Yu28fd32f2014-01-28 19:03:03 -080076 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
77 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070078
Yingdi Yu28fd32f2014-01-28 19:03:03 -080079 tpm.deleteKeyPairInTpm(keyName);
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070080
Yingdi Yu28fd32f2014-01-28 19:03:03 -080081 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
82 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
83}
84
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -070085BOOST_AUTO_TEST_CASE(SignVerify)
Yingdi Yu28fd32f2014-01-28 19:03:03 -080086{
87 SecTpmOsx tpm;
88
Yingdi Yu5e96e002014-04-23 18:32:15 -070089 Name keyName("/TestSecTpmOsx/SignVerify/ksk-" +
Yingdi Yu7036ce22014-06-19 18:53:37 -070090 boost::lexical_cast<std::string>(
Yingdi Yu5e96e002014-04-23 18:32:15 -070091 time::toUnixTimestamp(time::system_clock::now()).count()));
Yingdi Yu7036ce22014-06-19 18:53:37 -070092 RsaKeyParams params(2048);
93 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070094
Yingdi Yube4150e2014-02-18 13:02:46 -080095 Data data("/TestSecTpmOsx/SignVaerify/Data/1");
Yingdi Yu28fd32f2014-01-28 19:03:03 -080096 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
97
Yingdi Yu2e57a582014-02-20 23:34:43 -080098 Block sigBlock;
Yingdi Yu5e96e002014-04-23 18:32:15 -070099 BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
100 keyName, DIGEST_ALGORITHM_SHA256));
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800101
Yingdi Yu7036ce22014-06-19 18:53:37 -0700102 shared_ptr<PublicKey> publicKey;
103 BOOST_CHECK_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName));
Yingdi Yu2e57a582014-02-20 23:34:43 -0800104 try
105 {
106 using namespace CryptoPP;
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800107
Yingdi Yu7036ce22014-06-19 18:53:37 -0700108 RSA::PublicKey rsaPublicKey;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800109 ByteQueue queue;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700110 queue.Put(reinterpret_cast<const byte*>(publicKey->get().buf()), publicKey->get().size());
111 rsaPublicKey.Load(queue);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800112
Yingdi Yu7036ce22014-06-19 18:53:37 -0700113 RSASS<PKCS1v15, SHA256>::Verifier verifier(rsaPublicKey);
114 bool isVerified = verifier.VerifyMessage(content, sizeof(content),
115 sigBlock.value(), sigBlock.value_size());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700116
Yingdi Yu7036ce22014-06-19 18:53:37 -0700117 BOOST_CHECK_EQUAL(isVerified, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800118 }
Yingdi Yu5e96e002014-04-23 18:32:15 -0700119 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800120 {
121 BOOST_CHECK(false);
122 }
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800123
124 tpm.deleteKeyPairInTpm(keyName);
125}
126
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700127BOOST_AUTO_TEST_CASE(RandomGenerator)
Yingdi Yu4b752752014-02-18 12:24:03 -0800128{
129 SecTpmOsx tpm;
130
131 size_t scale = 1000;
132 size_t size = 256 * scale;
133 uint8_t* block = new uint8_t[size];
134 tpm.generateRandomBlock(block, size);
135
Yingdi Yu7036ce22014-06-19 18:53:37 -0700136 std::map<uint8_t, int> counter;
137 for (size_t i = 0; i < size; i++)
138 {
139 counter[block[i]] += 1;
140 }
Yingdi Yu4b752752014-02-18 12:24:03 -0800141
142 float dev = 0.0;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700143 for (size_t i = 0; i != 255; i++)
144 {
145 dev += ((counter[i] - scale) * (counter[i] - scale)) * 1.0 / (scale * scale);
146 }
Yingdi Yu4b752752014-02-18 12:24:03 -0800147
148 BOOST_CHECK_CLOSE(dev / 256, 0.001, 100);
149
150}
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800151
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700152BOOST_AUTO_TEST_CASE(ExportImportKey)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800153{
154 using namespace CryptoPP;
155
156 SecTpmOsx tpm;
157
Yingdi Yu5e96e002014-04-23 18:32:15 -0700158 Name keyName("/TestSecTpmOsx/ExportImportKey/ksk-" +
Yingdi Yu7036ce22014-06-19 18:53:37 -0700159 boost::lexical_cast<std::string>(
Yingdi Yu5e96e002014-04-23 18:32:15 -0700160 time::toUnixTimestamp(time::system_clock::now()).count()));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700161
Yingdi Yu7036ce22014-06-19 18:53:37 -0700162 RsaKeyParams params(2048);
163 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800164
Yingdi Yu7036ce22014-06-19 18:53:37 -0700165 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
166 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800167
Yingdi Yu2e57a582014-02-20 23:34:43 -0800168 ConstBufferPtr exported;
Yingdi Yu5e96e002014-04-23 18:32:15 -0700169 BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234"));
Yingdi Yu7036ce22014-06-19 18:53:37 -0700170 shared_ptr<PublicKey> publicKey;
171 BOOST_REQUIRE_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800172
173 tpm.deleteKeyPairInTpm(keyName);
174
Yingdi Yu7036ce22014-06-19 18:53:37 -0700175 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
176 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800177
Yingdi Yu5e96e002014-04-23 18:32:15 -0700178 BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName,
179 exported->buf(), exported->size(),
180 "1234"));
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700181
Yingdi Yu7036ce22014-06-19 18:53:37 -0700182 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
183 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800184
185 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
Yingdi Yu2e57a582014-02-20 23:34:43 -0800186 Block sigBlock;
Yingdi Yu5e96e002014-04-23 18:32:15 -0700187 BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
188 keyName, DIGEST_ALGORITHM_SHA256));
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800189
Yingdi Yu2e57a582014-02-20 23:34:43 -0800190 try
191 {
192 using namespace CryptoPP;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800193
Yingdi Yu7036ce22014-06-19 18:53:37 -0700194 RSA::PublicKey rsaPublicKey;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800195 ByteQueue queue;
Yingdi Yu7036ce22014-06-19 18:53:37 -0700196 queue.Put(reinterpret_cast<const byte*>(publicKey->get().buf()), publicKey->get().size());
197 rsaPublicKey.Load(queue);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800198
Yingdi Yu7036ce22014-06-19 18:53:37 -0700199 RSASS<PKCS1v15, SHA256>::Verifier verifier(rsaPublicKey);
200 bool isVerified = verifier.VerifyMessage(content, sizeof(content),
201 sigBlock.value(), sigBlock.value_size());
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700202
Yingdi Yu7036ce22014-06-19 18:53:37 -0700203 BOOST_CHECK_EQUAL(isVerified, true);
Yingdi Yu2e57a582014-02-20 23:34:43 -0800204 }
Yingdi Yu5e96e002014-04-23 18:32:15 -0700205 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800206 {
207 BOOST_CHECK(false);
208 }
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -0700209
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800210 tpm.deleteKeyPairInTpm(keyName);
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700211 // This is some problem related to Mac OS Key chain.
212 // On OSX 10.8, we cannot delete imported keys, but there is no such problem on OSX 10.9.
213#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
214#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9
215 BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
216 BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
217#endif
218#endif
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800219}
220
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700221BOOST_AUTO_TEST_CASE(NonExistingKey)
222{
223 using namespace CryptoPP;
224
225 SecTpmOsx tpm;
226
227 Name keyName("/TestSecTpmOsx/NonExistingKey");
228
229 BOOST_REQUIRE_THROW(tpm.getPublicKeyFromTpm(keyName), SecTpmOsx::Error);
230
231 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
232 BOOST_REQUIRE_THROW(tpm.signInTpm(content, sizeof(content), keyName, DIGEST_ALGORITHM_SHA256),
233 SecTpmOsx::Error);
234
235 BOOST_REQUIRE_THROW(tpm.signInTpm(0, 1, keyName, DIGEST_ALGORITHM_SHA256),
236 SecTpmOsx::Error);
237}
238
Yingdi Yuc8f883c2014-06-20 23:25:22 -0700239BOOST_AUTO_TEST_CASE(EcdsaSigning)
240{
241 SecTpmOsx tpm;
242
243 Name keyName("/TestSecTpmOsx/EcdsaSigning/ksk-" +
244 boost::lexical_cast<std::string>(time::toUnixTimestamp(time::system_clock::now())));
245 EcdsaKeyParams params;
246 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
247
248 Data data("/TestSecTpmOsx/EcdsaSigning/Data/1");
249 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
250
251 Block sigBlock;
252 BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
253 keyName, DIGEST_ALGORITHM_SHA256));
254
255 shared_ptr<PublicKey> pubkeyPtr;
256 BOOST_CHECK_NO_THROW(pubkeyPtr = tpm.getPublicKeyFromTpm(keyName));
257
258 try
259 {
260 using namespace CryptoPP;
261
262 ECDSA<ECP, SHA256>::PublicKey publicKey;
263 ByteQueue queue;
264 queue.Put(reinterpret_cast<const byte*>(pubkeyPtr->get().buf()), pubkeyPtr->get().size());
265 publicKey.Load(queue);
266
267 uint8_t buffer[64];
268 size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
269 sigBlock.value(), sigBlock.value_size(), DSA_DER);
270
271 ECDSA<ECP, SHA256>::Verifier verifier(publicKey);
272 bool result = verifier.VerifyMessage(content, sizeof(content),
273 buffer, usedSize);
274
275 BOOST_CHECK_EQUAL(result, true);
276 }
277 catch (CryptoPP::Exception& e)
278 {
279 BOOST_CHECK(false);
280 }
281
282 tpm.deleteKeyPairInTpm(keyName);
283}
Alexander Afanasyevf82d13a2014-04-30 14:30:19 -0700284
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700285
286BOOST_AUTO_TEST_CASE(ExportImportEcdsaKey)
287{
288 using namespace CryptoPP;
289
290 SecTpmOsx tpm;
291
292 Name keyName("/TestSecTpmOsx/ExportImportEcdsaKey/ksk-" +
293 boost::lexical_cast<std::string>(
294 time::toUnixTimestamp(time::system_clock::now()).count()));
295
296 EcdsaKeyParams params;
297 BOOST_CHECK_NO_THROW(tpm.generateKeyPairInTpm(keyName, params));
298
299 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
300 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
301
302 ConstBufferPtr exported;
303 BOOST_CHECK_NO_THROW(exported = tpm.exportPrivateKeyPkcs5FromTpm(keyName, "1234"));
304
305 shared_ptr<PublicKey> publicKey;
306 BOOST_REQUIRE_NO_THROW(publicKey = tpm.getPublicKeyFromTpm(keyName));
307
308 tpm.deleteKeyPairInTpm(keyName);
309
310 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), false);
311 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), false);
312
313 BOOST_REQUIRE(tpm.importPrivateKeyPkcs5IntoTpm(keyName,
314 exported->buf(), exported->size(),
315 "1234"));
316
317 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC), true);
318 BOOST_REQUIRE_EQUAL(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE), true);
319
320 const uint8_t content[] = {0x01, 0x02, 0x03, 0x04};
321 Block sigBlock;
322 BOOST_CHECK_NO_THROW(sigBlock = tpm.signInTpm(content, sizeof(content),
323 keyName, DIGEST_ALGORITHM_SHA256));
324
325 try
326 {
327 using namespace CryptoPP;
328
329 ECDSA<ECP, SHA256>::PublicKey ecdsaPublicKey;
330 ByteQueue queue;
331 queue.Put(reinterpret_cast<const byte*>(publicKey->get().buf()), publicKey->get().size());
332 ecdsaPublicKey.Load(queue);
333
334 uint8_t buffer[64];
335 size_t usedSize = DSAConvertSignatureFormat(buffer, 64, DSA_P1363,
336 sigBlock.value(), sigBlock.value_size(),
337 DSA_DER);
338
339 ECDSA<ECP, SHA256>::Verifier verifier(ecdsaPublicKey);
340 bool isVerified = verifier.VerifyMessage(content, sizeof(content),
341 buffer, usedSize);
342
343 BOOST_CHECK_EQUAL(isVerified, true);
344 }
345 catch (CryptoPP::Exception& e)
346 {
347 BOOST_CHECK(false);
348 }
349
350 tpm.deleteKeyPairInTpm(keyName);
351 // This is some problem related to Mac OS Key chain.
352 // On OSX 10.8, we cannot delete imported keys, but there is no such problem on OSX 10.9.
353#ifdef __MAC_OS_X_VERSION_MAX_ALLOWED
354#if __MAC_OS_X_VERSION_MAX_ALLOWED >= __MAC_10_9
355 BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PRIVATE) == false);
356 BOOST_REQUIRE(tpm.doesKeyExistInTpm(keyName, KEY_CLASS_PUBLIC) == false);
357#endif
358#endif
359}
360
Yingdi Yu28fd32f2014-01-28 19:03:03 -0800361BOOST_AUTO_TEST_SUITE_END()
Alexander Afanasyev0abb2da2014-01-30 18:07:57 -0800362
363} // namespace ndn