blob: a4b27f14c0885016da323c1f40a084b7750e3938 [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 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.
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"
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080029
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080030namespace ndn {
31
Yingdi Yu5ec0ee32014-06-24 16:26:09 -070032using std::string;
33
Yingdi Yu41546342014-11-30 23:37:53 -080034SecTpm::SecTpm(const string& location)
35 : m_location(location)
36{
37}
38
39SecTpm::~SecTpm()
40{
41}
42
43std::string
44SecTpm::getTpmLocator()
45{
Alexander Afanasyev07113802015-01-15 19:14:36 -080046 return this->getScheme() + ":" + m_location;
Yingdi Yu41546342014-11-30 23:37:53 -080047}
48
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080049ConstBufferPtr
Yingdi Yu5e96e002014-04-23 18:32:15 -070050SecTpm::exportPrivateKeyPkcs5FromTpm(const Name& keyName, const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080051{
Yingdi Yu2e57a582014-02-20 23:34:43 -080052 using namespace CryptoPP;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070053
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080054 uint8_t salt[8] = {0};
55 uint8_t iv[8] = {0};
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070056
Yingdi Yu2e57a582014-02-20 23:34:43 -080057 // derive key
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070058 if (!generateRandomBlock(salt, 8) || !generateRandomBlock(iv, 8))
Yingdi Yu2e57a582014-02-20 23:34:43 -080059 throw Error("Cannot generate salt or iv");
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080060
Yingdi Yu2e57a582014-02-20 23:34:43 -080061 uint32_t iterationCount = 2048;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070062
Yingdi Yu2e57a582014-02-20 23:34:43 -080063 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
64 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
65 byte derived[24] = {0};
66 byte purpose = 0;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070067
Yingdi Yu2e57a582014-02-20 23:34:43 -080068 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080069 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070070 keyGenerator.DeriveKey(derived, derivedLen, purpose,
71 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -080072 salt, 8, iterationCount);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080073 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070074 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080075 {
76 throw Error("Cannot derived the encryption key");
77 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -080078
Yingdi Yu2e57a582014-02-20 23:34:43 -080079 //encrypt
80 CBC_Mode< DES_EDE3 >::Encryption e;
81 e.SetKeyWithIV(derived, derivedLen, iv);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070082
Yingdi Yu5e96e002014-04-23 18:32:15 -070083 ConstBufferPtr pkcs8PrivateKey = exportPrivateKeyPkcs8FromTpm(keyName);
Yingdi Yu9d9d5992014-06-25 12:25:16 -070084
Yingdi Yu5e96e002014-04-23 18:32:15 -070085 if (!static_cast<bool>(pkcs8PrivateKey))
Yingdi Yu2e57a582014-02-20 23:34:43 -080086 throw Error("Cannot export the private key, #1");
87
88 OBufferStream encryptedOs;
89 try
90 {
Yingdi Yu5e96e002014-04-23 18:32:15 -070091 StringSource stringSource(pkcs8PrivateKey->buf(), pkcs8PrivateKey->size(), true,
Yingdi Yu2e57a582014-02-20 23:34:43 -080092 new StreamTransformationFilter(e, new FileSink(encryptedOs)));
93 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070094 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -080095 {
96 throw Error("Cannot export the private key, #2");
97 }
98
99 //encode
100 OID pbes2Id("1.2.840.113549.1.5.13");
101 OID pbkdf2Id("1.2.840.113549.1.5.12");
102 OID pbes2encsId("1.2.840.113549.3.7");
103
104 OBufferStream pkcs8Os;
105 try
106 {
107 FileSink sink(pkcs8Os);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700108
Yingdi Yu2e57a582014-02-20 23:34:43 -0800109 // EncryptedPrivateKeyInfo ::= SEQUENCE {
110 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
111 // encryptedData OCTET STRING }
112 DERSequenceEncoder encryptedPrivateKeyInfo(sink);
113 {
114 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
115 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
116 // parameters SEQUENCE {{PBES2-params}} }
117 DERSequenceEncoder encryptionAlgorithm(encryptedPrivateKeyInfo);
118 {
119 pbes2Id.encode(encryptionAlgorithm);
120 // PBES2-params ::= SEQUENCE {
121 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
122 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
123 DERSequenceEncoder pbes2Params(encryptionAlgorithm);
124 {
125 // AlgorithmIdentifier ::= SEQUENCE {
126 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
127 // parameters SEQUENCE {{PBKDF2-params}} }
128 DERSequenceEncoder pbes2KDFs(pbes2Params);
129 {
130 pbkdf2Id.encode(pbes2KDFs);
131 // AlgorithmIdentifier ::= SEQUENCE {
132 // salt OCTET STRING,
133 // iterationCount INTEGER (1..MAX),
134 // keyLength INTEGER (1..MAX) OPTIONAL,
135 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
136 DERSequenceEncoder pbkdf2Params(pbes2KDFs);
137 {
138 DEREncodeOctetString(pbkdf2Params, salt, 8);
139 DEREncodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
140 }
141 pbkdf2Params.MessageEnd();
142 }
143 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700144
Yingdi Yu2e57a582014-02-20 23:34:43 -0800145 // AlgorithmIdentifier ::= SEQUENCE {
146 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
147 // parameters OCTET STRING} {{iv}} }
148 DERSequenceEncoder pbes2Encs(pbes2Params);
149 {
150 pbes2encsId.encode(pbes2Encs);
151 DEREncodeOctetString(pbes2Encs, iv, 8);
152 }
153 pbes2Encs.MessageEnd();
154 }
155 pbes2Params.MessageEnd();
156 }
157 encryptionAlgorithm.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700158
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700159 DEREncodeOctetString(encryptedPrivateKeyInfo,
160 encryptedOs.buf()->buf(), encryptedOs.buf()->size());
Yingdi Yu2e57a582014-02-20 23:34:43 -0800161 }
162 encryptedPrivateKeyInfo.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700163
Yingdi Yu2e57a582014-02-20 23:34:43 -0800164 return pkcs8Os.buf();
165 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700166 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800167 {
168 throw Error("Cannot export the private key, #3");
169 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800170}
171
172bool
Yingdi Yu5e96e002014-04-23 18:32:15 -0700173SecTpm::importPrivateKeyPkcs5IntoTpm(const Name& keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700174 const uint8_t* buf, size_t size,
175 const string& passwordStr)
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800176{
Yingdi Yu2e57a582014-02-20 23:34:43 -0800177 using namespace CryptoPP;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700178
Yingdi Yu2e57a582014-02-20 23:34:43 -0800179 OID pbes2Id;
180 OID pbkdf2Id;
181 SecByteBlock saltBlock;
182 uint32_t iterationCount;
183 OID pbes2encsId;
184 SecByteBlock ivBlock;
185 SecByteBlock encryptedDataBlock;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700186
Yingdi Yu2e57a582014-02-20 23:34:43 -0800187 try
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800188 {
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700189 // decode some decoding processes are not necessary for now,
190 // because we assume only one encryption scheme.
Yingdi Yu2e57a582014-02-20 23:34:43 -0800191 StringSource source(buf, size, true);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700192
Yingdi Yu2e57a582014-02-20 23:34:43 -0800193 // EncryptedPrivateKeyInfo ::= SEQUENCE {
194 // encryptionAlgorithm EncryptionAlgorithmIdentifier,
195 // encryptedData OCTET STRING }
196 BERSequenceDecoder encryptedPrivateKeyInfo(source);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800197 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800198 // EncryptionAlgorithmIdentifier ::= SEQUENCE {
199 // algorithm OBJECT IDENTIFIER {{PBES2-id}},
200 // parameters SEQUENCE {{PBES2-params}} }
201 BERSequenceDecoder encryptionAlgorithm(encryptedPrivateKeyInfo);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800202 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800203 pbes2Id.decode(encryptionAlgorithm);
204 // PBES2-params ::= SEQUENCE {
205 // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
206 // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
207 BERSequenceDecoder pbes2Params(encryptionAlgorithm);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800208 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800209 // AlgorithmIdentifier ::= SEQUENCE {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800210 // algorithm OBJECT IDENTIFIER {{PBKDF2-id}},
211 // parameters SEQUENCE {{PBKDF2-params}} }
212 BERSequenceDecoder pbes2KDFs(pbes2Params);
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800213 {
Yingdi Yu2e57a582014-02-20 23:34:43 -0800214 pbkdf2Id.decode(pbes2KDFs);
215 // AlgorithmIdentifier ::= SEQUENCE {
216 // salt OCTET STRING,
217 // iterationCount INTEGER (1..MAX),
218 // keyLength INTEGER (1..MAX) OPTIONAL,
219 // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 }
220 BERSequenceDecoder pbkdf2Params(pbes2KDFs);
221 {
222 BERDecodeOctetString(pbkdf2Params, saltBlock);
223 BERDecodeUnsigned<uint32_t>(pbkdf2Params, iterationCount, INTEGER);
224 }
225 pbkdf2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800226 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800227 pbes2KDFs.MessageEnd();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700228
Yingdi Yu2e57a582014-02-20 23:34:43 -0800229 // AlgorithmIdentifier ::= SEQUENCE {
230 // algorithm OBJECT IDENTIFIER {{DES-EDE3-CBC-PAD}},
231 // parameters OCTET STRING} {{iv}} }
232 BERSequenceDecoder pbes2Encs(pbes2Params);
233 {
234 pbes2encsId.decode(pbes2Encs);
235 BERDecodeOctetString(pbes2Encs, ivBlock);
236 }
237 pbes2Encs.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800238 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800239 pbes2Params.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800240 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800241 encryptionAlgorithm.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800242
Yingdi Yu2e57a582014-02-20 23:34:43 -0800243 BERDecodeOctetString(encryptedPrivateKeyInfo, encryptedDataBlock);
244 }
245 encryptedPrivateKeyInfo.MessageEnd();
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800246 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700247 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800248 {
249 return false;
250 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800251
Yingdi Yu2e57a582014-02-20 23:34:43 -0800252 PKCS5_PBKDF2_HMAC<SHA1> keyGenerator;
253 size_t derivedLen = 24; //For DES-EDE3-CBC-PAD
254 byte derived[24] = {0};
255 byte purpose = 0;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700256
Yingdi Yu2e57a582014-02-20 23:34:43 -0800257 try
258 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700259 keyGenerator.DeriveKey(derived, derivedLen,
260 purpose,
261 reinterpret_cast<const byte*>(passwordStr.c_str()), passwordStr.size(),
262 saltBlock.BytePtr(), saltBlock.size(),
Yingdi Yu2e57a582014-02-20 23:34:43 -0800263 iterationCount);
264 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700265 catch (CryptoPP::Exception& e)
Yingdi Yu2e57a582014-02-20 23:34:43 -0800266 {
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800267 return false;
Yingdi Yu2e57a582014-02-20 23:34:43 -0800268 }
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800269
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700270 //decrypt
271 CBC_Mode< DES_EDE3 >::Decryption d;
272 d.SetKeyWithIV(derived, derivedLen, ivBlock.BytePtr());
273
274 OBufferStream privateKeyOs;
275 try
276 {
277 StringSource encryptedSource(encryptedDataBlock.BytePtr(), encryptedDataBlock.size(), true,
278 new StreamTransformationFilter(d, new FileSink(privateKeyOs)));
279 }
280 catch (CryptoPP::Exception& e)
281 {
282 return false;
283 }
284
Yingdi Yu5e96e002014-04-23 18:32:15 -0700285 if (!importPrivateKeyPkcs8IntoTpm(keyName,
Yingdi Yu4b8c6a22014-04-15 23:00:54 -0700286 privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()))
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800287 return false;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700288
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700289 //determine key type
290 StringSource privateKeySource(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size(), true);
291
292 KeyType publicKeyType = KEY_TYPE_NULL;
293 SecByteBlock rawKeyBits;
294 // PrivateKeyInfo ::= SEQUENCE {
295 // INTEGER,
296 // SEQUENCE,
297 // OCTECT STRING}
298 BERSequenceDecoder privateKeyInfo(privateKeySource);
299 {
300 uint32_t versionNum;
301 BERDecodeUnsigned<uint32_t>(privateKeyInfo, versionNum, INTEGER);
302 BERSequenceDecoder sequenceDecoder(privateKeyInfo);
303 {
304 OID keyTypeOID;
305 keyTypeOID.decode(sequenceDecoder);
306 if (keyTypeOID == oid::RSA)
307 publicKeyType = KEY_TYPE_RSA;
308 else if (keyTypeOID == oid::ECDSA)
309 publicKeyType = KEY_TYPE_ECDSA;
310 else
311 return false; // Unsupported key type;
312 }
313 }
314
315
Yingdi Yu2e57a582014-02-20 23:34:43 -0800316 //derive public key
317 OBufferStream publicKeyOs;
318
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700319 try {
320 switch (publicKeyType) {
321 case KEY_TYPE_RSA:
322 {
323 RSA::PrivateKey privateKey;
324 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
325 RSAFunction publicKey(privateKey);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700326
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700327 FileSink publicKeySink(publicKeyOs);
328 publicKey.DEREncode(publicKeySink);
329 publicKeySink.MessageEnd();
330 break;
331 }
332 case KEY_TYPE_ECDSA:
333 {
334 ECDSA<ECP, SHA256>::PrivateKey privateKey;
335 privateKey.Load(StringStore(privateKeyOs.buf()->buf(), privateKeyOs.buf()->size()).Ref());
336
337 ECDSA<ECP, SHA256>::PublicKey publicKey;
338 privateKey.MakePublicKey(publicKey);
339 publicKey.AccessGroupParameters().SetEncodeAsOID(true);
340
341 FileSink publicKeySink(publicKeyOs);
342 publicKey.DEREncode(publicKeySink);
343 publicKeySink.MessageEnd();
344 break;
345 }
346 default:
Yingdi Yu2e57a582014-02-20 23:34:43 -0800347 return false;
348 }
Yingdi Yu9d9d5992014-06-25 12:25:16 -0700349 }
350 catch (CryptoPP::Exception& e) {
351 return false;
352 }
Yingdi Yu2e57a582014-02-20 23:34:43 -0800353
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700354 if (!importPublicKeyPkcs1IntoTpm(keyName, publicKeyOs.buf()->buf(), publicKeyOs.buf()->size()))
Yingdi Yu2e57a582014-02-20 23:34:43 -0800355 return false;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700356
Yingdi Yu2e57a582014-02-20 23:34:43 -0800357 return true;
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800358}
359
Yingdi Yu7036ce22014-06-19 18:53:37 -0700360bool
361SecTpm::getImpExpPassWord(std::string& password, const std::string& prompt)
362{
363 bool isInitialized = false;
364
365 char* pw0 = 0;
366
367 pw0 = getpass(prompt.c_str());
368 if (0 == pw0)
369 return false;
370 std::string password1 = pw0;
371 memset(pw0, 0, strlen(pw0));
372
373 pw0 = getpass("Confirm:");
374 if (0 == pw0)
375 {
376 std::fill(password1.begin(), password1.end(), 0);
377 return false;
378 }
379
380 if (0 == password1.compare(pw0))
381 {
382 isInitialized = true;
383 password.swap(password1);
384 }
385
386 std::fill(password1.begin(), password1.end(), 0);
387 memset(pw0, 0, strlen(pw0));
388
389 if (password.empty())
390 return false;
391
392 return isInitialized;
393}
394
Yingdi Yu8dceb1d2014-02-18 12:45:10 -0800395
Yingdi Yufc40d872014-02-18 12:56:04 -0800396} // namespace ndn