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