bool InboundRTMPProtocol::ValidateClientScheme(IOBuffer &inputBuffer, uint8_t scheme) {
	uint8_t *pBuffer = GETIBPOINTER(inputBuffer);

	uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme);

	uint8_t *pTempBuffer = new uint8_t[1536 - 32];
	memcpy(pTempBuffer, pBuffer, clientDigestOffset);
	memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32,
			1536 - clientDigestOffset - 32);

	uint8_t *pTempHash = new uint8_t[512];
	HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);

	bool result = true;
	for (uint32_t i = 0; i < 32; i++) {
		if (pBuffer[clientDigestOffset + i] != pTempHash[i]) {
			result = false;
			break;
		}
	}

	delete[] pTempBuffer;
	delete[] pTempHash;

	return result;
}
Exemple #2
0
bool ValidateClientScheme(uint8_t *pBuffer, uint8_t scheme){
  uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme);
  uint8_t pTempBuffer[1536 - 32];
  memcpy(pTempBuffer, pBuffer, clientDigestOffset);
  memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32,
         1536 - clientDigestOffset - 32);
  char pTempHash[32];
  Secure::hmac_sha256bin((char *)pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);
  bool result = (memcmp(pBuffer + clientDigestOffset, pTempHash, 32) == 0);
  MEDIUM_MSG("Client scheme validation %hhi %s", scheme, result ? "success" : "failed");
  return result;
}
bool OutboundRTMPProtocol::VerifyServer(IOBuffer & inputBuffer) {
	uint8_t *pBuffer = GETIBPOINTER(inputBuffer) + 1;

	uint32_t serverDigestOffset = GetDigestOffset(pBuffer, _usedScheme);
	DEBUG_HANDSHAKE("CLIENT: Validate: 1. serverDigestOffset: %" PRIu32 "; _usedScheme: %" PRIu8,
			serverDigestOffset, _usedScheme);

	uint8_t *pTempBuffer = new uint8_t[1536 - 32];
	memcpy(pTempBuffer, pBuffer, serverDigestOffset);
	memcpy(pTempBuffer + serverDigestOffset, pBuffer + serverDigestOffset + 32,
			1536 - serverDigestOffset - 32);

	uint8_t * pDigest = new uint8_t[512];
	HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pDigest);
	DEBUG_HANDSHAKE("CLIENT: Validate: 2. computed serverDigest %s", STR(hex(pDigest, 32)));
	DEBUG_HANDSHAKE("CLIENT: Validate: 3.    found serverDigest %s", STR(hex(pBuffer + serverDigestOffset, 32)));

	int result = memcmp(pDigest, pBuffer + serverDigestOffset, 32);

	delete[] pTempBuffer;
	delete[] pDigest;

	if (result != 0) {
		FATAL("Server not verified");
		return false;
	}

	pBuffer = pBuffer + 1536;

	uint8_t * pChallange = new uint8_t[512];
	HMACsha256(_pClientDigest, 32, genuineFMSKey, 68, pChallange);

	pDigest = new uint8_t[512];
	HMACsha256(pBuffer, 1536 - 32, pChallange, 32, pDigest);

	DEBUG_HANDSHAKE("CLIENT: Validate: 4. computed serverChallange: %s", STR(hex(pDigest, 32)));
	DEBUG_HANDSHAKE("CLIENT: Validate: 5.    found serverChallange: %s", STR(hex(pBuffer + 1536 - 32, 32)));
	result = memcmp(pDigest, pBuffer + 1536 - 32, 32);

	delete[] pChallange;
	delete[] pDigest;

	if (result != 0) {
		FATAL("Server not verified");
		return false;
	}

	return true;
}
bool OutboundRTMPProtocol::PerformHandshakeStage2(IOBuffer &inputBuffer,
		bool encrypted) {
	if (encrypted || _pProtocolHandler->ValidateHandshake()) {
		if (!VerifyServer(inputBuffer)) {
			FATAL("Unable to verify server");
			return false;
		}
	}

	uint8_t *pInputBuffer = GETIBPOINTER(inputBuffer) + 1;

	uint32_t serverDHOffset = GetDHOffset(pInputBuffer, _usedScheme);
	if (_pDHWrapper == NULL) {
		FATAL("dh wrapper not initialized");
		return false;
	}

	DEBUG_HANDSHAKE("CLIENT: 1. serverDHOffset: %" PRIu32 "; _usedScheme: %" PRIu8 "; serverPublicKey: %s",
			serverDHOffset,
			_usedScheme,
			STR(hex(pInputBuffer + serverDHOffset, 128)));
	if (!_pDHWrapper->CreateSharedKey(pInputBuffer + serverDHOffset, 128)) {
		FATAL("Unable to create shared key");
		return false;
	}

	uint8_t secretKey[128];
	if (!_pDHWrapper->CopySharedKey(secretKey, sizeof (secretKey))) {
		FATAL("Unable to compute shared");
		return false;
	}
	DEBUG_HANDSHAKE("CLIENT: 2. secretKey: %s", STR(hex(secretKey, 128)));

	if (encrypted) {
		_pKeyIn = new RC4_KEY;
		_pKeyOut = new RC4_KEY;

		InitRC4Encryption(
				secretKey,
				(uint8_t*) & pInputBuffer[serverDHOffset],
				_pClientPublicKey,
				_pKeyIn,
				_pKeyOut);

		uint8_t data[1536];
		RC4(_pKeyIn, 1536, data, data);
		RC4(_pKeyOut, 1536, data, data);
	}

	delete _pDHWrapper;
	_pDHWrapper = NULL;

	uint32_t serverDigestOffset = GetDigestOffset(pInputBuffer, _usedScheme);
	DEBUG_HANDSHAKE("CLIENT: 3. serverDigestOffset: %" PRIu32 "; _usedScheme: %" PRIu8, serverDigestOffset, _usedScheme);

	if (_pOutputBuffer == NULL) {
		_pOutputBuffer = new uint8_t[1536];
	} else {
		delete[] _pOutputBuffer;
		_pOutputBuffer = new uint8_t[1536];
	}

	for (uint32_t i = 0; i < 1536; i++) {
		_pOutputBuffer[i] = rand() % 256;
	}

	uint8_t * pChallangeKey = new uint8_t[512];
	HMACsha256(pInputBuffer + serverDigestOffset, 32, genuineFPKey, 62, pChallangeKey);

	uint8_t * pDigest = new uint8_t[512];
	HMACsha256(_pOutputBuffer, 1536 - 32, pChallangeKey, 32, pDigest);

	memcpy(_pOutputBuffer + 1536 - 32, pDigest, 32);
	DEBUG_HANDSHAKE("CLIENT: 4. clientChallange: %s", STR(hex(pDigest, 32)));

	delete[] pChallangeKey;
	delete[] pDigest;

	_outputBuffer.ReadFromBuffer(_pOutputBuffer, 1536);

	delete[] _pOutputBuffer;
	_pOutputBuffer = NULL;

	_rtmpState = RTMP_STATE_DONE;

	return true;
}
bool OutboundRTMPProtocol::PerformHandshakeStage1(bool encrypted) {
	_outputBuffer.ReadFromByte(encrypted ? 6 : 3);

	if (_pOutputBuffer == NULL) {
		_pOutputBuffer = new uint8_t[1536];
	} else {
		delete[] _pOutputBuffer;
		_pOutputBuffer = new uint8_t[1536];
	}

	for (uint32_t i = 0; i < 1536; i++) {
		_pOutputBuffer[i] = rand() % 256;
	}

	EHTONLP(_pOutputBuffer, 0);

	_pOutputBuffer[4] = 9;
	_pOutputBuffer[5] = 0;
	_pOutputBuffer[6] = 124;
	_pOutputBuffer[7] = 2;

	uint32_t clientDHOffset = GetDHOffset(_pOutputBuffer, _usedScheme);

	_pDHWrapper = new DHWrapper(1024);
	if (!_pDHWrapper->Initialize()) {
		FATAL("Unable to initialize DH wrapper");
		return false;
	}

	if (!_pDHWrapper->CopyPublicKey(_pOutputBuffer + clientDHOffset, 128)) {
		FATAL("Couldn't write public key!");
		return false;
	}
	DEBUG_HANDSHAKE("CLIENT: 1. clientDHOffset: %" PRIu32 "; _usedScheme: %" PRIu8 "; clientPublicKey: %s",
			clientDHOffset,
			_usedScheme,
			STR(hex(_pOutputBuffer + clientDHOffset, 128)));
	_pClientPublicKey = new uint8_t[128];
	memcpy(_pClientPublicKey, _pOutputBuffer + clientDHOffset, 128);


	uint32_t clientDigestOffset = GetDigestOffset(_pOutputBuffer, _usedScheme);

	uint8_t *pTempBuffer = new uint8_t[1536 - 32];
	memcpy(pTempBuffer, _pOutputBuffer, clientDigestOffset);
	memcpy(pTempBuffer + clientDigestOffset, _pOutputBuffer + clientDigestOffset + 32,
			1536 - clientDigestOffset - 32);

	uint8_t *pTempHash = new uint8_t[512];
	HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);

	memcpy(_pOutputBuffer + clientDigestOffset, pTempHash, 32);
	DEBUG_HANDSHAKE("CLIENT: 2. clientDigestOffset: %" PRIu32 "; _usedScheme: %" PRIu8 "; clientDigest: %s",
			clientDigestOffset, _usedScheme,
			STR(hex(_pOutputBuffer + clientDigestOffset, 32)));
	_pClientDigest = new uint8_t[32];
	memcpy(_pClientDigest, pTempHash, 32);


	delete[] pTempBuffer;
	delete[] pTempHash;

	_outputBuffer.ReadFromBuffer(_pOutputBuffer, 1536);

	delete[] _pOutputBuffer;
	_pOutputBuffer = NULL;

	if (_pFarProtocol != NULL) {
		if (!_pFarProtocol->EnqueueForOutbound()) {
			FATAL("Unable to signal output data");
			return false;
		}
	}

	_rtmpState = RTMP_STATE_CLIENT_REQUEST_SENT;

	return true;
}
bool InboundRTMPProtocol::PerformComplexHandshake(IOBuffer &buffer, bool encrypted) {
	//get the buffers
	uint8_t *pInputBuffer = GETIBPOINTER(buffer);
	if (_pOutputBuffer == NULL) {
		_pOutputBuffer = new uint8_t[3072];
	} else {
		delete[] _pOutputBuffer;
		_pOutputBuffer = new uint8_t[3072];
	}

	//timestamp
	EHTONLP(_pOutputBuffer, (uint32_t) time(NULL));

	//version
	EHTONLP(_pOutputBuffer + 4, (uint32_t) 0x00000000);

	//generate random data
	for (uint32_t i = 8; i < 3072; i++) {
		_pOutputBuffer[i] = rand() % 256;
	}
	for (uint32_t i = 0; i < 10; i++) {
		uint32_t index = rand() % (3072 - HTTP_HEADERS_SERVER_US_LEN);
		memcpy(_pOutputBuffer + index, HTTP_HEADERS_SERVER_US, HTTP_HEADERS_SERVER_US_LEN);
	}

	//**** FIRST 1536 bytes from server response ****//
	//compute DH key position
	uint32_t serverDHOffset = GetDHOffset(_pOutputBuffer, _handshakeScheme);
	uint32_t clientDHOffset = GetDHOffset(pInputBuffer, _handshakeScheme);

	//generate DH key
	DHWrapper dhWrapper(1024);

	if (!dhWrapper.Initialize()) {
		FATAL("Unable to initialize DH wrapper");
		return false;
	}

	if (!dhWrapper.CreateSharedKey(pInputBuffer + clientDHOffset, 128)) {
		FATAL("Unable to create shared key");
		return false;
	}

	if (!dhWrapper.CopyPublicKey(_pOutputBuffer + serverDHOffset, 128)) {
		FATAL("Couldn't write public key!");
		return false;
	}

	if (encrypted) {
		uint8_t secretKey[128];
		if (!dhWrapper.CopySharedKey(secretKey, sizeof (secretKey))) {
			FATAL("Unable to copy shared key");
			return false;
		}

		_pKeyIn = new RC4_KEY;
		_pKeyOut = new RC4_KEY;
		InitRC4Encryption(
				secretKey,
				(uint8_t*) & pInputBuffer[clientDHOffset],
				(uint8_t*) & _pOutputBuffer[serverDHOffset],
				_pKeyIn,
				_pKeyOut);

		//bring the keys to correct cursor
		uint8_t data[1536];
		RC4(_pKeyIn, 1536, data, data);
		RC4(_pKeyOut, 1536, data, data);
	}

	//generate the digest
	uint32_t serverDigestOffset = GetDigestOffset(_pOutputBuffer, _handshakeScheme);

	uint8_t *pTempBuffer = new uint8_t[1536 - 32];
	memcpy(pTempBuffer, _pOutputBuffer, serverDigestOffset);
	memcpy(pTempBuffer + serverDigestOffset, _pOutputBuffer + serverDigestOffset + 32,
			1536 - serverDigestOffset - 32);

	uint8_t *pTempHash = new uint8_t[512];
	HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pTempHash);

	//put the digest in place
	memcpy(_pOutputBuffer + serverDigestOffset, pTempHash, 32);

	//cleanup
	delete[] pTempBuffer;
	delete[] pTempHash;


	//**** SECOND 1536 bytes from server response ****//
	//Compute the chalange index from the initial client request
	uint32_t keyChallengeIndex = GetDigestOffset(pInputBuffer, _handshakeScheme);

	//compute the key
	pTempHash = new uint8_t[512];
	HMACsha256(pInputBuffer + keyChallengeIndex, //pData
			32, //dataLength
			BaseRTMPProtocol::genuineFMSKey, //key
			68, //keyLength
			pTempHash //pResult
			);

	//generate the hash
	uint8_t *pLastHash = new uint8_t[512];
	HMACsha256(_pOutputBuffer + 1536, //pData
			1536 - 32, //dataLength
			pTempHash, //key
			32, //keyLength
			pLastHash //pResult
			);

	//put the hash where it belongs
	memcpy(_pOutputBuffer + 1536 * 2 - 32, pLastHash, 32);


	//cleanup
	delete[] pTempHash;
	delete[] pLastHash;
	//***** DONE BUILDING THE RESPONSE ***//


	//wire the response
	if (encrypted)
		_outputBuffer.ReadFromByte(6);
	else
		_outputBuffer.ReadFromByte(3);
	_outputBuffer.ReadFromBuffer(_pOutputBuffer, 3072);

	//final cleanup
	delete[] _pOutputBuffer;
	_pOutputBuffer = NULL;
	if (!buffer.IgnoreAll()) {
		FATAL("Unable to ignore input buffer");
		return false;
	}

	//signal outbound data
	if (!EnqueueForOutbound()) {
		FATAL("Unable to signal outbound data");
		return false;
	}

	//move to the next stage in the handshake
	_rtmpState = RTMP_STATE_SERVER_RESPONSE_SENT;

	return true;
}