blob: 5c12049a219acd727693d9d1cdad330acea7ddf5 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yingdi Yu8dceb1d2014-02-18 12:45:10 -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.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080022 */
23
24#include "sec-tpm.hpp"
25
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070026#include "../encoding/oid.hpp"
27#include "../encoding/buffer-stream.hpp"
Junxiao Shi482ccc52014-03-31 13:05:24 -070028#include "cryptopp.hpp"
Alexander Afanasyeva2ada222015-01-22 18:34:16 -080029#include <unistd.h>
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080030
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080031namespace ndn {
32
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070033using std::string;
34
Yingdi Yu41546342014-11-30 23:37:53 -080035SecTpm::SecTpm(const string& location)
36 : m_location(location)
37{
38}
39
40SecTpm::~SecTpm()
41{
42}
43
44std::string
45SecTpm::getTpmLocator()
46{
Alexander Afanasyev07113802015-01-15 19:14:36 -080047 return this->getScheme() + ":" + m_location;
Yingdi Yu41546342014-11-30 23:37:53 -080048}
49
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080050ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -070051SecTpm::exportPrivateKeyPkcs5FromTpm(const Name& keyName, const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080052{
Yingdi Yu2e57a582014-02-20 23:34:43 -080053 using namespace CryptoPP;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070054
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080055 uint8_t salt[8] = {0};
56 uint8_t iv[8] = {0};
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070057
Yingdi Yu2e57a582014-02-20 23:34:43 -080058 // derive key
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070059 if (!generateRandomBlock(salt, 8) || !generateRandomBlock(iv, 8))
Yingdi Yu2e57a582014-02-20 23:34:43 -080060 throw Error("Cannot generate salt or iv");
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080061
Yingdi Yu2e57a582014-02-20 23:34:43 -080062 uint32_t iterationCount = 2048;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070063
Yingdi Yu2e57a582014-02-20 23:34:43 -080064 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
65 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
66 byte derived[24] = {0};
67 byte purpose = 0;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070068
Yingdi Yu2e57a582014-02-20 23:34:43 -080069 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080070 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070071 keyGenerator.DeriveKey(derived, derivedLen, purpose,
72 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -080073 salt, 8, iterationCount);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080074 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070075 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080076 {
77 throw Error("Cannot derived the encryption key");
78 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080079
Yingdi Yu2e57a582014-02-20 23:34:43 -080080 //encrypt
81 CBC_Mode< DES_EDE3 >::Encryption e;
82 e.SetKeyWithIV(derived, derivedLen, iv);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070083
Yingdi Yu5e96e002014-04-23 18:32:15 -070084 ConstBufferPtr pkcs8PrivateKey = exportPrivateKeyPkcs8FromTpm(keyName);
Yingdi Yu9d9d5992014-06-25 12:25:16 -070085
Yingdi Yu5e96e002014-04-23 18:32:15 -070086 if (!static_cast<bool>(pkcs8PrivateKey))
Yingdi Yu2e57a582014-02-20 23:34:43 -080087 throw Error("Cannot export the private key, #1");
88
89 OBufferStream encryptedOs;
90 try
91 {
Yingdi Yu5e96e002014-04-23 18:32:15 -070092 StringSource stringSource(pkcs8PrivateKey->buf(), pkcs8PrivateKey->size(), true,
Yingdi Yu2e57a582014-02-20 23:34:43 -080093 new StreamTransformationFilter(e, new FileSink(encryptedOs)));
94 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070095 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080096 {
97 throw Error("Cannot export the private key, #2");
98 }
99
100 //encode
101 OID pbes2Id("1.2.840.113549.1.5.13");
102 OID pbkdf2Id("1.2.840.113549.1.5.12");
103 OID pbes2encsId("1.2.840.113549.3.7");
104
105 OBufferStream pkcs8Os;
106 try
107 {
108 FileSink sink(pkcs8Os);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700109
Yingdi Yu2e57a582014-02-20 23:34:43 -0800110 // EncryptedPrivateKeyInfo ::= SEQUENCE {
111 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
112 // encryptedData OCTET STRING }
113 DERSequenceEncoder encryptedPrivateKeyInfo(sink);
114 {
115 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
116 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
117 // parameters SEQUENCE {{PBES2-params}} }
118 DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo);
119 {
120 pbes2Id.encode(encryptionAlgorithm);
121 // PBES2-params ::= SEQUENCE {
122 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
123 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
124 DERSequenceEncoder pbes2Params(encryptionAlgorithm);
125 {
126 // AlgorithmIdentifier ::= SEQUENCE {
127 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
128 // parameters SEQUENCE {{PBKDF2-params}} }
129 DERSequenceEncoder pbes2KDFs(pbes2Params);
130 {
131 pbkdf2Id.encode(pbes2KDFs);
132 // AlgorithmIdentifier ::= SEQUENCE {
133 // salt OCTET STRING,
134 // iterationCount INTEGER (1..MAX),
135 // keyLength INTEGER (1..MAX) OPTIONAL,
136 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
137 DERSequenceEncoder pbkdf2Params(pbes2KDFs);
138 {
139 DEREncodeOctetString(pbkdf2Params, salt, 8);
140 DEREncodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
141 }
142 pbkdf2Params.MessageEnd();
143 }
144 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700145
Yingdi Yu2e57a582014-02-20 23:34:43 -0800146 // AlgorithmIdentifier ::= SEQUENCE {
147 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
148 // parameters OCTET STRING} {{iv}} }
149 DERSequenceEncoder pbes2Encs(pbes2Params);
150 {
151 pbes2encsId.encode(pbes2Encs);
152 DEREncodeOctetString(pbes2Encs, iv, 8);
153 }
154 pbes2Encs.MessageEnd();
155 }
156 pbes2Params.MessageEnd();
157 }
158 encryptionAlgorithm.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700159
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700160 DEREncodeOctetString(encryptedPrivateKeyInfo,
161 encryptedOs.buf()->buf(), encryptedOs.buf()->size());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800162 }
163 encryptedPrivateKeyInfo.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700164
Yingdi Yu2e57a582014-02-20 23:34:43 -0800165 return pkcs8Os.buf();
166 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700167 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800168 {
169 throw Error("Cannot export the private key, #3");
170 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800171}
172
173bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700174SecTpm::importPrivateKeyPkcs5IntoTpm(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700175 const uint8_t* buf, size_t size,
176 const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800177{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800178 using namespace CryptoPP;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700179
Yingdi Yu2e57a582014-02-20 23:34:43 -0800180 OID pbes2Id;
181 OID pbkdf2Id;
182 SecByteBlock saltBlock;
183 uint32_t iterationCount;
184 OID pbes2encsId;
185 SecByteBlock ivBlock;
186 SecByteBlock encryptedDataBlock;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700187
Yingdi Yu2e57a582014-02-20 23:34:43 -0800188 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800189 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700190 // decode some decoding processes are not necessary for now,
191 // because we assume only one encryption scheme.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800192 StringSource source(buf, size, true);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700193
Yingdi Yu2e57a582014-02-20 23:34:43 -0800194 // EncryptedPrivateKeyInfo ::= SEQUENCE {
195 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
196 // encryptedData OCTET STRING }
197 BERSequenceDecoder encryptedPrivateKeyInfo(source);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800198 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800199 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
200 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
201 // parameters SEQUENCE {{PBES2-params}} }
202 BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800203 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800204 pbes2Id.decode(encryptionAlgorithm);
205 // PBES2-params ::= SEQUENCE {
206 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
207 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
208 BERSequenceDecoder pbes2Params(encryptionAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800209 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800210 // AlgorithmIdentifier ::= SEQUENCE {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800211 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
212 // parameters SEQUENCE {{PBKDF2-params}} }
213 BERSequenceDecoder pbes2KDFs(pbes2Params);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800214 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800215 pbkdf2Id.decode(pbes2KDFs);
216 // AlgorithmIdentifier ::= SEQUENCE {
217 // salt OCTET STRING,
218 // iterationCount INTEGER (1..MAX),
219 // keyLength INTEGER (1..MAX) OPTIONAL,
220 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
221 BERSequenceDecoder pbkdf2Params(pbes2KDFs);
222 {
223 BERDecodeOctetString(pbkdf2Params, saltBlock);
224 BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
225 }
226 pbkdf2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800227 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800228 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700229
Yingdi Yu2e57a582014-02-20 23:34:43 -0800230 // AlgorithmIdentifier ::= SEQUENCE {
231 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
232 // parameters OCTET STRING} {{iv}} }
233 BERSequenceDecoder pbes2Encs(pbes2Params);
234 {
235 pbes2encsId.decode(pbes2Encs);
236 BERDecodeOctetString(pbes2Encs, ivBlock);
237 }
238 pbes2Encs.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800239 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800240 pbes2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800241 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800242 encryptionAlgorithm.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800243
Yingdi Yu2e57a582014-02-20 23:34:43 -0800244 BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock);
245 }
246 encryptedPrivateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800247 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700248 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800249 {
250 return false;
251 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800252
Yingdi Yu2e57a582014-02-20 23:34:43 -0800253 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
254 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
255 byte derived[24] = {0};
256 byte purpose = 0;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700257
Yingdi Yu2e57a582014-02-20 23:34:43 -0800258 try
259 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700260 keyGenerator.DeriveKey(derived, derivedLen,
261 purpose,
262 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
263 saltBlock.BytePtr(), saltBlock.size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800264 iterationCount);
265 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700266 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800267 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800268 return false;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800269 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800270
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700271 //decrypt
272 CBC_Mode< DES_EDE3 >::Decryption d;
273 d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr());
274
275 OBufferStream privateKeyOs;
276 try
277 {
278 StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true,
279 new StreamTransformationFilter(d, new FileSink(privateKeyOs)));
280 }
281 catch (CryptoPP::Exception& e)
282 {
283 return false;
284 }
285
Yingdi Yu5e96e002014-04-23 18:32:15 -0700286 if (!importPrivateKeyPkcs8IntoTpm(keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700287 privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()))
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800288 return false;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700289
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700290 //determine key type
291 StringSource privateKeySource(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size(), true);
292
293 KeyType publicKeyType = KEY_TYPE_NULL;
294 SecByteBlock rawKeyBits;
295 // PrivateKeyInfo ::= SEQUENCE {
296 // INTEGER,
297 // SEQUENCE,
298 // OCTECT STRING}
299 BERSequenceDecoder privateKeyInfo(privateKeySource);
300 {
301 uint32_t versionNum;
302 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
303 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
304 {
305 OID keyTypeOID;
306 keyTypeOID.decode(sequenceDecoder);
307 if (keyTypeOID == oid::RSA)
308 publicKeyType = KEY_TYPE_RSA;
309 else if (keyTypeOID == oid::ECDSA)
310 publicKeyType = KEY_TYPE_ECDSA;
311 else
312 return false; // Unsupported key type;
313 }
314 }
315
316
Yingdi Yu2e57a582014-02-20 23:34:43 -0800317 //derive public key
318 OBufferStream publicKeyOs;
319
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700320 try {
321 switch (publicKeyType) {
322 case KEY_TYPE_RSA:
323 {
324 RSA::PrivateKey privateKey;
325 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
326 RSAFunction publicKey(privateKey);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700327
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700328 FileSink publicKeySink(publicKeyOs);
329 publicKey.DEREncode(publicKeySink);
330 publicKeySink.MessageEnd();
331 break;
332 }
333 case KEY_TYPE_ECDSA:
334 {
335 ECDSA<ECP, SHA256>::PrivateKey privateKey;
336 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
337
338 ECDSA<ECP, SHA256>::PublicKey publicKey;
339 privateKey.MakePublicKey(publicKey);
340 publicKey.AccessGroupParameters().SetEncodeAsOID(true);
341
342 FileSink publicKeySink(publicKeyOs);
343 publicKey.DEREncode(publicKeySink);
344 publicKeySink.MessageEnd();
345 break;
346 }
347 default:
Yingdi Yu2e57a582014-02-20 23:34:43 -0800348 return false;
349 }
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700350 }
351 catch (CryptoPP::Exception& e) {
352 return false;
353 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800354
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700355 if (!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800356 return false;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700357
Yingdi Yu2e57a582014-02-20 23:34:43 -0800358 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800359}
360
Yingdi Yu7036ce22014-06-19 18:53:37 -0700361bool
362SecTpm::getImpExpPassWord(std::string& password, const std::string& prompt)
363{
364 bool isInitialized = false;
365
Alexander Afanasyevcf3a6672015-02-01 20:33:22 -0800366#ifdef NDN_CXX_HAVE_GETPASS
Yingdi Yu7036ce22014-06-19 18:53:37 -0700367 char* pw0 = 0;
368
369 pw0 = getpass(prompt.c_str());
370 if (0 == pw0)
371 return false;
372 std::string password1 = pw0;
373 memset(pw0, 0, strlen(pw0));
374
375 pw0 = getpass("Confirm:");
376 if (0 == pw0)
377 {
378 std::fill(password1.begin(), password1.end(), 0);
379 return false;
380 }
381
382 if (0 == password1.compare(pw0))
383 {
384 isInitialized = true;
385 password.swap(password1);
386 }
387
388 std::fill(password1.begin(), password1.end(), 0);
389 memset(pw0, 0, strlen(pw0));
390
391 if (password.empty())
392 return false;
393
Alexander Afanasyeva2ada222015-01-22 18:34:16 -0800394#endif // NDN_CXX_HAVE_GETPASS
395
Yingdi Yu7036ce22014-06-19 18:53:37 -0700396 return isInitialized;
397}
398
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800399
Yingdi Yufc40d872014-02-18 12:56:04 -0800400} // namespace ndn