Exemple #1
0
void initializeSecHandler()
{
	ERR_load_crypto_strings();
	OpenSSL_add_all_algorithms();

	gHandlerMap[BASIC_SECHANDLER] = new LLSecAPIBasicHandler();
	
	
	// Currently, we only have the Basic handler, so we can point the main sechandler
	// pointer to the basic handler.  Later, we'll create a wrapper handler that
	// selects the appropriate sechandler as needed, for instance choosing the
	// mac keyring handler, with fallback to the basic sechandler
	gSecAPIHandler = gHandlerMap[BASIC_SECHANDLER];

	// initialize all SecAPIHandlers
	std::string exception_msg;
	std::map<std::string, LLPointer<LLSecAPIHandler> >::const_iterator itr;
	for(itr = gHandlerMap.begin(); itr != gHandlerMap.end(); ++itr)
	{
		LLPointer<LLSecAPIHandler> handler = (*itr).second;
		try 
		{
			handler->init();
		}
		catch (LLProtectedDataException e)
		{
			exception_msg = e.getMessage();
		}
	}
	if (!exception_msg.empty())  // an exception was thrown.
	{
		throw LLProtectedDataException(exception_msg.c_str());
	}

}
void initializeSecHandler()
{
	ERR_load_crypto_strings();
	OpenSSL_add_all_algorithms();

	// <FS:ND If we can, enabled the rdrand engine. It is available as a CPU instruction on newer Intel CPUs
	ENGINE_load_builtin_engines();
	
	ENGINE* engRdRand = ENGINE_by_id("rdrand");
	if( engRdRand )
		ENGINE_set_default(engRdRand, ENGINE_METHOD_RAND);
	
	unsigned long lErr ( ERR_get_error() );
	while( lErr )
	{
		char aError[128];
		ERR_error_string_n( lErr, aError, sizeof( aError ) );
		LL_WARNS() << aError << LL_ENDL;

		lErr = ERR_get_error();
	}
	// </FS:ND>
		
	gHandlerMap[BASIC_SECHANDLER] = new LLSecAPIBasicHandler();
	
	
	// Currently, we only have the Basic handler, so we can point the main sechandler
	// pointer to the basic handler.  Later, we'll create a wrapper handler that
	// selects the appropriate sechandler as needed, for instance choosing the
	// mac keyring handler, with fallback to the basic sechandler
	gSecAPIHandler = gHandlerMap[BASIC_SECHANDLER];

	// initialize all SecAPIHandlers
	std::string exception_msg;
	std::map<std::string, LLPointer<LLSecAPIHandler> >::const_iterator itr;
	for(itr = gHandlerMap.begin(); itr != gHandlerMap.end(); ++itr)
	{
		LLPointer<LLSecAPIHandler> handler = (*itr).second;
		try 
		{
			handler->init();
		}
		catch (LLProtectedDataException e)
		{
			exception_msg = e.getMessage();
		}
	}
	if (!exception_msg.empty())  // an exception was thrown.
	{
		throw LLProtectedDataException(exception_msg.c_str());
	}

}
void LLSecAPIBasicHandler::_writeProtectedData()
{	
	std::ostringstream formatted_data_ostream;
	U8 salt[STORE_SALT_SIZE];
	U8 buffer[BUFFER_READ_SIZE];
	U8 encrypted_buffer[BUFFER_READ_SIZE];

	
	if(mProtectedDataMap.isUndefined())
	{
		LLFile::remove(mProtectedDataFilename);
		return;
	}
	// create a string with the formatted data.
	LLSDSerialize::toXML(mProtectedDataMap, formatted_data_ostream);
	std::istringstream formatted_data_istream(formatted_data_ostream.str());
	// generate the seed
	RAND_bytes(salt, STORE_SALT_SIZE);

	
	// write to a temp file so we don't clobber the initial file if there is
	// an error.
	std::string tmp_filename = mProtectedDataFilename + ".tmp";
	
	llofstream protected_data_stream(tmp_filename.c_str(), 
										llofstream::binary);
	try
	{
		
		EVP_CIPHER_CTX ctx;
		EVP_CIPHER_CTX_init(&ctx);
		EVP_EncryptInit(&ctx, EVP_rc4(), salt, NULL);
		unsigned char unique_id[MAC_ADDRESS_BYTES];
        LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
		LLXORCipher cipher(unique_id, sizeof(unique_id));
		cipher.encrypt(salt, STORE_SALT_SIZE);
		protected_data_stream.write((const char *)salt, STORE_SALT_SIZE);

		while (formatted_data_istream.good())
		{
			formatted_data_istream.read((char *)buffer, BUFFER_READ_SIZE);
			if(formatted_data_istream.gcount() == 0)
			{
				break;
			}
			int encrypted_length;
			EVP_EncryptUpdate(&ctx, encrypted_buffer, &encrypted_length, 
						  buffer, formatted_data_istream.gcount());
			protected_data_stream.write((const char *)encrypted_buffer, encrypted_length);
		}
		
		// no EVP_EncrypteFinal, as this is a stream cipher
		EVP_CIPHER_CTX_cleanup(&ctx);

		protected_data_stream.close();
	}
	catch (...)
	{
		// it's good practice to clean up any secure information on error
		// (even though this file isn't really secure.  Perhaps in the future
		// it may be, however.
		LLFile::remove(tmp_filename);
		throw LLProtectedDataException("Error writing Protected Data Store");
	}

	// move the temporary file to the specified file location.
	if((((LLFile::isfile(mProtectedDataFilename) != 0) && 
		 (LLFile::remove(mProtectedDataFilename) != 0))) || 
	   (LLFile::rename(tmp_filename, mProtectedDataFilename)))
	{
		LLFile::remove(tmp_filename);
		throw LLProtectedDataException("Could not overwrite protected data store");
	}
}
void LLSecAPIBasicHandler::_readProtectedData()
{	
	// attempt to load the file into our map
	LLPointer<LLSDParser> parser = new LLSDXMLParser();
	llifstream protected_data_stream(mProtectedDataFilename.c_str(), 
									llifstream::binary);

	if (!protected_data_stream.fail()) {
		int offset;
		U8 salt[STORE_SALT_SIZE];
		U8 buffer[BUFFER_READ_SIZE];
		U8 decrypted_buffer[BUFFER_READ_SIZE];
		int decrypted_length;	
		unsigned char unique_id[MAC_ADDRESS_BYTES];
        LLMachineID::getUniqueID(unique_id, sizeof(unique_id));
		LLXORCipher cipher(unique_id, sizeof(unique_id));

		// read in the salt and key
		protected_data_stream.read((char *)salt, STORE_SALT_SIZE);
		offset = 0;
		if (protected_data_stream.gcount() < STORE_SALT_SIZE)
		{
			throw LLProtectedDataException("Config file too short.");
		}

		cipher.decrypt(salt, STORE_SALT_SIZE);		

		// totally lame.  As we're not using the OS level protected data, we need to
		// at least obfuscate the data.  We do this by using a salt stored at the head of the file
		// to encrypt the data, therefore obfuscating it from someone using simple existing tools.
		// We do include the MAC address as part of the obfuscation, which would require an
		// attacker to get the MAC address as well as the protected store, which improves things
		// somewhat.  It would be better to use the password, but as this store
		// will be used to store the SL password when the user decides to have SL remember it, 
		// so we can't use that.  OS-dependent store implementations will use the OS password/storage 
		// mechanisms and are considered to be more secure.
		// We've a strong intent to move to OS dependent protected data stores.
		

		// read in the rest of the file.
		EVP_CIPHER_CTX ctx;
		EVP_CIPHER_CTX_init(&ctx);
		EVP_DecryptInit(&ctx, EVP_rc4(), salt, NULL);
		// allocate memory:
		std::string decrypted_data;	
		
		while(protected_data_stream.good()) {
			// read data as a block:
			protected_data_stream.read((char *)buffer, BUFFER_READ_SIZE);
			
			EVP_DecryptUpdate(&ctx, decrypted_buffer, &decrypted_length, 
							  buffer, protected_data_stream.gcount());
			decrypted_data.append((const char *)decrypted_buffer, protected_data_stream.gcount());
		}
		
		// RC4 is a stream cipher, so we don't bother to EVP_DecryptFinal, as there is
		// no block padding.
		EVP_CIPHER_CTX_cleanup(&ctx);
		std::istringstream parse_stream(decrypted_data);
		if (parser->parse(parse_stream, mProtectedDataMap, 
						  LLSDSerialize::SIZE_UNLIMITED) == LLSDParser::PARSE_FAILURE)
		{
			throw LLProtectedDataException("Config file cannot be decrypted.");
		}
	}
}