Пример #1
0
void * thread_handler(void * arg)
{
	int ret;
	int i = (int)arg;
	char * str = (char *)malloc(100);
	if (!str) {
		exit(1);
	}

	sprintf(str, "This is %d\n", i);
	ret = pthread_setspecific(key, (void *)str);
	if (ret) {
		fprintf(stderr, "setspecific:%s\n",
			strerror(ret));
		return NULL;	
	}

	str_display();

	return NULL;
}
Пример #2
0
// Called by the password callback function.
// The password callback uses this to get the password for any individual Nym.
// This will also generate the master password, if one does not already exist.
//
bool OTCachedKey::GetMasterPassword(_SharedPtr<OTCachedKey> & mySharedPtr,
                                    OTPassword            & theOutput,
									const char            * szDisplay,
									bool bVerifyTwice/*=false*/)
{
	tthread::lock_guard<tthread::mutex> lock(m_Mutex); // Multiple threads can't get inside here at the same time.

	std::string str_display(NULL != szDisplay ? szDisplay : "(Display string was blank.)");

	const char * szFunc = "OTCachedKey::GetMasterPassword";

	//  OT_ASSERT(NULL != m_pSymmetricKey); // (This had better be set already.) // Took this out because calling Generate inside here now.
	// ----------------------------------------
	//
	if (NULL != m_pMasterPassword)
	{
		OTLog::vOutput(2, "%s: Master password was available. (Returning it now.)\n", szFunc);

		theOutput = *m_pMasterPassword;
		return true;
	}
	// --------------------------------------------
	OTLog::vOutput(2, "%s: Master password wasn't loaded. Instantiating...\n", szFunc);

	// If m_pMasterPassword is NULL, (which below this point it is) then...
	//
	// Either it hasn't been created yet, in which case we need to instantiate it,
	// OR it expired, in which case m_pMasterPassword is NULL,
	// but m_pThread isn't, and still needs cleaning up before we instantiate another one!
	//
	LowLevelReleaseThread();
	// --------------------------------------------
	m_pMasterPassword = OTCrypto::It()->InstantiateBinarySecret(); // already asserts.
	// --------------------------------------------
	/*
	How does this work?

	When trying to open a normal nym, the password callback realizes we are calling it
	in "NOT master mode", so instead of just collecting the passphrase and giving it
	back to OpenSSL, it calls this function first, which returns the master password
	(so that IT can be given to OpenSSL instead.)

	If the master wasn't already loaded (common) then we call the callback in here ourselves.
	Notice it's recursive! But this time, the callback sees we ARE in master mode, so it doesn't
	call this function again (which would be an infinite loop.) Instead, it collects the password
	as normal, only instead of passing it back to the caller via the buffer, it uses the
	passUserInput by attaching it to thePWData before the call. That way the callback function
	can set passUserInput with whatever it retrieved from the user, and then back in this function
	again we can get the passUserInput and use it to unlock the MASTER passphrase, which we set
	onto theOutput.

	When this function returns true, the callback (0th level of recursion) uses theOutput
	as the "passphrase" for all Nyms, passing it to OpenSSL.

	This way, OpenSSL gets a random key instead of a passphrase, and the passphrase is just used
	for encrypting that random key whenever its timer has run out.

	*/

	bool bReturnVal = false;

	// CALL the callback directly. (To retrieve a passphrase so I can use it in GenerateKey
	// and GetRawKey.)
	//
	//int32_t OT_OPENSSL_CALLBACK (char *buf, int32_t size, int32_t rwflag, void *userdata);
	//
	// For us, it will set passUserInput to the password from the user, and return
	// a simple 1 or 0 (instead of the length.) buf and size can be NULL / 0, and
	// rwflag should be passed in from somewhere.
	//
	// m_pSymmetricKey is the encrypted form of the master key. Therefore we want to hash
	// it, in order to get the ID for lookups on the keychain.
	//
	OTPassword * pDerivedKey = NULL;
	OTCleanup<OTPassword> theDerivedAngel;
	// ---------------------------------
	if (NULL == m_pSymmetricKey)
	{
		m_pSymmetricKey = new OTSymmetricKey;
		OT_ASSERT(NULL != m_pSymmetricKey);
	}
	// --------------------------------------------------
	if (false == m_pSymmetricKey->IsGenerated()) // doesn't already exist.
	{
		OTLog::vOutput(1, "%s: Master key didn't exist. Need to collect a passphrase from the user, "
			"so we can generate a master key...\n ", szFunc);

		bVerifyTwice = true; // we force it, in this case.
	}

	// --------------------------------------------------
	else // If the symmetric key itself ALREADY exists (which it usually will...)
	{    // then we might have also already stashed the derived key on the system
		// keychain. Let's check there first before asking the user to enter his
		// passphrase...
		//

		// -----------------------------------------------------
		const OTIdentifier idCachedKey(*m_pSymmetricKey); // Grab the ID of this symmetric key.
		const OTString     strCachedKeyHash(idCachedKey); // Same thing, in string form.
		//
		// This only happens in here where we KNOW m_pSymmetricKey was already generated.
		//
		//      OTString strCachedKeyHash;
		//      m_pSymmetricKey->GetIdentifier(strCachedKeyHash);
		// -----------------------------------------------------
		pDerivedKey = OTCrypto::It()->InstantiateBinarySecret(); // pDerivedKey is instantiated here to use as output argument below.
		// -----------------------------------------------------
		//
		// *** ATTEMPT to RETRIEVE the *Derived Key* from THE SYSTEM KEYCHAIN ***
		//
		const bool bFoundOnKeyring = this->IsUsingSystemKeyring() &&
			OTKeyring::RetrieveSecret(
			strCachedKeyHash, // HASH OF ENCRYPTED MASTER KEY
			*pDerivedKey,     // (Output) RETRIEVED PASSWORD.
			str_display);     // optional display string.
		// -----------------------------------------------------
		if (bFoundOnKeyring) // We found it -- but does it WORK?
		{
			const bool bCachedKey = m_pSymmetricKey->GetRawKeyFromDerivedKey(*pDerivedKey, *m_pMasterPassword);

			//
			// Note: What IS the secret? We don't want it to be the user's passphrase that he TYPES.
			// We also don't want it to be the eventual (random) key that unlocks the private keys.
			// Rather, we want it to be the intermediary key, generated from the user's passphrase via
			// a key-derivation algorithm, which is then used to unlock the (random) symmetric key that
			// actually unlocks the private keys.
			// This way the symmetric key itself can be kept locked at ALL times, and instead, we have the
			// derived key on the timer, use it to unlock the symmetric key EVERY TIME we use that, and
			// IMMEDIATELY throw it away afterwards, since we can still open it again (until the timeout) by
			// using the derived key.
			// This is slick because the user doesn't directly enter the derived key, and neither is it
			// directly used for unlocking private keys -- so it's preferable to store in RAM than those things.
			//
			//
			// 1. Make sure the above description is actually what we DO do now. (UPDATE: for keyring, yes. For OT internally, no.)
			// 2. Make sure the derived key, as described above, is also what is stored as the SECRET, here! (UPDATE: Yes!)
			//    (i.e. in other processes such as Mac Keychain or Gnome.)
			// 3. Done. Need to add ability for OTIdentifier to hash OTSymmetricKey, so we can use it for strUser above. DONE.
			//
			// UPDATE: the master key cached inside OT (on a timer) is not the derived key, but the master key itself
			// that's used on the private keys. However, the one we're caching in the system keyring IS the derived key,
			// and not the master key. So for example, if an attacker obtained the derived key from the system keyring,
			//

			if (bCachedKey) // It works!
			{
				OTLog::vOutput(1, "%s: Finished calling m_pSymmetricKey->GetRawKeyFromDerivedKey (Success.)\n", szFunc);
				theOutput  = *m_pMasterPassword; // Return it to the caller.
				theDerivedAngel.SetCleanupTarget(*pDerivedKey); // Set our own copy to be destroyed later. It continues below as "NOT NULL".
				bReturnVal = true; // Success.
			}
			else // It didn't unlock with the one we found.
			{
				OTLog::vOutput(0, "%s: Unable to unlock master key using derived key found on system keyring.\n", szFunc);
				delete pDerivedKey;
				pDerivedKey = NULL;  // Below, this function checks pDerivedKey for NULL.
			}
		}
		else    // NOT found on keyring.
		{
			if (this->IsUsingSystemKeyring()) // We WERE using the keying, but we DIDN'T find the derived key.
				OTLog::vOutput(1, "%s: Unable to find derived key on system keyring.\n", szFunc);
			// (Otherwise if we WEREN'T using the system keyring, then of course we didn't find any derived key cached there.)
			delete pDerivedKey;
			pDerivedKey = NULL; // Below, this function checks pDerivedKey for NULL.

		}
	}
	// --------------------------------------------------
	// NOT found on Keyring...
	//
	if (NULL == pDerivedKey) // Master key was not cached in OT, nor was it found in the system keychain.
	{                        // Therefore we HAVE to ask the user for a passphrase and decrypt it ourselves,
		// since we DO have an encrypted version of the key...

		// This time we DEFINITELY force the user input, since we already played our hand.
		// If the master key was still in memory we would have returned already, above.
		// Then we tried to find it on the keyring and we couldn't find it, so now we have
		// to actually ask the user to enter it.
		//

		std::string default_password(OT_DEFAULT_PASSWORD); // default password
		OTPassword passwordDefault; passwordDefault.zeroMemory();
        passwordDefault.setPassword(default_password.c_str(), static_cast<int32_t>(default_password.length()));

		OTPassword passUserInput;  passUserInput.zeroMemory(); // text mode.
		OTPasswordData  thePWData(str_display.c_str(), &passUserInput, mySharedPtr); // these pointers are only passed in the case where it's for a master key.
//      OTLog::vOutput(2, "*********Begin OTCachedKey::GetMasterPassword: Calling souped-up password cb...\n * *  * *  * *  * *  * ");
		// -----------------------------------------------------------------------


		// It's possible this is the first time this is happening, and the master key
		// hasn't even been generated yet. In which case, we generate it here...
		//
		bool bGenerated = m_pSymmetricKey->IsGenerated();

		if (!bGenerated) // This Symmetric Key hasn't been generated before....
		{

			if (!OTAsymmetricKey::GetPasswordCallback()(NULL, 0, bVerifyTwice ? 1 : 0, static_cast<void *>(&thePWData)))
			{
				OTLog::vError("%s: Failed to get password from user!", __FUNCTION__);
				return false;
			}


			// If the length of the user supplied password is less than 4 characters int64_t, we are going to use the default password!
			bool bUsingDefaultPassword = false;
			{
				if (4 > std::string(passUserInput.getPassword()).length())
				{
					OTLog::vOutput(0, "\n Password entered was less than 4 characters int64_t! This is NOT secure!!\n"
						"... Assuming password is for testing only... setting to default password: %s \n",
						OT_DEFAULT_PASSWORD);
					bUsingDefaultPassword = true;
				}
			}

//          OTLog::vOutput(0, "%s: Calling m_pSymmetricKey->GenerateKey()...\n", szFunc);

			bGenerated = m_pSymmetricKey->GenerateKey(bUsingDefaultPassword ? passwordDefault : passUserInput, &pDerivedKey); // derived key is optional here.
			//
			// Note: since I passed &pDerivedKey in the above call, then **I** am responsible to
			// check it for NULL, and delete it if there's something there!
			//
			if (NULL != pDerivedKey)
				theDerivedAngel.SetCleanupTarget(*pDerivedKey);
			else
				OTLog::vError("%s: FYI: Derived key is still NULL after calling OTSymmetricKey::GenerateKey.\n");

//          OTLog::vOutput(0, "%s: Finished calling m_pSymmetricKey->GenerateKey()...\n", szFunc);
		}
		else // m_pSymmetricKey->IsGenerated() == true. (Symmetric Key is already generated.)
		{
			// -------------------------------------------------------------------------------------------------
			// Generate derived key from passphrase.
			//
			// We generate the derived key here so that GetRawKeyFromPassphrase() call (below)
			// works with it being passed in. (Because the above call to GenerateKey also grabs
			// a copy of the derived key and passes it in below to the same GetRawKeyFromPassphrase.)
			//
			// So WHY are we keeping a copy of the derived key through these calls? Otherwise they
			// would all individually generate it, which is a waste of resources. Also, we want to have
			// our grubby hands on the derived key at the end so we can add it to the system keyring
			// (below), and we'd just end up having to derive it AGAIN in order to do so.
			//
			if (m_pSymmetricKey->HasHashCheck())
			{
				pDerivedKey = m_pSymmetricKey->CalculateDerivedKeyFromPassphrase(passwordDefault); // asserts already.

				if (NULL == pDerivedKey)
				{
					OTLog::vOutput(0, "\n\n%s: Please enter your password.\n\n", __FUNCTION__);

					for ( ;; )  // bad passphase (as the calculate key returned NULL)
					{
						if (!OTAsymmetricKey::GetPasswordCallback()(NULL, 0, false, static_cast<void *>(&thePWData)))
						{
							OTLog::vError("\n\n%s: Failed to get password from user!\n\n", __FUNCTION__);
							return false;
						}
						pDerivedKey = m_pSymmetricKey->CalculateDerivedKeyFromPassphrase(passUserInput); // asserts already.
						if (NULL != pDerivedKey) break; // success

						OTLog::vOutput(0, "\n\n%s: Wrong Password, Please Try Again.\n\n", __FUNCTION__);
					}
				}
			}
			else
			{
				OTLog::vOutput(0,"\n Please enter your current password twice, (not a new password!!) \n");

				if (!OTAsymmetricKey::GetPasswordCallback()(NULL, 0, true, static_cast<void *>(&thePWData)))
				{
					OTLog::vError("%s: Failed to get password from user!", __FUNCTION__);
					return false;
				}

				pDerivedKey = m_pSymmetricKey->CalculateNewDerivedKeyFromPassphrase(passUserInput); // asserts already.
				OT_ASSERT(NULL != pDerivedKey);
			}
			theDerivedAngel.SetCleanupTarget(*pDerivedKey);

			OTLog::vOutput(1, "%s: FYI, symmetric key was already generated. "
				"Proceeding to try and use it...\n", szFunc);

			// bGenerated is true, if we're even in this block in the first place.
			// (No need to set it twice.)
		}

		// -------------------------------------------------------------------------------------------------
		// Below this point, pDerivedKey could still be null.
		// (And we only clean it up later if we created it.)
		// Also, bGenerated could still be false. (Like if it wasn't
		// generated, then generation itself failed, then it's still false.)
		//
		// Also, even if it was already generated, or if it wasn't but then successfully did,
		//
		// -----------------------------------------------------

		if (bGenerated) // If SymmetricKey (*this) is already generated.
		{
			OTLog::vOutput(2, "%s: Calling m_pSymmetricKey->GetRawKeyFromPassphrase()...\n", szFunc);

			// Once we have the user's password, then we use it to GetKey from the OTSymmetricKey (which
			// is encrypted) and that retrieves the cleartext master password which we set here and also
			// return a copy of.
			//
			// Note: if pDerivedKey was derived above already, which it should have been, then it will
			// be not-NULL, and will be used here, and will be used subsequently for adding to the system
			// keychain. Otherwise, it will be NULL, and GetRawKeyFromPassphrase will thus just derive its
			// own copy of the derived key internally. It will still work, but then back up here, it will
			// NOT be added to the system keyring, since it's still NULL back up here.
			// (FYI.)
			//
			const bool bCachedKey = m_pSymmetricKey->GetRawKeyFromPassphrase(passUserInput,
				*m_pMasterPassword,
				pDerivedKey);
			if (bCachedKey)
			{
				OTLog::vOutput(2, "%s: Finished calling m_pSymmetricKey->GetRawKeyFromPassphrase (Success.)\n", szFunc);
				theOutput  = *m_pMasterPassword; // Success!
				// ------------------------------
				// Store the derived key to the system keyring.
				//
				if (this->IsUsingSystemKeyring() && (NULL != pDerivedKey))
				{
					const std::string str_display(NULL != szDisplay ? szDisplay : "(Display string was blank.)");
					// -----------------------------------------------------
					const OTIdentifier idCachedKey(*m_pSymmetricKey);
					const OTString     strCachedKeyHash(idCachedKey); // Same thing, in string form.
					// -----------------------------------------------------
					//                      const bool bStored =
					OTKeyring::StoreSecret(strCachedKeyHash, // HASH OF ENCRYPTED MASTER KEY
						*pDerivedKey,     // (Input) Derived Key BEING STORED.
						str_display);     // optional display string.
				}
				else
					OTLog::vOutput(1, "%s: Strange: Problem with either: this->IsUsingSystemKeyring (%s) "
					"or: (NULL != pDerivedKey) (%s)\n", szFunc, this->IsUsingSystemKeyring() ? "true" : "false",
					(NULL != pDerivedKey) ? "true" : "false");

				bReturnVal = true;
			}
			else
				OTLog::vOutput(0, "%s: m_pSymmetricKey->GetRawKeyFromPassphrase() failed.\n", szFunc);
		} // bGenerated
		else
			OTLog::vError("%s: bGenerated is still false, even after trying to generate it, yadda yadda yadda.\n", szFunc);

	} // NULL == pDerivedKey
	// -------------------------------------------

	if (bReturnVal) // Start the thread!
	{
//      OTLog::vOutput(4, "%s: starting up new thread, so we can expire the master key from RAM.\n", szFunc);


// ************************************************************************
#if defined(OT_CRYPTO_USING_OPENSSL)

// -------------------------------------------------
#if defined(OPENSSL_THREADS)
		// thread support enabled

		OTLog::vOutput(2, "%s: Starting thread for Master Key...\n", szFunc);

        _SharedPtr<OTCachedKey> * pthreadSharedPtr = new _SharedPtr<OTCachedKey>(mySharedPtr); // TODO: memory leak.

		m_pThread = new tthread::thread(OTCachedKey::ThreadTimeout, static_cast<void *>(pthreadSharedPtr));

#else
		// no thread support

		OTLog::vError("%s: WARNING: OpenSSL was NOT compiled with thread support. "
			"(Master Key will not expire.)\n", szFunc);

#endif
// -------------------------------------------------

// ************************************************************************
#elif defined(OT_CRYPTO_USING_GPG)

        OTLog::vError("%s: WARNING: OT was compiled for GPG, which is not yet supported. "
                      "(Master Key will not expire.)\n", szFunc);

// ************************************************************************
#else  // OT_CRYPTO_USING_ ... nothing?

        OTLog::vError("%s: WARNING: OT wasn't compiled for any crypto library "
                      "(such as OpenSSL or GPG). Which is very strange, and I doubt "
                      "things will even work, with it in this condition. (Plus, Master "
                      "Key will not expire.)\n", szFunc);

// -------------------------------------------------
#endif     //if defined(OT_CRYPTO_USING_OPENSSL),  elif defined(OT_CRYPTO_USING_GPG),  else,  endif.
// ************************************************************************


		// -------------------------------------------------

	}
	else if (m_nTimeoutSeconds != (-1))
	{
		if (NULL != m_pMasterPassword)
        {
            OTPassword * pMasterPassword = m_pMasterPassword;

            m_pMasterPassword = NULL;

			delete pMasterPassword; pMasterPassword = NULL;
        }
	}
	// Since we have set the cleartext master password, We also have to fire up the thread
	// so it can timeout and be destroyed. In the meantime, it'll be stored in an OTPassword
	// which has these security precautions:
	/*
	1. Zeros memory in a secure and cross-platform way, in its destructor.
	2. OT_Init() uses setrlimit to prevent core dumps.
	3. Uses VirtualLock and mlock to reduce/prevent swapping RAM to hard drive.
	4. (SOON) will use VirtualProtect on Windows (standard API for protected memory)
	5. (SOON) and similarly have option in config file for ssh-agent, gpg-agent, etc.
	6. Even without those things,the master password is stored in an encrypted form after it times out.
	7. While decrypted (while timer is going) it's still got the above security mechanisms,
	plus options for standard protected-memory APIs are made available wherever possible.
	8. The actual passphrase the user types is not stored in memory, except just int64_t enough to
	use it to derive another key, used to unlock the actual key (for a temporary period of time.)
	9. Meanwhile the actual key is stored in encrypted form on disk, and the derived key isn't stored anywhere.
	10. Ultimately external hardware, and smart cards, are the way to go. But OT should still do the best possible.
	*/

	return bReturnVal;
}