Open-Transactions  0.93.0-ge03d287
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
OTAsymmetricKeyOpenSSL.cpp
Go to the documentation of this file.
1 /************************************************************
2  *
3  * OTAsymmetricKeyOpenSSL.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)
145 #include "crypto/OpenSSL_BIO.hpp"
146 #endif
147 
148 namespace opentxs
149 {
150 
151 #if defined(OT_CRYPTO_USING_OPENSSL)
152 
154  : OTAsymmetricKey()
156 {
157  dp->backlink = this;
158 
159  dp->m_pX509 = nullptr;
160  dp->m_pKey = nullptr;
161 }
162 
164 {
166 
168 
169  if (nullptr !=
170  dp->m_pX509) // Todo: figure out if I should put a copy of this
171  // into ReleaseKeyLowLevel_Hook as we are with
172  // m_pKey.
173  X509_free(dp->m_pX509); // FYI: the reason it's not there already is
174  // because the original need was for wiping
175  // m_pKey when a private key timed out.
176  dp->m_pX509 = nullptr; // ReleaseKeyLowLevel is used all over
177  // OTAsymmetricKey.cpp for the purpose of wiping that
178  // private key. The same need didn't exist with the x509
179  // so it was never coded that way. As long as it's
180  // cleaned up here in the destructor, seems good enough?
181  // YOU MIGHT ASK... Why is m_pKey cleaned up here in the destructor, and
182  // ALSO in ReleaseKeyLowLevel_Hook ?
183  // The answer is because if we call ReleaseKeyLowLevel_Hook from
184  // OTAsymmetricKey's destructor (down that chain)
185  // then it will fail at runtime, since it is a pure virtual method. Since we
186  // still want the ABILITY to use ReleaseKeyLowLevel_Hook
187  // (For cases where the destructor is not being used) and since we still
188  // want it to ALSO work when destructing, the
189  // easiest/quickest/simplest way is to put the code into
190  // OTAsymmetricKey_OpenSSL's destructor directly, as well
191  // as OTAsymmetricKey_OpenSSL's override of ReleaseKeyLowLevel_Hook. Then go
192  // into OTAsymmetricKey's destructor and
193  // make sure the full call path through there doesn't involve any virtual
194  // functions.
195 }
196 
197 // virtual
199 {
200  Release_AsymmetricKey_OpenSSL(); // My own cleanup is performed here.
201 
202  // Next give the base class a chance to do the same...
203  ot_super::Release(); // since I've overridden the base class, I call it
204  // now...
205 }
206 
208 {
209  // Release any dynamically allocated members here. (Normally.)
210 }
211 
213 {
214  // Release the instantiated OpenSSL key (unsafe to store in this form.)
215  //
216  if (nullptr != dp->m_pKey) EVP_PKEY_free(dp->m_pKey);
217  dp->m_pKey = nullptr;
218 }
219 
220 // Load the private key from a .pem formatted cert string
221 //
223  const OTString& strCert, // Contains certificate and private key.
224  bool bEscaped, // "escaped" means pre-pended with "- " as in: -
225  // -----BEGIN CER....
226  const OTString* pstrReason, // This reason is what displays on the
227  // passphrase dialog.
228  const OTPassword* pImportPassword) // Used when importing an exported
229  // Nym into a wallet.
230 {
231  Release();
232 
233  m_bIsPublicKey = false;
234  m_bIsPrivateKey = true;
235 
236  if (!strCert.Exists()) {
237  otErr << __FUNCTION__ << ": Error: Cert input is nonexistent!\n";
238  return false;
239  }
240 
241  // Read private key
242  //
243  OTString strWithBookends;
244  otLog3 << __FUNCTION__ << ": FYI, Reading private key from x509 stored in "
245  "bookended string...\n";
246 
247  if (bEscaped) {
248  OTASCIIArmor theArmor;
249 
250  // I only have a CERTIFICATE 'if' here, not a PUBLIC KEY 'if'.
251  // That's because this function is called
252  // "LoadPublicKeyFrom*CERT*String"
253  // If you want to load a public key from a public key string, then call
254  // the
255  // other function that does that.
256  if (theArmor.LoadFromString(
257  const_cast<OTString&>(strCert),
258  true, // passing bEscaped in as true explicitly here.
259  "-----BEGIN ENCRYPTED PRIVATE")) // It will start loading from
260  // THIS substring...
261  strWithBookends.Format("-----BEGIN ENCRYPTED PRIVATE "
262  "KEY-----\n%s-----END ENCRYPTED PRIVATE "
263  "KEY-----\n",
264  theArmor.Get());
265  else {
266  otErr
267  << __FUNCTION__
268  << ": Error extracting ASCII-Armored text from Cert String.\n";
269  return false;
270  }
271  }
272  else // It's not escaped already, so no need to remove the escaping, in
273  // this case.
274  {
275  strWithBookends = strCert;
276  }
277 
278  // Create a new memory buffer on the OpenSSL side.
279  //
280  // OpenSSL_BIO bio = BIO_new(BIO_s_mem());
281  // OpenSSL_BIO bio =
282  // BIO_new_mem_buf(static_cast<void*>(const_cast<char*>(strWithBookends.Get())),
283  // strWithBookends.GetLength() /*+1*/);
284  OpenSSL_BIO bio = BIO_new_mem_buf(
285  static_cast<void*>(const_cast<char*>(strWithBookends.Get())), -1);
286  OT_ASSERT_MSG(nullptr != bio,
287  "OTAsymmetricKey_OpenSSL::"
288  "LoadPrivateKeyFromCertString: Assert: nullptr != "
289  "bio \n");
290 
291  {
292  // TODO security: Need to replace PEM_read_bio_PrivateKey().
293  /*
294  The old PrivateKey write routines are retained for compatibility.
295  New applications should write private keys using the
296  PEM_write_bio_PKCS8PrivateKey() or PEM_write_PKCS8PrivateKey()
297  routines because they are more secure (they use an iteration count of
298  2048 whereas the traditional routines use a
299  count of 1) unless compatibility with older versions of OpenSSL is
300  important.
301  NOTE: The PrivateKey read routines can be used in all applications
302  because they handle all formats transparently.
303  */
304  OTPasswordData thePWData(
305  (nullptr == pstrReason)
306  ? (nullptr == pImportPassword
307  ? "Enter the master passphrase. "
308  "(LoadPrivateKeyFromCertString)"
309  : "Enter the passphrase for this exported nym.")
310  : pstrReason->Get());
311 
312  EVP_PKEY* pkey = nullptr;
313 
314  if (!pImportPassword) // pImportPassword is nullptr? Do it normally then
315  {
316  pkey = PEM_read_bio_PrivateKey(
317  bio, nullptr, OTAsymmetricKey::GetPasswordCallback(),
318  &thePWData);
319  }
320  else // Otherwise, use pImportPassword instead of the normal
321  // OTCachedKey system.
322  {
323  pkey = PEM_read_bio_PrivateKey(
324  bio, nullptr, 0,
325  const_cast<void*>(reinterpret_cast<const void*>(
326  pImportPassword->getPassword())));
327  }
328 
329  if (nullptr == pkey) {
330  otErr << __FUNCTION__ << ": (pImportPassword size: "
331  << (nullptr == pImportPassword
332  ? 0
333  : pImportPassword->getPasswordSize())
334  << ") Error reading private key from string.\n\n";
335  return false;
336  }
337  else {
338  // Note: no need to start m_timer here since SetKeyAsCopyOf already
339  // calls ArmorPrivateKey, which does that.
340  //
341  dp->SetKeyAsCopyOf(*pkey, true, &thePWData,
342  pImportPassword); // bIsPrivateKey=false by
343  // default, but true
344  // here.
345  EVP_PKEY_free(pkey);
346  pkey = nullptr;
347  otLog3 << __FUNCTION__
348  << ": Successfully loaded private key, FYI.\n";
349  return true;
350  }
351  }
352 }
353 
354 // Load the public key from a x509 stored in a bookended string
355 // If the string is escaped (- ----BEGIN is prefixed with dash space: "- ") then
356 // make
357 // sure to pass true. (Keys that appear inside contracts are escaped after
358 // signing.)
359 // This function will remove the escapes.
360 //
362  const OTString& strCert, bool bEscaped, const OTString* pstrReason,
363  const OTPassword* pImportPassword)
364 {
365  Release();
366 
367  m_bIsPublicKey = true;
368  m_bIsPrivateKey = false;
369 
370  bool bReturnValue = false;
371 
372  // Read public key
373  otLog3 << __FUNCTION__
374  << ": Reading public key from x509 stored in bookended string...\n";
375 
376  OTString strWithBookends;
377 
378  if (bEscaped) {
379  OTASCIIArmor theArmor;
380 
381  // I only have a CERTIFICATE 'if' here, not a PUBLIC KEY 'if'.
382  // That's because this function is called
383  // "LoadPublicKeyFrom*CERT*String"
384  // If you want to load a public key from a public key string, then call
385  // the
386  // other function that does that.
387  //
388  if (theArmor.LoadFromString(
389  const_cast<OTString&>(strCert),
390  true, // passing bEscaped in as true explicitly here.
391  "-----BEGIN CERTIFICATE")) // Overrides "-----BEGIN"
392  strWithBookends.Format(
393  "-----BEGIN CERTIFICATE-----\n%s-----END CERTIFICATE-----\n",
394  theArmor.Get());
395  else {
396  otErr
397  << __FUNCTION__
398  << ": Error extracting ASCII-Armored text from Cert String.\n";
399  return false;
400  }
401  }
402  else // It's not escaped already, so no need to remove the escaping, in
403  // this case.
404  {
405  strWithBookends = strCert;
406  }
407 
408  // took out the +1 on the length since null terminater only
409  // needed in string form, not binary form as OpenSSL treats it.
410  //
411  OpenSSL_BIO keyBio = BIO_new_mem_buf(
412  static_cast<void*>(const_cast<char*>(strWithBookends.Get())), -1);
413  // OpenSSL_BIO keyBio =
414  // BIO_new_mem_buf(static_cast<void*>(const_cast<char*>(strWithBookends.Get())),
415  // strWithBookends.GetLength() /*+1*/);
416  // OpenSSL_BIO keyBio = BIO_new_mem_buf((void*)strCert.Get(),
417  // strCert.GetLength() /*+1*/);
418  OT_ASSERT(nullptr != keyBio);
419 
420  OTPasswordData thePWData(
421  nullptr == pImportPassword ? "Enter your wallet master passphrase. "
422  "(LoadPublicKeyFromCertString)"
423  :
424  // pImportPassword exists:
425  (nullptr == pstrReason
426  ? "Enter the passphrase for your exported Nym. "
427  "(LoadPublicKeyFromCertString)"
428  : pstrReason->Get()));
429 
430  X509* x509 = nullptr;
431 
432  if (nullptr == pImportPassword)
433  x509 = PEM_read_bio_X509(keyBio, nullptr,
435  &thePWData);
436  else
437  x509 = PEM_read_bio_X509(
438  keyBio, nullptr, 0, const_cast<void*>(reinterpret_cast<const void*>(
439  pImportPassword->getPassword())));
440 
441  // TODO security: At some point need to switch to using X509_AUX functions.
442  // The current x509 functions will read a trust certificate but discard the
443  // trust structure.
444  // The X509_AUX functions will process the trust structure.
445  // UPDATE: Possibly the trust structure sucks. Need to consult experts. (CA
446  // system is a farce.)
447  //
448  if (nullptr != x509) {
449  EVP_PKEY* pkey = X509_get_pubkey(x509);
450 
451  if (pkey == nullptr) {
452  otErr << __FUNCTION__ << ": Error reading public key from x509.\n";
453  }
454  else {
455  dp->SetKeyAsCopyOf(*pkey, false, // bIsPrivateKey=false. PUBLIC KEY.
456  &thePWData, pImportPassword); // pImportPassword
457  // is sometimes
458  // nullptr here.
459 
460  EVP_PKEY_free(pkey);
461  pkey = nullptr;
462  otLog3 << __FUNCTION__ << ": Successfully extracted a public key "
463  "from an x509 certificate.\n";
464  bReturnValue = true;
465  }
466  }
467  else {
468  otErr << __FUNCTION__ << ": Error reading x509 out of certificate.\n";
469  }
470 
471  // For now we save the x509, and free it in the destructor, since we may
472  // need it in the meantime, to convert the Nym to the new master key and
473  // re-save. (Don't want to have to load the x509 AGAIN just to re-save
474  // it...)
475  //
476  if (bReturnValue) {
477  dp->SetX509(x509);
478  }
479  else {
480  if (nullptr != x509) X509_free(x509);
481  x509 = nullptr;
482  dp->SetX509(nullptr);
483  }
484 
485  return bReturnValue;
486 }
487 
488 // Used when importing / exporting Nym to/from the wallet.
489 //
491  const OTPassword& theExportPassword, bool bImporting) const
492 {
493  OT_ASSERT(m_p_ascKey != nullptr);
494  OT_ASSERT(IsPrivate());
495 
496  bool bReturnVal = false;
497 
498  const EVP_CIPHER* pCipher =
499  EVP_des_ede3_cbc(); // todo should this algorithm be hardcoded?
500 
501  OTPayload theData; // after base64-decoding the ascii-armored string, the
502  // (encrypted) binary will be stored here.
503 
504  // This line base64 decodes the ascii-armored string into binary object
505  // theData...
506  //
507  m_p_ascKey->GetData(theData); // theData now contains binary data, the
508  // encrypted private key itself, no longer in
509  // text-armoring.
510 
511  if (theData.GetSize() > 0) {
512  EVP_PKEY* pClearKey = nullptr;
513 
514  // Copy the encrypted binary private key data into an OpenSSL memory
515  // BIO...
516  //
517  OpenSSL_BIO keyBio = BIO_new_mem_buf(
518  static_cast<char*>(const_cast<void*>(theData.GetPayloadPointer())),
519  theData.GetSize()); // theData will zeroMemory upon destruction.
520  OT_ASSERT_MSG(nullptr != keyBio,
521  "OTAsymmetricKey_OpenSSL::"
522  "ReEncryptPrivateKey: Assert: nullptr != "
523  "keyBio \n");
524 
525  // Here's thePWData we use if we didn't have anything else:
526  //
527  OTPasswordData thePWData(
528  bImporting ? "(Importing) Enter the exported Nym's passphrase."
529  : "(Exporting) Enter your wallet's master passphrase.");
530 
531  // If we're importing, that means we're currently stored as an EXPORTED
532  // NYM (i.e. with its own
533  // password, independent of the wallet.) So we use theExportedPassword.
534  //
535  if (bImporting) {
536  // otOut << "RE-ENCRYPT PRIVATE KEY -- READING using
537  // special EXPORT password: %s\n", theExportPassword.getPassword());
538  pClearKey = PEM_read_bio_PrivateKey(
539  keyBio, nullptr, 0,
540  const_cast<void*>(reinterpret_cast<const void*>(
541  theExportPassword.getPassword())));
542  }
543 
544  // Else if we're exporting, that means we're currently stored in the
545  // wallet (i.e. using the wallet's
546  // cached master key.) So we use the normal password callback.
547  //
548  else {
549  // otOut << "RE-ENCRYPT PRIVATE KEY -- READING using WALLET
550  // password.\n";
551  pClearKey = PEM_read_bio_PrivateKey(
552  keyBio, nullptr, OTAsymmetricKey::GetPasswordCallback(),
553  &thePWData);
554  }
555 
556  if (nullptr != pClearKey) {
557  // otLog4 << "%s: Success reading private key from
558  // ASCII-armored data:\n\n%s\n\n",
559  // __FUNCTION__, m_p_ascKey->Get());
560  otLog4
561  << __FUNCTION__
562  << ": Success reading private key from ASCII-armored data.\n";
563 
564  // Okay, we have loaded up the private key, now let's save it back
565  // to m_p_ascKey
566  // using the new passphrase.
567  //
568  OpenSSL_BIO bmem = BIO_new(BIO_s_mem());
569  OT_ASSERT(nullptr != bmem);
570 
571  // write a private key to that buffer, from pClearKey
572  //
573  int32_t nWriteBio = 0;
574 
575  // If we're importing, that means we just loaded up the (previously)
576  // exported Nym
577  // using theExportedPassphrase, so now we need to save it back again
578  // using the
579  // normal password callback (for importing it to the wallet.)
580  //
581  if (bImporting) {
582  // otOut << "RE-ENCRYPT PRIVATE KEY -- WRITING
583  // using WALLET password.\n";
584  nWriteBio = PEM_write_bio_PrivateKey(
585  bmem, pClearKey, pCipher, nullptr, 0,
587  }
588 
589  // Else if we're exporting, that means we just loaded up the Nym
590  // from the wallet
591  // using the normal password callback, and now we need to save it
592  // back again using
593  // theExportedPassphrase (for exporting it outside of the wallet.)
594  //
595  else {
596  // otOut << "RE-ENCRYPT PRIVATE KEY -- WRITING
597  // using special EXPORT password: %s Size: %d\n",
598  // theExportPassword.getPassword(),
599  // theExportPassword.getPasswordSize());
600  nWriteBio = PEM_write_bio_PrivateKey(
601  bmem, pClearKey, pCipher, nullptr, 0, 0,
602  const_cast<void*>(reinterpret_cast<const void*>(
603  theExportPassword.getPassword())));
604  }
605 
606  EVP_PKEY_free(pClearKey);
607 
608  if (0 == nWriteBio)
609  otErr << __FUNCTION__
610  << ": Failed writing EVP_PKEY to memory buffer.\n";
611  else {
612 
613  otLog5 << __FUNCTION__
614  << ": Success writing EVP_PKEY to memory buffer.\n";
615 
616  OTPayload theNewData;
617  char* pChar = nullptr;
618 
619  // After the below call, pChar will point to the memory buffer
620  // where the private key supposedly is,
621  // and lSize will contain the size of that memory.
622  //
623  int64_t lSize = BIO_get_mem_data(bmem, &pChar);
624  uint32_t nSize = static_cast<uint32_t>(lSize);
625 
626  if (nSize > 0) {
627  // Set the buffer size in our own memory.
628  theNewData.SetPayloadSize(nSize);
629 
630  // void * pv =
632  (static_cast<char*>(const_cast<void*>(
633  theNewData.GetPayloadPointer()))), // destination
634  theNewData.GetSize(), // size of destination buffer.
635  pChar, // source
636  nSize); // length of source.
637  // bool bZeroSource=false); // if true, sets the source
638  // buffer to zero after copying is done.
639 
640  // This base64 encodes the private key data, which
641  // is already encrypted to its passphase as well.
642  //
643  m_p_ascKey->SetData(theNewData); // <======== Success!
644  bReturnVal = true;
645  }
646  else
647  otErr << __FUNCTION__
648  << ": Failed copying private key into memory.\n";
649  } // (nWriteBio != 0)
650 
651  }
652  else
653  otErr << __FUNCTION__ << ": Failed loading actual private key from "
654  "BIO containing ASCII-armored data:\n\n"
655  << m_p_ascKey->Get() << "\n\n";
656  }
657  else
658  otErr << __FUNCTION__
659  << ": Failed reading private key from ASCII-armored data.\n\n";
660  // otErr << "%s: Failed reading private key from ASCII-armored
661  // data:\n\n%s\n\n",
662  // __FUNCTION__, m_p_ascKey->Get());
663 
664  return bReturnVal;
665 }
666 
667 // virtual
669  OTString& strOutput, const OTString* pstrReason,
670  const OTPassword* pImportPassword) const
671 {
672  X509* x509 = dp->GetX509();
673 
674  if (nullptr == x509) {
675  otErr << __FUNCTION__
676  << ": Error: Unexpected nullptr x509. (Returning false.)\n";
677  return false;
678  }
679 
680  OpenSSL_BIO bio_out_x509 = BIO_new(BIO_s_mem()); // we now have auto-cleanup
681 
682  PEM_write_bio_X509(bio_out_x509, x509);
683 
684  bool bSuccess = false;
685 
686  uint8_t buffer_x509[8192] = ""; // todo hardcoded
687  OTString strx509;
688  int32_t len = 0;
689 
690  // todo hardcoded 4080 (see array above.)
691  //
692  if (0 < (len = BIO_read(bio_out_x509, buffer_x509, 8100))) // returns number
693  // of bytes
694  // successfully
695  // read.
696  {
697  buffer_x509[len] = '\0';
698  strx509.Set((const char*)buffer_x509);
699 
700  EVP_PKEY* pPublicKey = X509_get_pubkey(x509);
701  if (nullptr != pPublicKey) {
702  OTPasswordData thePWData(
703  nullptr == pstrReason
704  ? "OTAsymmetricKey_OpenSSL::SaveCertToString"
705  : pstrReason->Get());
706 
707  dp->SetKeyAsCopyOf(*pPublicKey, false, &thePWData, pImportPassword);
708  EVP_PKEY_free(pPublicKey);
709  pPublicKey = nullptr;
710  }
711 
712  bSuccess = true;
713  }
714 
715  if (bSuccess) strOutput = strx509;
716 
717  return bSuccess;
718 }
719 
720 // virtual
722  OTString& strOutput, const OTString* pstrReason,
723  const OTPassword* pImportPassword) const
724 {
725  const EVP_CIPHER* pCipher =
726  EVP_des_ede3_cbc(); // todo security (revisit this mode...)
727 
728  if (!IsPrivate()) {
729  otErr << __FUNCTION__ << ": Error: !IsPrivate() (This function should "
730  "only be called on a private key.)\n";
731  return false;
732  }
733 
734  EVP_PKEY* pPrivateKey = dp->GetKeyLowLevel();
735  if (nullptr == pPrivateKey) {
736  otErr
737  << __FUNCTION__
738  << ": Error: Unexpected nullptr pPrivateKey. (Returning false.)\n";
739  return false;
740  }
741 
742  OpenSSL_BIO bio_out_pri = BIO_new(BIO_s_mem());
743  bio_out_pri.setFreeOnly(); // only BIO_free(), not BIO_free_all();
744 
745  OTPasswordData thePWData((nullptr != pstrReason)
746  ? pstrReason->Get()
747  : "OTAsymmetricKey_OpenSSL::"
748  "SavePrivateKeyToString is calling "
749  "PEM_write_bio_PrivateKey...");
750 
751  if (nullptr == pImportPassword)
752  PEM_write_bio_PrivateKey(bio_out_pri, pPrivateKey, pCipher, nullptr, 0,
754  &thePWData);
755  else
756  PEM_write_bio_PrivateKey(
757  bio_out_pri, pPrivateKey, pCipher, nullptr, 0, 0,
758  const_cast<void*>(
759  reinterpret_cast<const void*>(pImportPassword->getPassword())));
760 
761  bool bSuccess = false;
762 
763  int32_t len = 0;
764  uint8_t buffer_pri[4096] = ""; // todo hardcoded
765 
766  // todo hardcoded 4080 (see array above.)
767  if (0 < (len = BIO_read(bio_out_pri, buffer_pri, 4080))) // returns number
768  // of bytes
769  // successfully
770  // read.
771  {
772  buffer_pri[len] = '\0';
773  strOutput.Set((const char*)buffer_pri); // so I can write this string to
774  // file in a sec... todo cast
775  bSuccess = true;
776  }
777  else
778  otErr << __FUNCTION__ << ": Error : key length is not 1 or more!";
779 
780  return bSuccess;
781 }
782 
783 /*
784  * An implementation of convertion from PGP public key format to OpenSSL
785  *equivalent
786  * Support of RSA, DSA and Elgamal public keys
787  *
788  * Copyright (c) 2010 Mounir IDRASSI <[email protected]>. All rights
789  *reserved.
790  *
791  * This program is distributed in the hope that it will be useful,
792  * but WITHOUT ANY WARRANTY; without even the implied warranty of
793  *MERCHANTABILITY
794  * or FITNESS FOR A PARTICULAR PURPOSE.
795  *
796  */
797 
798 typedef struct
799 {
800  BIGNUM* p;
801  BIGNUM* g;
802  BIGNUM* pub_key;
803  BIGNUM* priv_key;
804 } ELGAMAL;
805 
806 typedef struct
807 {
808  RSA* pRsa;
809  DSA* pDsa;
811 } PgpKeys;
812 
813 PgpKeys ExportRsaKey(uint8_t* pbData, int32_t dataLength)
814 {
815  PgpKeys pgpKeys;
816  int32_t i;
817 
818  OT_ASSERT(nullptr != pbData);
819 
820  memset(&pgpKeys, 0, sizeof(pgpKeys));
821  for (i = 0; i < dataLength;) {
822  int32_t packetLength;
823  uint8_t packetTag = pbData[i++];
824  if ((packetTag & 0x80) == 0) break;
825  if ((packetTag & 0x40)) {
826  packetTag &= 0x3F;
827  packetLength = pbData[i++];
828  if ((packetLength > 191) && (packetLength < 224))
829  packetLength = ((packetLength - 192) << 8) + pbData[i++];
830  else if ((packetLength > 223) && (packetLength < 255))
831  packetLength = (1 << (packetLength & 0x1f));
832  else if (packetLength == 255) {
833  packetLength = (pbData[i] << 24) + (pbData[i + 1] << 16) +
834  (pbData[i + 2] << 8) + pbData[i + 3];
835  i += 4;
836  }
837  }
838  else {
839  packetLength = packetTag & 3;
840  packetTag = (packetTag >> 2) & 15;
841  if (packetLength == 0)
842  packetLength = pbData[i++];
843  else if (packetLength == 1) {
844  packetLength = (pbData[i] << 8) + pbData[i + 1];
845  i += 2;
846  }
847  else if (packetLength == 2) {
848  packetLength = (pbData[i] << 24) + (pbData[i + 1] << 16) +
849  (pbData[i + 2] << 8) + pbData[i + 3];
850  i += 4;
851  }
852  else
853  packetLength = dataLength - 1;
854  }
855 
856  if ((packetTag == 6) || (packetTag == 14)) // a public key
857  {
858  int32_t algorithm;
859  int32_t version = pbData[i++];
860 
861  // skip time over 4 bytes
862  i += 4;
863 
864  if ((version == 2) || (version == 3)) {
865  // skip validity over 2 bytes
866  i += 2;
867  }
868 
869  algorithm = pbData[i++];
870 
871  if ((algorithm == 1) || (algorithm == 2) ||
872  (algorithm == 3)) // an RSA key
873  {
874  int32_t modulusLength, exponentLength;
875  RSA* pKey = RSA_new();
876 
877  // Get the modulus
878  modulusLength = ((pbData[i] * 256 + pbData[i + 1] + 7) / 8);
879  pKey->n = BN_bin2bn(pbData + i + 2, modulusLength, nullptr);
880  i += modulusLength + 2;
881 
882  // Get the exponent
883  exponentLength = (pbData[i] * 256 + pbData[i + 1] + 7) / 8;
884  pKey->e = BN_bin2bn(pbData + i + 2, exponentLength, nullptr);
885  i += exponentLength + 2;
886 
887  pgpKeys.pRsa = pKey;
888 
889  continue;
890  }
891  else if (algorithm == 17) // a DSA key
892  {
893  int32_t pLen, qLen, gLen, yLen;
894  DSA* pKey = DSA_new();
895 
896  // Get Prime P
897  pLen = ((pbData[i] * 256 + pbData[i + 1] + 7) / 8);
898  pKey->p = BN_bin2bn(pbData + i + 2, pLen, nullptr);
899  i += pLen + 2;
900 
901  // Get Prime Q
902  qLen = ((pbData[i] * 256 + pbData[i + 1] + 7) / 8);
903  pKey->q = BN_bin2bn(pbData + i + 2, qLen, nullptr);
904  i += qLen + 2;
905 
906  // Get Prime G
907  gLen = ((pbData[i] * 256 + pbData[i + 1] + 7) / 8);
908  pKey->g = BN_bin2bn(pbData + i + 2, gLen, nullptr);
909  i += gLen + 2;
910 
911  // Get Prime Y
912  yLen = ((pbData[i] * 256 + pbData[i + 1] + 7) / 8);
913  pKey->pub_key = BN_bin2bn(pbData + i + 2, yLen, nullptr);
914  i += yLen + 2;
915 
916  pgpKeys.pDsa = pKey;
917 
918  continue;
919  }
920  else if ((algorithm == 16) || (algorithm == 20)) // Elgamal key
921  // (not supported
922  // by OpenSSL
923  {
924  int32_t pLen, gLen, yLen;
925  ELGAMAL* pKey = (ELGAMAL*)malloc(sizeof(ELGAMAL));
926  if (nullptr == pKey) {
927  otErr << __FUNCTION__ << ": Error: pKey is nullptr!";
928  OT_FAIL;
929  }
930 
931  // Get Prime P
932  pLen = ((pbData[i] * 256 + pbData[i + 1] + 7) / 8);
933 
934  pKey->p = BN_bin2bn(pbData + i + 2, pLen, nullptr);
935 
936  i += pLen + 2;
937 
938  // Get Prime G
939  gLen = ((pbData[i] * 256 + pbData[i + 1] + 7) / 8);
940  pKey->g = BN_bin2bn(pbData + i + 2, gLen, nullptr);
941  i += gLen + 2;
942 
943  // Get Prime Y
944  yLen = ((pbData[i] * 256 + pbData[i + 1] + 7) / 8);
945  pKey->pub_key = BN_bin2bn(pbData + i + 2, yLen, nullptr);
946  i += yLen + 2;
947 
948  pgpKeys.pElgamal = pKey;
949 
950  continue;
951  }
952  else {
953  i -= 6;
954  if (version == 2 || version == 3) i -= 2;
955  }
956  }
957 
958  i += packetLength;
959  }
960 
961  return pgpKeys;
962 }
963 
964 // Decodes a PGP public key from ASCII armor into an actual key pointer
965 // and sets that as the keypointer on this object.
966 // This function expects the bookends to be GONE already
967 // It just wants the base64 encoded data which is why we have ascii-armor
968 // object coming in instead of a string.
970  const OTASCIIArmor& strKey)
971 {
972  Release();
973 
974  m_bIsPublicKey = true;
975  m_bIsPrivateKey = false;
976 
977  /*
978  * An implementation of convertion from PGP public key format to OpenSSL
979  *equivalent
980  * Support of RSA, DSA and Elgamal public keys
981  *
982  * Copyright (c) 2010 Mounir IDRASSI <[email protected]>. All rights
983  *reserved.
984  *
985  * This program is distributed in the hope that it will be useful,
986  * but WITHOUT ANY WARRANTY; without even the implied warranty of
987  *MERCHANTABILITY
988  * or FITNESS FOR A PARTICULAR PURPOSE.
989  *
990  */
991  int32_t len;
992  uint8_t buffer[520]; // Making it a bit bigger than 512 for safety reasons.
993  BUF_MEM* bptr;
994  PgpKeys pgpKeys;
995 
996  OpenSSL_BIO b64 = BIO_new(BIO_f_base64());
997  OpenSSL_BIO bio = BIO_new_mem_buf((void*)strKey.Get(), -1);
998  OpenSSL_BIO bio_out = BIO_new(BIO_s_mem());
999  OpenSSL_BIO bioJoin = BIO_push(b64, bio);
1000  b64.release();
1001  bio.release();
1002 
1003  while ((len = BIO_read(bioJoin, buffer, 512)) > 0)
1004  BIO_write(bio_out, buffer, len);
1005 
1006  BIO_get_mem_ptr(bio_out, &bptr);
1007  bio_out.setFreeOnly();
1008 
1009  pgpKeys =
1010  ExportRsaKey((uint8_t*)bptr->data, static_cast<int32_t>(bptr->length));
1011 
1012  if (!pgpKeys.pRsa) {
1013  otLog5 << "\nNo RSA public key found.\n\n";
1014  }
1015  else {
1016  char* szModulusHex = BN_bn2hex(pgpKeys.pRsa->n);
1017  char* szExponentHex = BN_bn2hex(pgpKeys.pRsa->e);
1018  otLog5 << "RSA public key found : \n Modulus ("
1019  << BN_num_bits(pgpKeys.pRsa->n) << " bits)\n";
1020  otLog5 << " Exponent : 0x" << szExponentHex << "\n\n";
1021  otLog5 << "RSA public key found : \nModulus ("
1022  << BN_num_bits(pgpKeys.pRsa->n) << " bits) : 0x" << szModulusHex
1023  << "\n";
1024  otLog5 << "Exponent : 0x" << szExponentHex << "\n\n";
1025 
1026  CRYPTO_free(szModulusHex);
1027  CRYPTO_free(szExponentHex);
1028  }
1029 
1030  if (!pgpKeys.pDsa) {
1031  otLog5 << "No DSA public key found.\n\n";
1032  }
1033  else {
1034  char* szPHex = BN_bn2hex(pgpKeys.pDsa->p);
1035  char* szQHex = BN_bn2hex(pgpKeys.pDsa->q);
1036  char* szGHex = BN_bn2hex(pgpKeys.pDsa->g);
1037  char* szYHex = BN_bn2hex(pgpKeys.pDsa->pub_key);
1038  otLog5 << "DSA public key found : \n p ("
1039  << BN_num_bits(pgpKeys.pDsa->p) << " bits)\n";
1040  otLog5 << " q (" << BN_num_bits(pgpKeys.pDsa->q) << " bits)\n";
1041  otLog5 << " g (" << BN_num_bits(pgpKeys.pDsa->g) << " bits)\n";
1042  otLog5 << "public key (" << BN_num_bits(pgpKeys.pDsa->pub_key)
1043  << " bits)\n\n";
1044  otLog5 << "DSA public key found : \np (" << BN_num_bits(pgpKeys.pDsa->p)
1045  << " bits) : 0x" << szPHex << "\n";
1046  otLog5 << "q (" << BN_num_bits(pgpKeys.pDsa->q) << " bits) : 0x"
1047  << szQHex << "\n";
1048  otLog5 << "g (" << BN_num_bits(pgpKeys.pDsa->g) << " bits) : 0x"
1049  << szGHex << "\n";
1050  otLog5 << "public key (" << BN_num_bits(pgpKeys.pDsa->pub_key)
1051  << " bits) : 0x" << szYHex << "\n\n";
1052 
1053  CRYPTO_free(szPHex);
1054  CRYPTO_free(szQHex);
1055  CRYPTO_free(szGHex);
1056  CRYPTO_free(szYHex);
1057  }
1058 
1059  if (!pgpKeys.pElgamal) {
1060  otLog5 << "No Elgamal public key found.\n\n";
1061  }
1062  else {
1063  char* szPHex = BN_bn2hex(pgpKeys.pElgamal->p);
1064  char* szGHex = BN_bn2hex(pgpKeys.pElgamal->g);
1065  char* szYHex = BN_bn2hex(pgpKeys.pElgamal->pub_key);
1066  otLog5 << "Elgamal public key found : \n p ("
1067  << BN_num_bits(pgpKeys.pElgamal->p) << " bits) : 0x" << szPHex
1068  << "\n";
1069  otLog5 << " g (" << BN_num_bits(pgpKeys.pElgamal->g) << " bits) : 0x"
1070  << szGHex << "\n";
1071  otLog5 << " public key (" << BN_num_bits(pgpKeys.pElgamal->pub_key)
1072  << " bits) : 0x" << szYHex << "\n\n";
1073 
1074  CRYPTO_free(szPHex);
1075  CRYPTO_free(szGHex);
1076  CRYPTO_free(szYHex);
1077  }
1078 
1079  bool bReturnValue = false;
1080  EVP_PKEY* pkey = EVP_PKEY_new();
1081  OT_ASSERT(nullptr != pkey);
1082 
1083  if (pgpKeys.pRsa) {
1084  if (EVP_PKEY_assign_RSA(pkey, pgpKeys.pRsa)) {
1085  bReturnValue = true;
1086  // todo: make sure the lack of RSA_free here is not a memory leak.
1087  otLog4 << "Successfully extracted RSA public key from PGP public "
1088  "key block.\n";
1089  }
1090  else {
1091  RSA_free(pgpKeys.pRsa);
1092  otOut << "Extracted RSA public key from PGP public key block, but "
1093  "unable to convert to EVP_PKEY.\n";
1094  }
1095 
1096  pgpKeys.pRsa = nullptr;
1097  }
1098  else if (pgpKeys.pDsa) {
1099  if (EVP_PKEY_assign_DSA(pkey, pgpKeys.pDsa)) {
1100  bReturnValue = true;
1101  // todo: make sure the lack of DSA_free here is not a memory leak.
1102  otLog4 << "Successfully extracted DSA public key from PGP public "
1103  "key block.\n";
1104  }
1105  else {
1106  DSA_free(pgpKeys.pDsa);
1107  otOut << "Extracted DSA public key from PGP public key block, but "
1108  "unable to convert to EVP_PKEY.\n";
1109  }
1110 
1111  pgpKeys.pDsa = nullptr;
1112  }
1113  else if (pgpKeys.pElgamal) {
1114  otOut << "Extracted ElGamal Key from PGP public key block, but "
1115  "currently do not support it (sorry))\n";
1116  //
1117  // int32_t EVP_PKEY_assign_EC_KEY(EVP_PKEY* pkey, EC_KEY* key); // Here
1118  // is the assign function for El Gamal
1119  // (assuming that "EC" stands for eliptical curve... kind of hard to
1120  // tell with the OpenSSL docs...)
1121  //
1122  free(pgpKeys.pElgamal);
1123  pgpKeys.pElgamal = nullptr;
1124  }
1125 
1126  // FT: Adding some fixes here...
1127  //
1128  if (bReturnValue) {
1129  dp->SetKeyAsCopyOf(*pkey, false); // bIsPrivateKey=false. PUBLIC KEY.
1130  EVP_PKEY_free(pkey); // We have our own copy already. It's set nullptr
1131  // just below...
1132  }
1133  else if (nullptr !=
1134  pkey) // we failed, but pkey is NOT null (need to free it.)
1135  {
1136  EVP_PKEY_free(pkey); // Set nullptr just below...
1137  }
1138 
1139  pkey = nullptr; // This is either stored on m_pKey, or deleted. I'm setting
1140  // pointer to nullptr here just for completeness.
1141 
1142  return bReturnValue;
1143 }
1144 
1145 #elif defined(OT_CRYPTO_USING_GPG)
1146 
1147 #else
1148 
1149 #endif
1150 } // namespace opentxs
OTLOG_IMPORT OTLogStream otLog4
virtual bool SaveCertToString(OTString &strOutput, const OTString *pstrReason=nullptr, const OTPassword *pImportPassword=nullptr) const
virtual bool SavePrivateKeyToString(OTString &strOutput, const OTString *pstrReason=nullptr, const OTPassword *pImportPassword=nullptr) const
virtual bool LoadPublicKeyFromPGPKey(const OTASCIIArmor &strKey)
virtual bool ReEncryptPrivateKey(const OTPassword &theExportPassword, bool bImporting) const
virtual bool LoadPublicKeyFromCertString(const OTString &strCert, bool bEscaped=true, const OTString *pstrReason=nullptr, const OTPassword *pImportPassword=nullptr)
OTLOG_IMPORT OTLogStream otOut
OTLOG_IMPORT OTLogStream otLog3
virtual bool LoadPrivateKeyFromCertString(const OTString &strCert, bool bEscaped=true, const OTString *pstrReason=nullptr, const OTPassword *pImportPassword=nullptr)
PgpKeys ExportRsaKey(uint8_t *pbData, int32_t dataLength)
EXPORT bool Exists() const
Definition: OTString.cpp:1035
static EXPORT bool LoadFromString(OTASCIIArmor &ascArmor, const OTString &strInput, std::string str_bookend="-----BEGIN")
EXPORT void Format(const char *fmt,...)
Definition: OTString.cpp:1319
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
Definition: OTString.cpp:1055
#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
EXPORT uint32_t getPasswordSize() const
Definition: OTPassword.cpp:613
EXPORT bool GetData(OTData &theData, bool bLineBreaks=true) const
EXPORT void setFreeOnly()
Definition: OTCrypto.cpp:5077
#define OT_FAIL
Definition: Assert.hpp:139
EXPORT const char * getPassword() const
Definition: OTPassword.cpp:547
EXPORT void release()
Definition: OTCrypto.cpp:5072
EXPORT const char * Get() const
Definition: OTString.cpp:1045
EXPORT const void * GetPayloadPointer() const
Definition: OTPayload.cpp:318
OTLOG_IMPORT OTLogStream otErr
OTAsymmetricKey_OpenSSLPrivdp * dp
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
uint32_t GetSize() const
Definition: OTData.hpp:174
OTLOG_IMPORT OTLogStream otLog5