NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.3: NDN, CCN, CCNx, content centric networks
API Documentation
sec-tpm-file.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "sec-tpm-file.hpp"
27 
28 #include "../encoding/buffer-stream.hpp"
29 
30 #include <boost/filesystem.hpp>
31 #include <boost/algorithm/string.hpp>
32 
33 #include "v1/cryptopp.hpp"
34 
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 
38 #include <algorithm>
39 
40 namespace ndn {
41 namespace security {
42 
43 using std::string;
44 using std::ostringstream;
45 using std::ofstream;
46 
47 const std::string SecTpmFile::SCHEME("tpm-file");
48 
50 {
51 public:
52  explicit
53  Impl(const string& dir)
54  {
55  boost::filesystem::path actualDir;
56  if (dir.empty()) {
57 #ifdef NDN_CXX_HAVE_TESTS
58  if (getenv("TEST_HOME") != nullptr) {
59  actualDir = boost::filesystem::path(getenv("TEST_HOME")) / ".ndn";
60  }
61  else
62 #endif // NDN_CXX_HAVE_TESTS
63  if (getenv("HOME") != nullptr) {
64  actualDir = boost::filesystem::path(getenv("HOME")) / ".ndn";
65  }
66  else {
67  actualDir = boost::filesystem::path(".") / ".ndn";
68  }
69  }
70  else {
71  actualDir = boost::filesystem::path(dir);
72  }
73 
74  m_keystorePath = actualDir / "ndnsec-tpm-file";
75  boost::filesystem::create_directories(m_keystorePath);
76  }
77 
78  boost::filesystem::path
79  transformName(const string& keyName, const string& extension)
80  {
81  using namespace CryptoPP;
82  string digest;
83  SHA256 hash;
84  StringSource src(keyName,
85  true,
86  new HashFilter(hash,
87  new Base64Encoder(new CryptoPP::StringSink(digest))));
88 
89  boost::algorithm::trim(digest);
90  std::replace(digest.begin(), digest.end(), '/', '%');
91 
92  return m_keystorePath / (digest + extension);
93  }
94 
95  string
96  maintainMapping(const string& keyName)
97  {
98  string keyFileName = transformName(keyName, "").string();
99 
100  ofstream outfile;
101  string dirFile = (m_keystorePath / "mapping.txt").string();
102 
103  outfile.open(dirFile.c_str(), std::ios_base::app);
104  outfile << keyName << ' ' << keyFileName << '\n';
105  outfile.close();
106 
107  return keyFileName;
108  }
109 
110 public:
111  boost::filesystem::path m_keystorePath;
112 };
113 
114 
115 SecTpmFile::SecTpmFile(const string& location)
116  : SecTpm(location)
117  , m_impl(new Impl(location))
118  , m_inTerminal(false)
119 {
120 }
121 
123 {
124 }
125 
126 void
127 SecTpmFile::generateKeyPairInTpm(const Name& keyName, const KeyParams& params)
128 {
129  string keyURI = keyName.toUri();
130 
131  if (doesKeyExistInTpm(keyName, KeyClass::PUBLIC))
132  BOOST_THROW_EXCEPTION(Error("public key exists"));
133  if (doesKeyExistInTpm(keyName, KeyClass::PRIVATE))
134  BOOST_THROW_EXCEPTION(Error("private key exists"));
135 
136  string keyFileName = m_impl->maintainMapping(keyURI);
137 
138  try {
139  switch (params.getKeyType()) {
140  case KeyType::RSA: {
141  using namespace CryptoPP;
142 
143  const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(params);
144  AutoSeededRandomPool rng;
145  InvertibleRSAFunction privateKey;
146  privateKey.Initialize(rng, rsaParams.getKeySize());
147 
148  string privateKeyFileName = keyFileName + ".pri";
149  Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
150  privateKey.DEREncode(privateKeySink);
151  privateKeySink.MessageEnd();
152 
153  RSAFunction publicKey(privateKey);
154  string publicKeyFileName = keyFileName + ".pub";
155  Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
156  publicKey.DEREncode(publicKeySink);
157  publicKeySink.MessageEnd();
158 
159  // set file permission
160  chmod(privateKeyFileName.c_str(), 0000400);
161  chmod(publicKeyFileName.c_str(), 0000444);
162  return;
163  }
164 
165  case KeyType::EC: {
166  using namespace CryptoPP;
167 
168  const EcdsaKeyParams& ecdsaParams = static_cast<const EcdsaKeyParams&>(params);
169 
170  CryptoPP::OID curveName;
171  switch (ecdsaParams.getKeySize()) {
172  case 256:
173  curveName = ASN1::secp256r1();
174  break;
175  case 384:
176  curveName = ASN1::secp384r1();
177  break;
178  default:
179  curveName = ASN1::secp256r1();
180  break;
181  }
182 
183  AutoSeededRandomPool rng;
184 
185  ECDSA<ECP, SHA256>::PrivateKey privateKey;
186  DL_GroupParameters_EC<ECP> cryptoParams(curveName);
187  cryptoParams.SetEncodeAsOID(true);
188  privateKey.Initialize(rng, cryptoParams);
189 
190  ECDSA<ECP, SHA256>::PublicKey publicKey;
191  privateKey.MakePublicKey(publicKey);
192  publicKey.AccessGroupParameters().SetEncodeAsOID(true);
193 
194  string privateKeyFileName = keyFileName + ".pri";
195  Base64Encoder privateKeySink(new FileSink(privateKeyFileName.c_str()));
196  privateKey.DEREncode(privateKeySink);
197  privateKeySink.MessageEnd();
198 
199  string publicKeyFileName = keyFileName + ".pub";
200  Base64Encoder publicKeySink(new FileSink(publicKeyFileName.c_str()));
201  publicKey.Save(publicKeySink);
202  publicKeySink.MessageEnd();
203 
204  // set file permission
205  chmod(privateKeyFileName.c_str(), 0000400);
206  chmod(publicKeyFileName.c_str(), 0000444);
207  return;
208  }
209 
210  default:
211  BOOST_THROW_EXCEPTION(Error("Unsupported key type"));
212  }
213  }
214  catch (const KeyParams::Error& e) {
215  BOOST_THROW_EXCEPTION(Error(e.what()));
216  }
217  catch (const CryptoPP::Exception& e) {
218  BOOST_THROW_EXCEPTION(Error(e.what()));
219  }
220 }
221 
222 void
224 {
225  boost::filesystem::path publicKeyPath(m_impl->transformName(keyName.toUri(), ".pub"));
226  boost::filesystem::path privateKeyPath(m_impl->transformName(keyName.toUri(), ".pri"));
227 
228  if (boost::filesystem::exists(publicKeyPath))
229  boost::filesystem::remove(publicKeyPath);
230 
231  if (boost::filesystem::exists(privateKeyPath))
232  boost::filesystem::remove(privateKeyPath);
233 }
234 
235 shared_ptr<v1::PublicKey>
237 {
238  string keyURI = keyName.toUri();
239 
240  if (!doesKeyExistInTpm(keyName, KeyClass::PUBLIC))
241  BOOST_THROW_EXCEPTION(Error("Public Key does not exist"));
242 
243  ostringstream os;
244  try {
245  using namespace CryptoPP;
246  FileSource(m_impl->transformName(keyURI, ".pub").string().c_str(),
247  true,
248  new Base64Decoder(new FileSink(os)));
249  }
250  catch (const CryptoPP::Exception& e) {
251  BOOST_THROW_EXCEPTION(Error(e.what()));
252  }
253 
254  return make_shared<v1::PublicKey>(reinterpret_cast<const uint8_t*>(os.str().c_str()),
255  os.str().size());
256 }
257 
258 std::string
260 {
261  return SCHEME;
262 }
263 
266 {
267  OBufferStream privateKeyOs;
268  CryptoPP::FileSource(m_impl->transformName(keyName.toUri(), ".pri").string().c_str(), true,
269  new CryptoPP::Base64Decoder(new CryptoPP::FileSink(privateKeyOs)));
270 
271  return privateKeyOs.buf();
272 }
273 
274 bool
275 SecTpmFile::importPrivateKeyPkcs8IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
276 {
277  try {
278  using namespace CryptoPP;
279 
280  string keyFileName = m_impl->maintainMapping(keyName.toUri());
281  keyFileName.append(".pri");
282  StringSource(buf, size,
283  true,
284  new Base64Encoder(new FileSink(keyFileName.c_str())));
285  return true;
286  }
287  catch (const CryptoPP::Exception& e) {
288  return false;
289  }
290 }
291 
292 bool
293 SecTpmFile::importPublicKeyPkcs1IntoTpm(const Name& keyName, const uint8_t* buf, size_t size)
294 {
295  try {
296  using namespace CryptoPP;
297 
298  string keyFileName = m_impl->maintainMapping(keyName.toUri());
299  keyFileName.append(".pub");
300  StringSource(buf, size,
301  true,
302  new Base64Encoder(new FileSink(keyFileName.c_str())));
303  return true;
304  }
305  catch (const CryptoPP::Exception& e) {
306  return false;
307  }
308 }
309 
310 Block
311 SecTpmFile::signInTpm(const uint8_t* data, size_t dataLength,
312  const Name& keyName, DigestAlgorithm digestAlgorithm)
313 {
314  string keyURI = keyName.toUri();
315 
316  if (!doesKeyExistInTpm(keyName, KeyClass::PRIVATE))
317  BOOST_THROW_EXCEPTION(Error("private key doesn't exist"));
318 
319  try {
320  using namespace CryptoPP;
321  AutoSeededRandomPool rng;
322 
323  // Read public key
324  shared_ptr<v1::PublicKey> pubkeyPtr;
325  pubkeyPtr = getPublicKeyFromTpm(keyName);
326 
327  switch (pubkeyPtr->getKeyType()) {
328  case KeyType::RSA: {
329  // Read private key
330  ByteQueue bytes;
331  FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(),
332  true, new Base64Decoder);
333  file.TransferTo(bytes);
334  bytes.MessageEnd();
335  RSA::PrivateKey privateKey;
336  privateKey.Load(bytes);
337 
338  // Sign message
339  switch (digestAlgorithm) {
341  RSASS<PKCS1v15, SHA256>::Signer signer(privateKey);
342 
343  OBufferStream os;
344  StringSource(data, dataLength,
345  true,
346  new SignerFilter(rng, signer, new FileSink(os)));
347 
348  return Block(tlv::SignatureValue, os.buf());
349  }
350 
351  default:
352  BOOST_THROW_EXCEPTION(Error("Unsupported digest algorithm"));
353  }
354  }
355 
356  case KeyType::EC: {
357  // Read private key
358  ByteQueue bytes;
359  FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(),
360  true, new Base64Decoder);
361  file.TransferTo(bytes);
362  bytes.MessageEnd();
363 
364  // Sign message
365  switch (digestAlgorithm) {
367  ECDSA<ECP, SHA256>::PrivateKey privateKey;
368  privateKey.Load(bytes);
369  ECDSA<ECP, SHA256>::Signer signer(privateKey);
370 
371  OBufferStream os;
372  StringSource(data, dataLength,
373  true,
374  new SignerFilter(rng, signer, new FileSink(os)));
375 
376  uint8_t buf[200];
377  size_t bufSize = DSAConvertSignatureFormat(buf, sizeof(buf), DSA_DER,
378  os.buf()->buf(), os.buf()->size(),
379  DSA_P1363);
380 
381  shared_ptr<Buffer> sigBuffer = make_shared<Buffer>(buf, bufSize);
382 
383  return Block(tlv::SignatureValue, sigBuffer);
384  }
385 
386  default:
387  BOOST_THROW_EXCEPTION(Error("Unsupported digest algorithm"));
388  }
389  }
390 
391  default:
392  BOOST_THROW_EXCEPTION(Error("Unsupported key type"));
393  }
394  }
395  catch (const CryptoPP::Exception& e) {
396  BOOST_THROW_EXCEPTION(Error(e.what()));
397  }
398 }
399 
400 
402 SecTpmFile::decryptInTpm(const uint8_t* data, size_t dataLength,
403  const Name& keyName, bool isSymmetric)
404 {
405  BOOST_THROW_EXCEPTION(Error("SecTpmFile::decryptInTpm is not supported"));
406  // string keyURI = keyName.toUri();
407  // if (!isSymmetric)
408  // {
409  // if (!doesKeyExistInTpm(keyName, KeyClass::PRIVATE))
410  // throw Error("private key doesn't exist");
411 
412  // try{
413  // using namespace CryptoPP;
414  // AutoSeededRandomPool rng;
415 
416  // //Read private key
417  // ByteQueue bytes;
418  // FileSource file(m_impl->transformName(keyURI, ".pri").string().c_str(), true, new Base64Decoder);
419  // file.TransferTo(bytes);
420  // bytes.MessageEnd();
421  // RSA::PrivateKey privateKey;
422  // privateKey.Load(bytes);
423  // RSAES_PKCS1v15_Decryptor decryptor(privateKey);
424 
425  // OBufferStream os;
426  // StringSource(data, dataLength, true, new PK_DecryptorFilter(rng, decryptor, new FileSink(os)));
427 
428  // return os.buf();
429  // }
430  // catch (const CryptoPP::Exception& e){
431  // throw Error(e.what());
432  // }
433  // }
434  // else
435  // {
436  // throw Error("Symmetric encryption is not implemented!");
437  // // if (!doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
438  // // throw Error("symmetric key doesn't exist");
439 
440  // // try{
441  // // string keyBits;
442  // // string symKeyFileName = m_impl->transformName(keyURI, ".key");
443  // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
444 
445  // // using CryptoPP::AES;
446  // // AutoSeededRandomPool rnd;
447  // // byte iv[AES::BLOCKSIZE];
448  // // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
449 
450  // // CFB_Mode<AES>::Decryption decryptor;
451  // // decryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
452 
453  // // OBufferStream os;
454  // // StringSource(data, dataLength, true, new StreamTransformationFilter(decryptor,new FileSink(os)));
455  // // return os.buf();
456 
457  // // }
458  // // catch (const CryptoPP::Exception& e){
459  // // throw Error(e.what());
460  // // }
461  // }
462 }
463 
465 SecTpmFile::encryptInTpm(const uint8_t* data, size_t dataLength,
466  const Name& keyName, bool isSymmetric)
467 {
468  BOOST_THROW_EXCEPTION(Error("SecTpmFile::encryptInTpm is not supported"));
469  // string keyURI = keyName.toUri();
470 
471  // if (!isSymmetric)
472  // {
473  // if (!doesKeyExistInTpm(keyName, KeyClass::PUBLIC))
474  // throw Error("public key doesn't exist");
475  // try
476  // {
477  // using namespace CryptoPP;
478  // AutoSeededRandomPool rng;
479 
480  // //Read private key
481  // ByteQueue bytes;
482  // FileSource file(m_impl->transformName(keyURI, ".pub").string().c_str(), true, new Base64Decoder);
483  // file.TransferTo(bytes);
484  // bytes.MessageEnd();
485  // RSA::PublicKey publicKey;
486  // publicKey.Load(bytes);
487 
488  // OBufferStream os;
489  // RSAES_PKCS1v15_Encryptor encryptor(publicKey);
490 
491  // StringSource(data, dataLength, true, new PK_EncryptorFilter(rng, encryptor, new FileSink(os)));
492  // return os.buf();
493  // }
494  // catch (const CryptoPP::Exception& e){
495  // throw Error(e.what());
496  // }
497  // }
498  // else
499  // {
500  // throw Error("Symmetric encryption is not implemented!");
501  // // if (!doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
502  // // throw Error("symmetric key doesn't exist");
503 
504  // // try{
505  // // string keyBits;
506  // // string symKeyFileName = m_impl->transformName(keyURI, ".key");
507  // // FileSource(symKeyFileName, true, new HexDecoder(new StringSink(keyBits)));
508 
509  // // using CryptoPP::AES;
510  // // AutoSeededRandomPool rnd;
511  // // byte iv[AES::BLOCKSIZE];
512  // // rnd.GenerateBlock(iv, AES::BLOCKSIZE);
513 
514  // // CFB_Mode<AES>::Encryption encryptor;
515  // // encryptor.SetKeyWithIV(reinterpret_cast<const uint8_t*>(keyBits.c_str()), keyBits.size(), iv);
516 
517  // // OBufferStream os;
518  // // StringSource(data, dataLength, true, new StreamTransformationFilter(encryptor, new FileSink(os)));
519  // // return os.buf();
520  // // } catch (const CryptoPP::Exception& e){
521  // // throw Error(e.what());
522  // // }
523  // }
524 }
525 
526 void
528 {
529  BOOST_THROW_EXCEPTION(Error("SecTpmFile::generateSymmetricKeyInTpm is not supported"));
530  // string keyURI = keyName.toUri();
531 
532  // if (doesKeyExistInTpm(keyName, KeyClass::SYMMETRIC))
533  // throw Error("symmetric key exists");
534 
535  // string keyFileName = m_impl->maintainMapping(keyURI);
536  // string symKeyFileName = keyFileName + ".key";
537 
538  // try{
539  // switch (keyType){
540  // case KeyType::AES:
541  // {
542  // using namespace CryptoPP;
543  // AutoSeededRandomPool rng;
544 
545  // SecByteBlock key(0x00, keySize);
546  // rng.GenerateBlock(key, keySize);
547 
548  // StringSource(key, key.size(), true, new HexEncoder(new FileSink(symKeyFileName.c_str())));
549 
550  // chmod(symKeyFileName.c_str(), 0000400);
551  // return;
552  // }
553  // default:
554  // throw Error("Unsupported symmetric key type!");
555  // }
556  // } catch (const CryptoPP::Exception& e){
557  // throw Error(e.what());
558  // }
559 }
560 
561 bool
562 SecTpmFile::doesKeyExistInTpm(const Name& keyName, KeyClass keyClass)
563 {
564  string keyURI = keyName.toUri();
565  if (keyClass == KeyClass::PUBLIC) {
566  return boost::filesystem::exists(m_impl->transformName(keyURI, ".pub"));
567  }
568  if (keyClass == KeyClass::PRIVATE) {
569  return boost::filesystem::exists(m_impl->transformName(keyURI, ".pri"));
570  }
571  if (keyClass == KeyClass::SYMMETRIC) {
572  return boost::filesystem::exists(m_impl->transformName(keyURI, ".key"));
573  }
574  return false;
575 }
576 
577 bool
578 SecTpmFile::generateRandomBlock(uint8_t* res, size_t size)
579 {
580  try {
581  CryptoPP::AutoSeededRandomPool rng;
582  rng.GenerateBlock(res, size);
583  return true;
584  }
585  catch (const CryptoPP::Exception& e) {
586  return false;
587  }
588 }
589 
590 } // namespace security
591 } // namespace ndn
boost::filesystem::path m_keystorePath
Copyright (c) 2011-2015 Regents of the University of California.
virtual bool generateRandomBlock(uint8_t *res, size_t size)
Generate a random block.
std::string toUri() const
Encode this name as a URI.
Definition: name.cpp:171
static const std::string SCHEME
string maintainMapping(const string &keyName)
Copyright (c) 2013-2016 Regents of the University of California.
Definition: oid.hpp:29
virtual void generateKeyPairInTpm(const Name &keyName, const KeyParams &params)
Generate a pair of asymmetric keys.
virtual ConstBufferPtr encryptInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, bool isSymmetric)
Encrypt data.
SecTpm is the base class of the TPM classes.
Definition: sec-tpm.hpp:42
virtual std::string getScheme()
boost::filesystem::path transformName(const string &keyName, const string &extension)
Class representing a wire element of NDN-TLV packet format.
Definition: block.hpp:43
virtual bool importPublicKeyPkcs1IntoTpm(const Name &keyName, const uint8_t *buf, size_t size)
Import a public key in PKCS#1 formatted buffer of size bufferSize.
virtual ConstBufferPtr decryptInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, bool isSymmetric)
Decrypt data.
virtual bool importPrivateKeyPkcs8IntoTpm(const Name &keyName, const uint8_t *buf, size_t size)
Import a private key from PKCS#8 formatted buffer of size bufferSize.
virtual void generateSymmetricKeyInTpm(const Name &keyName, const KeyParams &params)
Generate a symmetric key.
virtual Block signInTpm(const uint8_t *data, size_t dataLength, const Name &keyName, DigestAlgorithm digestAlgorithm)
Sign data.
Oid OID
Definition: oid.hpp:97
virtual shared_ptr< v1::PublicKey > getPublicKeyFromTpm(const Name &keyName)
Get a public key.
virtual void deleteKeyPairInTpm(const Name &keyName)
Delete a key pair of asymmetric keys.
Name abstraction to represent an absolute name.
Definition: name.hpp:46
SecTpmFile(const std::string &dir="")
KeyType getKeyType() const
Definition: key-params.hpp:54
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
Base class of key parameters.
Definition: key-params.hpp:35
void trim(std::string &str)
Modify str in place to erase whitespace on the left and right.
uint32_t getKeySize() const
Definition: key-params.hpp:135
implements an output stream that constructs ndn::Buffer
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:33
virtual bool doesKeyExistInTpm(const Name &keyName, KeyClass keyClass)
Check if a particular key exists.
SimplePublicKeyParams is a template for public keys with only one parameter: size.
Definition: key-params.hpp:110
virtual ConstBufferPtr exportPrivateKeyPkcs8FromTpm(const Name &keyName)
Export a private key in PKCS#8 format.
Impl(const string &dir)