Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTAsymmetricKeyOpenSSLPrivdp.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTAsymmetricKeyOpenSSLPrivdp.cpp
4  *
5  */
6 
7 /************************************************************
8  -----BEGIN PGP SIGNED MESSAGE-----
9  Hash: SHA1
10 
11  * OPEN TRANSACTIONS
12  *
13  * Financial Cryptography and Digital Cash
14  * Library, Protocol, API, Server, CLI, GUI
15  *
16  * -- Anonymous Numbered Accounts.
17  * -- Untraceable Digital Cash.
18  * -- Triple-Signed Receipts.
19  * -- Cheques, Vouchers, Transfers, Inboxes.
20  * -- Basket Currencies, Markets, Payment Plans.
21  * -- Signed, XML, Ricardian-style Contracts.
22  * -- Scripted smart contracts.
23  *
24  * Copyright (C) 2010-2013 by "Fellow Traveler" (A pseudonym)
25  *
26  * EMAIL:
28  *
29  * BITCOIN: 1NtTPVVjDsUfDWybS4BwvHpG2pdS9RnYyQ
30  *
31  * KEY FINGERPRINT (PGP Key in license file):
32  * 9DD5 90EB 9292 4B48 0484 7910 0308 00ED F951 BB8E
33  *
34  * OFFICIAL PROJECT WIKI(s):
35  * https://github.com/FellowTraveler/Moneychanger
36  * https://github.com/FellowTraveler/Open-Transactions/wiki
37  *
38  * WEBSITE:
39  * http://www.OpenTransactions.org/
40  *
41  * Components and licensing:
42  * -- Moneychanger..A Java client GUI.....LICENSE:.....GPLv3
43  * -- otlib.........A class library.......LICENSE:...LAGPLv3
44  * -- otapi.........A client API..........LICENSE:...LAGPLv3
45  * -- opentxs/ot....Command-line client...LICENSE:...LAGPLv3
46  * -- otserver......Server Application....LICENSE:....AGPLv3
47  * Github.com/FellowTraveler/Open-Transactions/wiki/Components
48  *
49  * All of the above OT components were designed and written by
50  * Fellow Traveler, with the exception of Moneychanger, which
51  * was contracted out to Vicky C ([email protected]).
52  * The open-source community has since actively contributed.
53  *
54  * -----------------------------------------------------
55  *
56  * LICENSE:
57  * This program is free software: you can redistribute it
58  * and/or modify it under the terms of the GNU Affero
59  * General Public License as published by the Free Software
60  * Foundation, either version 3 of the License, or (at your
61  * option) any later version.
62  *
63  * ADDITIONAL PERMISSION under the GNU Affero GPL version 3
64  * section 7: (This paragraph applies only to the LAGPLv3
65  * components listed above.) If you modify this Program, or
66  * any covered work, by linking or combining it with other
67  * code, such other code is not for that reason alone subject
68  * to any of the requirements of the GNU Affero GPL version 3.
69  * (==> This means if you are only using the OT API, then you
70  * don't have to open-source your code--only your changes to
71  * Open-Transactions itself must be open source. Similar to
72  * LGPLv3, except it applies to software-as-a-service, not
73  * just to distributing binaries.)
74  *
75  * Extra WAIVER for OpenSSL, Lucre, and all other libraries
76  * used by Open Transactions: This program is released under
77  * the AGPL with the additional exemption that compiling,
78  * linking, and/or using OpenSSL is allowed. The same is true
79  * for any other open source libraries included in this
80  * project: complete waiver from the AGPL is hereby granted to
81  * compile, link, and/or use them with Open-Transactions,
82  * according to their own terms, as long as the rest of the
83  * Open-Transactions terms remain respected, with regard to
84  * the Open-Transactions code itself.
85  *
86  * Lucre License:
87  * This code is also "dual-license", meaning that Ben Lau-
88  * rie's license must also be included and respected, since
89  * the code for Lucre is also included with Open Transactions.
90  * See Open-Transactions/src/otlib/lucre/LUCRE_LICENSE.txt
91  * The Laurie requirements are light, but if there is any
92  * problem with his license, simply remove the Lucre code.
93  * Although there are no other blind token algorithms in Open
94  * Transactions (yet. credlib is coming), the other functions
95  * will continue to operate.
96  * See Lucre on Github: https://github.com/benlaurie/lucre
97  * -----------------------------------------------------
98  * You should have received a copy of the GNU Affero General
99  * Public License along with this program. If not, see:
100  * http://www.gnu.org/licenses/
101  *
102  * If you would like to use this software outside of the free
103  * software license, please contact FellowTraveler.
104  * (Unfortunately many will run anonymously and untraceably,
105  * so who could really stop them?)
106  *
107  * DISCLAIMER:
108  * This program is distributed in the hope that it will be
109  * useful, but WITHOUT ANY WARRANTY; without even the implied
110  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
111  * PURPOSE. See the GNU Affero General Public License for
112  * more details.
113 
114  -----BEGIN PGP SIGNATURE-----
115  Version: GnuPG v1.4.9 (Darwin)
116 
117  iQIcBAEBAgAGBQJRSsfJAAoJEAMIAO35UbuOQT8P/RJbka8etf7wbxdHQNAY+2cC
118  vDf8J3X8VI+pwMqv6wgTVy17venMZJa4I4ikXD/MRyWV1XbTG0mBXk/7AZk7Rexk
119  KTvL/U1kWiez6+8XXLye+k2JNM6v7eej8xMrqEcO0ZArh/DsLoIn1y8p8qjBI7+m
120  aE7lhstDiD0z8mwRRLKFLN2IH5rAFaZZUvj5ERJaoYUKdn4c+RcQVei2YOl4T0FU
121  LWND3YLoH8naqJXkaOKEN4UfJINCwxhe5Ke9wyfLWLUO7NamRkWD2T7CJ0xocnD1
122  sjAzlVGNgaFDRflfIF4QhBx1Ddl6wwhJfw+d08bjqblSq8aXDkmFA7HeunSFKkdn
123  oIEOEgyj+veuOMRJC5pnBJ9vV+7qRdDKQWaCKotynt4sWJDGQ9kWGWm74SsNaduN
124  TPMyr9kNmGsfR69Q2Zq/FLcLX/j8ESxU+HYUB4vaARw2xEOu2xwDDv6jt0j3Vqsg
125  x7rWv4S/Eh18FDNDkVRChiNoOIilLYLL6c38uMf1pnItBuxP3uhgY6COm59kVaRh
126  nyGTYCDYD2TK+fI9o89F1297uDCwEJ62U0Q7iTDp5QuXCoxkPfv8/kX6lS6T3y9G
127  M9mqIoLbIQ1EDntFv7/t6fUTS2+46uCrdZWbQ5RjYXdrzjij02nDmJAm2BngnZvd
128  kamH0Y/n11lCvo1oQxM+
129  =uSzz
130  -----END PGP SIGNATURE-----
131  **************************************************************/
132 
133 #include "stdafx.hpp"
134 
136 
137 #include "crypto/OTASCIIArmor.hpp"
138 #include "OTLog.hpp"
139 #include "crypto/OTPassword.hpp"
140 #include "crypto/OTPasswordData.hpp"
141 #include "OTPayload.hpp"
142 
143 #if defined(OT_CRYPTO_USING_OPENSSL)
144 #include "crypto/OpenSSL_BIO.hpp"
145 #endif
146 
147 #include "util/stacktrace.h"
148 
149 namespace opentxs
150 {
151 
152 #if defined(OT_CRYPTO_USING_OPENSSL)
153 
154 void OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::SetX509(X509* x509)
155 {
156  if (m_pX509 == x509) return;
157 
158  if (nullptr != m_pX509) {
159  X509_free(m_pX509);
160  m_pX509 = nullptr;
161  }
162 
163  m_pX509 = x509;
164 }
165 
166 void OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::SetKeyAsCopyOf(
167  EVP_PKEY& theKey, bool bIsPrivateKey, const OTPasswordData* pPWData,
168  const OTPassword* pImportPassword)
169 {
170  backlink->Release();
171  OTPasswordData thePWData(!pImportPassword
172  ? "Enter your wallet's master passphrase. "
173  "(OTAsymmetricKey_OpenSSL::SetKeyAsCopyOf)"
174  : "Enter your exported Nym's passphrase. "
175  "(OTAsymmetricKey_OpenSSL::SetKeyAsCopyOf)");
176 
177  m_pKey = bIsPrivateKey
179  CopyPrivateKey(theKey,
180  nullptr == pPWData ? &thePWData : pPWData,
181  pImportPassword)
182  : OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::
183  CopyPublicKey(theKey,
184  nullptr == pPWData ? &thePWData : pPWData,
185  pImportPassword);
186  OT_ASSERT_MSG(nullptr != m_pKey, "OTAsymmetricKey_OpenSSL::SetKeyAsCopyOf: "
187  "ASSERT: nullptr != m_pKey \n");
188 
189  backlink->m_bIsPublicKey = !bIsPrivateKey;
190  backlink->m_bIsPrivateKey = bIsPrivateKey;
191 
192  if (nullptr == backlink->m_p_ascKey) {
193  backlink->m_p_ascKey = new OTASCIIArmor;
194  OT_ASSERT(nullptr != backlink->m_p_ascKey);
195  }
196  else {
197  backlink->m_p_ascKey->Release();
198  }
199  // By this point, m_p_ascKey definitely exists, and it's empty.
200 
201  if (backlink->m_bIsPrivateKey) {
203  *m_pKey, *backlink->m_p_ascKey, backlink->m_timer,
204  nullptr == pPWData ? &thePWData : pPWData, pImportPassword);
205  }
206  // NOTE: Timer is already set INSIDE ArmorPrivateKey. No need to set twice.
207  // m_timer.start(); // Note: this isn't the ultimate timer solution.
208  // See notes in ReleaseKeyLowLevel.
209  else if (backlink->m_bIsPublicKey) {
211  *m_pKey, *backlink->m_p_ascKey);
212  }
213  else {
214  otErr << __FUNCTION__
215  << ": Error: This key is NEITHER public NOR private!\n";
216  }
217 }
218 
219 EVP_PKEY* OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::
220  GetKeyLowLevel() const
221 {
222  return m_pKey;
223 }
224 
225 const EVP_PKEY* OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::GetKey(
226  const OTPasswordData* pPWData)
227 {
228  OT_ASSERT_MSG(nullptr != backlink->m_p_ascKey,
229  "OTAsymmetricKey_OpenSSL::GetKey: nullptr != m_p_ascKey\n");
230 
231  if (nullptr == backlink->m_p_ascKey) {
232  otErr << __FUNCTION__
233  << ": Unexpected nullptr m_p_ascKey. Printing stack "
234  "trace (and returning nullptr):\n";
235  print_stacktrace();
236  return nullptr;
237  }
238 
239  if (backlink->m_timer.getElapsedTimeInSec() > OT_KEY_TIMER)
240  backlink->ReleaseKeyLowLevel(); // This releases the actual loaded key,
241  // but not the ascii-armored, encrypted
242  // version of it.
243  // (Thus forcing a reload, and thus forcing the passphrase to be entered
244  // again.)
245 
246  if (nullptr == m_pKey)
247  return InstantiateKey(pPWData); // this is the ONLY place, currently,
248  // that this private method is called.
249 
250  return m_pKey;
251 }
252 
253 EVP_PKEY* OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::
254  InstantiateKey(const OTPasswordData* pPWData)
255 {
256  if (backlink->IsPublic())
257  return InstantiatePublicKey(pPWData); // this is the ONLY place,
258  // currently, that this private
259  // method is called.
260 
261  else if (backlink->IsPrivate())
262  return InstantiatePrivateKey(pPWData); // this is the ONLY place,
263  // currently, that this private
264  // method is called.
265 
266  else
267  otErr << "OTAsymmetricKey_OpenSSL::InstantiateKey: Error: Key is "
268  "neither public nor private!\n";
269 
270  return nullptr;
271 }
272 
274  EVP_PKEY& theKey, const OTPasswordData* pPWData,
275  const OTPassword* pImportPassword)
276 {
277  // Create a new memory buffer on the OpenSSL side
278  OpenSSL_BIO bmem = BIO_new(BIO_s_mem());
280  nullptr != bmem,
281  "OTAsymmetricKey_OpenSSL::CopyPublicKey: ASSERT: nullptr != bmem");
282 
283  EVP_PKEY* pReturnKey = nullptr;
284 
285  // write a public key to that buffer, from theKey (parameter.)
286  //
287  int32_t nWriteBio = PEM_write_bio_PUBKEY(bmem, &theKey);
288 
289  if (0 == nWriteBio) {
290  otErr << __FUNCTION__
291  << ": Error: Failed writing EVP_PKEY to memory buffer.\n";
292  }
293  else {
294  otLog5 << __FUNCTION__
295  << ": Success writing EVP_PKEY to memory buffer.\n";
296 
297  char* pChar = nullptr;
298 
299  // After the below call, pChar will point to the memory buffer where the
300  // public key
301  // supposedly is, and lSize will contain the size of that memory.
302  //
303  const int64_t lSize = BIO_get_mem_data(bmem, &pChar);
304  const uint32_t nSize = static_cast<uint32_t>(lSize);
305 
306  if (nSize > 0) {
307  OTPayload theData;
308 
309  // Set the buffer size in our own memory.
310  theData.SetPayloadSize(nSize);
311 
312  void* pv = OTPassword::safe_memcpy(
313  (static_cast<char*>(const_cast<void*>(
314  theData.GetPayloadPointer()))), // destination
315  theData.GetSize(), // size of destination buffer.
316  pChar, // source
317  nSize); // length of source.
318 
319  if (nullptr != pv) {
320  // Next, copy theData's contents into a new BIO_mem_buf,
321  // so OpenSSL can load the key out of it.
322  //
323  OpenSSL_BIO keyBio =
324  BIO_new_mem_buf(static_cast<char*>(const_cast<void*>(
325  theData.GetPayloadPointer())),
326  theData.GetSize());
327  OT_ASSERT_MSG(nullptr != keyBio,
328  "OTAsymmetricKey_OpenSSL::"
329  "CopyPublicKey: Assert: nullptr != "
330  "keyBio \n");
331 
332  // Next we load up the key from the BIO string into an
333  // instantiated key object.
334  //
335  OTPasswordData thePWData(
336  nullptr == pImportPassword
337  ? "Enter your wallet master passphrase. "
338  "(OTAsymmetricKey_OpenSSL::CopyPublicKey is calling "
339  "PEM_read_bio_PUBKEY...)"
340  : "Enter the passphrase for your exported Nym.");
341 
342  if (nullptr == pImportPassword)
343  pReturnKey = PEM_read_bio_PUBKEY(
344  keyBio, nullptr, OTAsymmetricKey::GetPasswordCallback(),
345  nullptr == pPWData
346  ? &thePWData
347  : const_cast<OTPasswordData*>(pPWData));
348  else
349  pReturnKey = PEM_read_bio_PUBKEY(
350  keyBio, nullptr, 0,
351  const_cast<OTPassword*>(pImportPassword));
352 
353  // We don't need the BIO anymore.
354  // Free the BIO and related buffers, filters, etc. (auto with
355  // scope).
356  //
357  }
358  else {
359  otErr << __FUNCTION__ << ": Error: Failed copying memory from "
360  "BIO into OTPayload.\n";
361  }
362  }
363  else {
364  otErr << __FUNCTION__
365  << ": Failed copying private key into memory.\n";
366  }
367  }
368 
369  return pReturnKey;
370 }
371 
372 // NOTE: OpenSSL will store the EVP_PKEY inside the X509, and when I get it,
373 // I'm not supposed to destroy the x509 until I destroy the EVP_PKEY FIRST!
374 // (AND it reference-counts.)
375 // Since I want ability to destroy the two, independent of each other, I made
376 // static functions here for copying public and private keys, so I am ALWAYS
377 // working with MY OWN copy of any given key, and not OpenSSL's
378 // reference-counted
379 // one.
380 //
381 // Furthermore, BIO_mem_buf doesn't allocate its own memory, but uses the memory
382 // you pass to it. You CANNOT free that memory until you destroy the BIO.
383 //
384 // That's why you see me copying one bio into a payload, before copying it into
385 // the next bio. Todo security: copy it into an OTPassword here, instead of an
386 // OTPayload, which is safer, and more appropriate for a private key. Make sure
387 // OTPassword can accommodate a bit larger size than what it does now.
388 //
390  CopyPrivateKey(EVP_PKEY& theKey, const OTPasswordData* pPWData,
391  const OTPassword* pImportPassword)
392 {
393  const EVP_CIPHER* pCipher =
394  EVP_des_ede3_cbc(); // todo should this algorithm be hardcoded?
395 
396  // Create a new memory buffer on the OpenSSL side
397  OpenSSL_BIO bmem = BIO_new(BIO_s_mem());
398  OT_ASSERT(nullptr != bmem);
399 
400  EVP_PKEY* pReturnKey = nullptr;
401 
402  // write a private key to that buffer, from theKey
403  //
404  OTPasswordData thePWDataWrite("OTAsymmetricKey_OpenSSL::CopyPrivateKey is "
405  "calling PEM_write_bio_PrivateKey...");
406 
407  // todo optimization: might just remove the password callback here, and just
408  // write the private key in the clear,
409  // and then load it up again, saving the encrypt/decrypt step that otherwise
410  // occurs, and then as long as we OpenSSL_cleanse
411  // the BIO, then it SHOULD stil be safe, right?
412  //
413  int32_t nWriteBio = false;
414 
415  if (nullptr == pImportPassword)
416  nWriteBio = PEM_write_bio_PrivateKey(
417  bmem, &theKey, pCipher, nullptr, 0,
419  nullptr == pPWData ? &thePWDataWrite
420  : const_cast<OTPasswordData*>(pPWData));
421  else
422  nWriteBio = PEM_write_bio_PrivateKey(
423  bmem, &theKey, pCipher, nullptr, 0, 0,
424  const_cast<void*>(
425  reinterpret_cast<const void*>(pImportPassword->getPassword())));
426 
427  if (0 == nWriteBio) {
428  otErr << __FUNCTION__
429  << ": Failed writing EVP_PKEY to memory buffer.\n";
430  }
431  else {
432  otLog5 << __FUNCTION__
433  << ": Success writing EVP_PKEY to memory buffer.\n";
434 
435  char* pChar = nullptr;
436 
437  // After the below call, pChar will point to the memory buffer where the
438  // private key supposedly is,
439  // and lSize will contain the size of that memory.
440  //
441  const int64_t lSize = BIO_get_mem_data(bmem, &pChar);
442  const uint32_t nSize = static_cast<uint32_t>(lSize);
443 
444  if (nSize > 0) {
445  OTPayload theData;
446 
447  // Set the buffer size in our own memory.
448  theData.SetPayloadSize(nSize);
449 
450  void* pv = OTPassword::safe_memcpy(
451  (static_cast<char*>(const_cast<void*>(
452  theData.GetPayloadPointer()))), // destination
453  theData.GetSize(), // size of destination buffer.
454  pChar, // source
455  nSize); // length of source.
456  // bool bZeroSource=false); // if true, sets the source buffer to
457  // zero after copying is done.
458 
459  if (nullptr != pv) {
460 
461  // Next, copy theData's contents into a new BIO_mem_buf,
462  // so OpenSSL can load the key out of it.
463  //
464  OpenSSL_BIO keyBio =
465  BIO_new_mem_buf(static_cast<char*>(const_cast<void*>(
466  theData.GetPayloadPointer())),
467  theData.GetSize());
468  OT_ASSERT_MSG(nullptr != keyBio,
469  "OTAsymmetricKey_OpenSSL::"
470  "CopyPrivateKey: Assert: nullptr != "
471  "keyBio \n");
472 
473  // Next we load up the key from the BIO string into an
474  // instantiated key object.
475  //
476  OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::"
477  "CopyPrivateKey is calling "
478  "PEM_read_bio_PUBKEY...");
479 
480  if (nullptr == pImportPassword)
481  pReturnKey = PEM_read_bio_PrivateKey(
482  keyBio, nullptr, OTAsymmetricKey::GetPasswordCallback(),
483  nullptr == pPWData
484  ? &thePWData
485  : const_cast<OTPasswordData*>(pPWData));
486  else
487  pReturnKey = PEM_read_bio_PrivateKey(
488  keyBio, nullptr, 0,
489  const_cast<void*>(reinterpret_cast<const void*>(
490  pImportPassword->getPassword())));
491 
492  }
493  else
494  otErr << __FUNCTION__ << ": Error: Failed copying memory from "
495  "BIO into OTPayload.\n";
496 
497  }
498  else {
499  otErr << __FUNCTION__
500  << ": Failed copying private key into memory.\n";
501  }
502  }
503 
504  return pReturnKey;
505 }
506 
507 // Take a public key, theKey (input), and create an armored version of
508 // it into ascKey (output.)
509 //
510 // OpenSSL loaded key ===> ASCII-Armored export of same key.
511 //
513  EVP_PKEY& theKey, OTASCIIArmor& ascKey)
514 {
515  bool bReturnVal = false;
516 
517  const char* szFunc = "OTAsymmetricKey_OpenSSL::ArmorPublicKey";
518 
519  ascKey.Release();
520 
521  // Create a new memory buffer on the OpenSSL side
522  OpenSSL_BIO bmem = BIO_new(BIO_s_mem());
524  nullptr != bmem,
525  "OTAsymmetricKey_OpenSSL::ArmorPublicKey: ASSERT: nullptr != bmem");
526 
527  // write a public key to that buffer, from theKey (parameter.)
528  //
529  int32_t nWriteBio = PEM_write_bio_PUBKEY(bmem, &theKey);
530 
531  if (0 == nWriteBio) {
532  otErr << szFunc
533  << ": Error: Failed writing EVP_PKEY to memory buffer.\n";
534  }
535  else {
536  otLog5 << szFunc << ": Success writing EVP_PKEY to memory buffer.\n";
537 
538  OTPayload theData;
539  char* pChar = nullptr;
540 
541  // After the below call, pChar will point to the memory buffer where the
542  // public key
543  // supposedly is, and lSize will contain the size of that memory.
544  //
545  int64_t lSize = BIO_get_mem_data(bmem, &pChar);
546  uint32_t nSize = static_cast<uint32_t>(
547  lSize); // todo security, etc. Fix this assumed type conversion.
548 
549  if (nSize > 0) {
550  // Set the buffer size in our own memory.
551  theData.SetPayloadSize(nSize);
552 
553  // void * pv =
555  (static_cast<char*>(const_cast<void*>(
556  theData.GetPayloadPointer()))), // destination
557  theData.GetSize(), // size of destination buffer.
558  pChar, // source
559  nSize); // length of source.
560  // bool bZeroSource=false); // if true, sets the source buffer to
561  // zero after copying is done.
562 
563  // This base64 encodes the public key data
564  //
565  ascKey.SetData(theData);
566 
567  otLog5 << szFunc << ": Success copying public key into memory.\n";
568  bReturnVal = true;
569  }
570  else {
571  otErr << szFunc << ": Failed copying public key into memory.\n";
572  }
573  }
574 
575  return bReturnVal;
576 }
577 
578 // (Internal) ASCII-Armored key ====> (Internal) Actual loaded OpenSSL key.
579 //
580 EVP_PKEY* OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::
581  InstantiatePublicKey(const OTPasswordData* pPWData)
582 {
583  OT_ASSERT(m_pKey == nullptr);
584  OT_ASSERT(backlink->m_p_ascKey != nullptr);
585  OT_ASSERT(backlink->IsPublic());
586 
587  const char* szFunc = "OTAsymmetricKey_OpenSSL::InstantiatePublicKey";
588 
589  EVP_PKEY* pReturnKey = nullptr;
590  OTPayload theData;
591 
592  // This base64 decodes the string m_p_ascKey into the
593  // binary payload object "theData"
594  //
595  backlink->m_p_ascKey->GetData(theData);
596 
597  if (theData.GetSize() > 0) {
598 
599  // Next, copy theData's contents into a new BIO_mem_buf,
600  // so OpenSSL can load the key out of it.
601  //
602  OpenSSL_BIO keyBio = BIO_new_mem_buf(
603  static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())),
604  theData.GetSize());
605  OT_ASSERT_MSG(nullptr != keyBio,
606  "OTAsymmetricKey_OpenSSL::"
607  "InstantiatePublicKey: Assert: nullptr != "
608  "keyBio \n");
609 
610  // Next we load up the key from the BIO string into an instantiated key
611  // object.
612  //
613  OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::"
614  "InstantiatePublicKey is calling "
615  "PEM_read_bio_PUBKEY...");
616 
617  if (nullptr == pPWData) pPWData = &thePWData;
618 
619  pReturnKey = PEM_read_bio_PUBKEY(keyBio, nullptr,
621  const_cast<OTPasswordData*>(pPWData));
622 
623  backlink->ReleaseKeyLowLevel(); // Release whatever loaded key I might
624  // have already had.
625 
626  if (nullptr != pReturnKey) {
627  m_pKey = pReturnKey;
628  otLog4
629  << szFunc
630  << ": Success reading public key from ASCII-armored data:\n\n"
631  << backlink->m_p_ascKey->Get() << "\n\n";
632  return m_pKey;
633  }
634  }
635 
636  otErr << szFunc
637  << ": Failed reading public key from ASCII-armored data:\n\n"
638  << backlink->m_p_ascKey->Get() << "\n\n";
639  return nullptr;
640 }
641 
642 EVP_PKEY* OTAsymmetricKey_OpenSSL::OTAsymmetricKey_OpenSSLPrivdp::
643  InstantiatePrivateKey(const OTPasswordData* pPWData)
644 {
645  OT_ASSERT(m_pKey == nullptr);
646  OT_ASSERT(backlink->m_p_ascKey != nullptr);
647  OT_ASSERT(backlink->IsPrivate());
648 
649  EVP_PKEY* pReturnKey = nullptr;
650  OTPayload theData; // after base64-decoding the ascii-armored string, the
651  // (encrypted) binary will be stored here.
652  // --------------------------------------
653  // This line base64 decodes the ascii-armored string into binary object
654  // theData...
655  //
656  backlink->m_p_ascKey->GetData(theData); // theData now contains binary data,
657  // the encrypted private key itself,
658  // no longer in text-armoring.
659  //
660  // Note, for future optimization: the ASCII-ARMORING could be used for
661  // serialization, but the BIO (still encrypted)
662  // could be used in RAM for this object. Otherwise you just have to do the
663  // extra step of ascii-decoding it first to get
664  // the BIO, before being able to instantiate the key itself from that. That
665  // final step can't change, but I can remove
666  // the step before it, in most cases, by just storing the BIO itself,
667  // instead of the ascii-armored string. Or perhaps
668  // make them both available...hm.
669 
670  // Copy the encrypted binary private key data into an OpenSSL memory BIO...
671  //
672  if (theData.GetSize() > 0) {
673  OpenSSL_BIO keyBio = BIO_new_mem_buf(
674  static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())),
675  theData.GetSize()); // theData will zeroMemory upon destruction.
676  OT_ASSERT_MSG(nullptr != keyBio,
677  "OTAsymmetricKey_OpenSSL::"
678  "InstantiatePrivateKey: Assert: nullptr != "
679  "keyBio \n");
680 
681  // Here's thePWData we use if we didn't have anything else:
682  //
683  OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::"
684  "InstantiatePrivateKey is calling "
685  "PEM_read_bio_PrivateKey...");
686 
687  if (nullptr == pPWData) pPWData = &thePWData;
688 
689  pReturnKey = PEM_read_bio_PrivateKey(
690  keyBio, nullptr, OTAsymmetricKey::GetPasswordCallback(),
691  const_cast<OTPasswordData*>(pPWData));
692 
693  // Free the BIO and related buffers, filters, etc.
694  backlink->ReleaseKeyLowLevel();
695 
696  if (nullptr != pReturnKey) {
697  m_pKey = pReturnKey;
698  // TODO (remove theTimer entirely. OTCachedKey replaces already.)
699  // I set this timer because the above required a password. But now
700  // that master key is working,
701  // the above would flow through even WITHOUT the user typing his
702  // passphrase (since master key still
703  // not timed out.) Resulting in THIS timer being reset! Todo: I
704  // already shortened this timer to 30
705  // seconds, but need to phase it down to 0 and then remove it
706  // entirely! Master key takes over now!
707  //
708 
709  backlink->m_timer.start(); // Note: this isn't the ultimate timer
710  // solution. See notes in
711  // ReleaseKeyLowLevel.
712  otLog4
713  << __FUNCTION__
714  << ": Success reading private key from ASCII-armored data.\n\n";
715  // otLog4 << __FUNCTION__ << ": Success reading private key
716  // from ASCII-armored data:\n\n" << m_p_ascKey->Get() << "\n\n";
717  return m_pKey;
718  }
719  }
720  otErr << __FUNCTION__
721  << ": Failed reading private key from ASCII-armored data.\n\n";
722  // otErr << __FUNCTION__ << ": Failed reading private key from
723  // ASCII-armored data:\n\n" << m_p_ascKey->Get() << "\n\n";
724  return nullptr;
725 }
726 
728  EVP_PKEY& theKey, OTASCIIArmor& ascKey, Timer& theTimer,
729  const OTPasswordData* pPWData, const OTPassword* pImportPassword)
730 {
731  bool bReturnVal = false;
732 
733  ascKey.Release();
734 
735  // Create a new memory buffer on the OpenSSL side
736  OpenSSL_BIO bmem = BIO_new(BIO_s_mem());
737  OT_ASSERT(nullptr != bmem);
738 
739  // write a private key to that buffer, from theKey
740  //
741  OTPasswordData thePWData("OTAsymmetricKey_OpenSSL::ArmorPrivateKey is "
742  "calling PEM_write_bio_PrivateKey...");
743 
744  if (nullptr == pPWData) pPWData = &thePWData;
745 
746  int32_t nWriteBio = 0;
747 
748  if (nullptr == pImportPassword)
749  nWriteBio = PEM_write_bio_PrivateKey(
750  bmem, &theKey,
751  EVP_des_ede3_cbc(), // todo should this algorithm be hardcoded?
753  const_cast<OTPasswordData*>(pPWData));
754  else
755  nWriteBio = PEM_write_bio_PrivateKey(
756  bmem, &theKey,
757  EVP_des_ede3_cbc(), // todo should this algorithm be hardcoded?
758  nullptr, 0, 0, const_cast<void*>(reinterpret_cast<const void*>(
759  pImportPassword->getPassword())));
760 
761  if (0 == nWriteBio) {
762  otErr << __FUNCTION__
763  << ": Failed writing EVP_PKEY to memory buffer.\n";
764  }
765  else {
766  // TODO (remove theTimer entirely. OTCachedKey replaces already.)
767  // I set this timer because the above required a password. But now that
768  // master key is working,
769  // the above would flow through even WITHOUT the user typing his
770  // passphrase (since master key still
771  // not timed out.) Resulting in THIS timer being reset! Todo: I already
772  // shortened this timer to 30
773  // seconds, but need to phase it down to 0 and then remove it entirely!
774  // Master key takes over now!
775  //
776 
777  theTimer.start(); // Note: this isn't the ultimate timer solution. See
778  // notes in ReleaseKeyLowLevel.
779 
780  otLog5 << __FUNCTION__
781  << ": Success writing EVP_PKEY to memory buffer.\n";
782 
783  OTPayload theData;
784  char* pChar = nullptr;
785 
786  // After the below call, pChar will point to the memory buffer where the
787  // private key supposedly is,
788  // and lSize will contain the size of that memory.
789  //
790  int64_t lSize = BIO_get_mem_data(bmem, &pChar);
791  uint32_t nSize = static_cast<uint32_t>(lSize);
792 
793  if (nSize > 0) {
794  // Set the buffer size in our own memory.
795  theData.SetPayloadSize(nSize);
796 
797  // void * pv =
799  (static_cast<char*>(const_cast<void*>(
800  theData.GetPayloadPointer()))), // destination
801  theData.GetSize(), // size of destination buffer.
802  pChar, // source
803  nSize); // length of source.
804  // bool bZeroSource=false); // if true, sets the source buffer to
805  // zero after copying is done.
806 
807  // This base64 encodes the private key data, which
808  // is already encrypted to its passphase as well.
809  //
810  ascKey.SetData(theData);
811 
812  otLog5 << __FUNCTION__
813  << ": Success copying private key into memory.\n";
814  bReturnVal = true;
815  }
816  else {
817  otErr << __FUNCTION__
818  << ": Failed copying private key into memory.\n";
819  }
820  }
821 
822  return bReturnVal;
823 }
824 
825 #endif
826 
827 } // namespace opentxs
OTLOG_IMPORT OTLogStream otLog4
Definition: Timer.hpp:31
static bool ArmorPrivateKey(EVP_PKEY &theKey, OTASCIIArmor &ascKey, Timer &theTimer, const OTPasswordData *pPWData=nullptr, const OTPassword *pImportPassword=nullptr)
EXPORT void start()
Definition: Timer.cpp:41
static bool ArmorPublicKey(EVP_PKEY &theKey, OTASCIIArmor &ascKey)
static EVP_PKEY * CopyPublicKey(EVP_PKEY &theKey, const OTPasswordData *pPWData=nullptr, const OTPassword *pImportPassword=nullptr)
#define OT_ASSERT(x)
Definition: Assert.hpp:150
#define OT_ASSERT_MSG(x, s)
Definition: Assert.hpp:155
EXPORT void SetPayloadSize(uint32_t lNewSize)
Definition: OTPayload.cpp:313
static EVP_PKEY * CopyPrivateKey(EVP_PKEY &theKey, const OTPasswordData *pPWData=nullptr, const OTPassword *pImportPassword=nullptr)
EXPORT const char * getPassword() const
Definition: OTPassword.cpp:547
EXPORT const void * GetPayloadPointer() const
Definition: OTPayload.cpp:318
OTLOG_IMPORT OTLogStream otErr
static EXPORT OT_OPENSSL_CALLBACK * GetPasswordCallback()
EXPORT bool SetData(const OTData &theData, bool bLineBreaks=true)
static EXPORT void * safe_memcpy(void *dest, uint32_t dsize, const void *src, uint32_t ssize, bool zeroSource=false)
Definition: OTPassword.cpp:357
#define OT_KEY_TIMER
virtual EXPORT void Release()
Definition: OTString.cpp:765
uint32_t GetSize() const
Definition: OTData.hpp:174
OTLOG_IMPORT OTLogStream otLog5