- Timestamp:
- 08/10/10 17:24:19 (18 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/sources/thelib/src/protocols/rtmp/inboundrtmpprotocol.cpp
r2 r56 1 1 /* 2 * Copyright (c) 2010,3 * Gavriloaie Eugen-Andrei (shiretu@gmail.com)4 * 5 * This file is part of crtmpserver.6 * crtmpserver is free software: you can redistribute it and/or modify7 * it under the terms of the GNU General Public License as published by8 * the Free Software Foundation, either version 3 of the License, or9 * (at your option) any later version.10 * 11 * crtmpserver is distributed in the hope that it will be useful,12 * but WITHOUT ANY WARRANTY; without even the implied warranty of13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14 * GNU General Public License for more details.15 * 16 * You should have received a copy of the GNU General Public License17 * along with crtmpserver. If not, see <http://www.gnu.org/licenses/>.18 */2 * Copyright (c) 2010, 3 * Gavriloaie Eugen-Andrei (shiretu@gmail.com) 4 * 5 * This file is part of crtmpserver. 6 * crtmpserver is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * crtmpserver is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with crtmpserver. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 19 20 20 #ifdef HAS_PROTOCOL_RTMP 21 21 #include "protocols/rtmp/inboundrtmpprotocol.h" 22 #include "buffering/iobuffer.h"23 22 #include "protocols/rtmp/rtmpeprotocol.h" 24 23 #include "protocols/rtmp/basertmpappprotocolhandler.h" 25 #include "utils/crypto.h"26 24 27 25 InboundRTMPProtocol::InboundRTMPProtocol() 28 26 : BaseRTMPProtocol(PT_INBOUND_RTMP) { 29 _pKeyIn = NULL;30 _pKeyOut = NULL;31 _pOutputBuffer = NULL;32 _currentFPVersion = 0;33 _validationScheme = 0;27 _pKeyIn = NULL; 28 _pKeyOut = NULL; 29 _pOutputBuffer = NULL; 30 _currentFPVersion = 0; 31 _validationScheme = 0; 34 32 } 35 33 36 34 InboundRTMPProtocol::~InboundRTMPProtocol() { 37 if (_pKeyIn != NULL) {38 delete _pKeyIn;39 _pKeyIn = NULL;40 }41 42 if (_pKeyOut != NULL) {43 delete _pKeyOut;44 _pKeyOut = NULL;45 }46 47 if (_pOutputBuffer != NULL) {48 delete[] _pOutputBuffer;49 _pOutputBuffer = NULL;50 }35 if (_pKeyIn != NULL) { 36 delete _pKeyIn; 37 _pKeyIn = NULL; 38 } 39 40 if (_pKeyOut != NULL) { 41 delete _pKeyOut; 42 _pKeyOut = NULL; 43 } 44 45 if (_pOutputBuffer != NULL) { 46 delete[] _pOutputBuffer; 47 _pOutputBuffer = NULL; 48 } 51 49 } 52 50 53 51 bool InboundRTMPProtocol::PerformHandshake(IOBuffer &buffer) { 54 switch (_rtmpState) {55 case RTMP_STATE_NOT_INITIALIZED:56 {57 if (GETAVAILABLEBYTESCOUNT(buffer) < 1537) {58 //FINEST("Not enough data");59 return true;60 }61 uint8_t handshakeType = GETIBPOINTER(buffer)[0];62 if (!buffer.Ignore(1)) {63 FATAL("Unable to ignore one byte");64 return false;65 }66 67 _currentFPVersion = ntohl(*((uint32_t *) (GETIBPOINTER(buffer) + 4))); //----MARKED-LONG---68 //FINEST("Flash player: %s", STR(_currentFlashPlayerVersion));69 70 switch (handshakeType) {71 case 3: //plain72 {73 return PerformHandshake(buffer, false);74 }75 case 6: //encrypted76 {77 return PerformHandshake(buffer, true);78 }79 default:80 {81 FATAL("Handshake type not implemented: %d", handshakeType);82 return false;83 }84 }85 }86 case RTMP_STATE_SERVER_RESPONSE_SENT:87 {88 //FINEST("I: Player request 2:\n%s", STR(*pInputBuffer));89 if (GETAVAILABLEBYTESCOUNT(buffer) < 1536) {90 return true;91 } else {92 //ignore the client's last handshake part93 if (!buffer.Ignore(1536)) {94 FATAL("Unable to ignore inbound data");95 return false;96 }97 _handshakeCompleted = true;98 _rtmpState = RTMP_STATE_DONE;99 100 if (_pKeyIn != NULL && _pKeyOut != NULL) {101 //insert the RTMPE protocol in the current protocol stack102 BaseProtocol *pFarProtocol = GetFarProtocol();103 RTMPEProtocol *pRTMPE = new RTMPEProtocol(_pKeyIn, _pKeyOut);104 ResetFarProtocol();105 pFarProtocol->SetNearProtocol(pRTMPE);106 pRTMPE->SetNearProtocol(this);107 FINEST("New protocol chain: %s", STR(*pFarProtocol));108 109 //decrypt the leftovers110 RC4(_pKeyIn, GETAVAILABLEBYTESCOUNT(buffer),111 GETIBPOINTER(buffer),112 GETIBPOINTER(buffer));113 }114 115 return true;116 }117 }118 default:119 {120 FATAL("Invalid RTMP state: %d", _rtmpState);121 return false;122 }123 }52 switch (_rtmpState) { 53 case RTMP_STATE_NOT_INITIALIZED: 54 { 55 if (GETAVAILABLEBYTESCOUNT(buffer) < 1537) { 56 //FINEST("Not enough data"); 57 return true; 58 } 59 uint8_t handshakeType = GETIBPOINTER(buffer)[0]; 60 if (!buffer.Ignore(1)) { 61 FATAL("Unable to ignore one byte"); 62 return false; 63 } 64 65 _currentFPVersion = ntohl(*((uint32_t *) (GETIBPOINTER(buffer) + 4))); //----MARKED-LONG--- 66 //FINEST("Flash player: %s", STR(_currentFlashPlayerVersion)); 67 68 switch (handshakeType) { 69 case 3: //plain 70 { 71 return PerformHandshake(buffer, false); 72 } 73 case 6: //encrypted 74 { 75 return PerformHandshake(buffer, true); 76 } 77 default: 78 { 79 FATAL("Handshake type not implemented: %d", handshakeType); 80 return false; 81 } 82 } 83 } 84 case RTMP_STATE_SERVER_RESPONSE_SENT: 85 { 86 //FINEST("I: Player request 2:\n%s", STR(*pInputBuffer)); 87 if (GETAVAILABLEBYTESCOUNT(buffer) < 1536) { 88 return true; 89 } else { 90 //ignore the client's last handshake part 91 if (!buffer.Ignore(1536)) { 92 FATAL("Unable to ignore inbound data"); 93 return false; 94 } 95 _handshakeCompleted = true; 96 _rtmpState = RTMP_STATE_DONE; 97 98 if (_pKeyIn != NULL && _pKeyOut != NULL) { 99 //insert the RTMPE protocol in the current protocol stack 100 BaseProtocol *pFarProtocol = GetFarProtocol(); 101 RTMPEProtocol *pRTMPE = new RTMPEProtocol(_pKeyIn, _pKeyOut); 102 ResetFarProtocol(); 103 pFarProtocol->SetNearProtocol(pRTMPE); 104 pRTMPE->SetNearProtocol(this); 105 FINEST("New protocol chain: %s", STR(*pFarProtocol)); 106 107 //decrypt the leftovers 108 RC4(_pKeyIn, GETAVAILABLEBYTESCOUNT(buffer), 109 GETIBPOINTER(buffer), 110 GETIBPOINTER(buffer)); 111 } 112 113 return true; 114 } 115 } 116 default: 117 { 118 FATAL("Invalid RTMP state: %d", _rtmpState); 119 return false; 120 } 121 } 124 122 } 125 123 126 124 bool InboundRTMPProtocol::ValidateClient(IOBuffer &inputBuffer) { 127 if (_currentFPVersion == 0) {128 WARN("This version of player doesn't support validation");129 return true;130 }131 if (ValidateClientScheme(inputBuffer, 0)) {132 _validationScheme = 0;133 return true;134 }135 if (ValidateClientScheme(inputBuffer, 1)) {136 _validationScheme = 1;137 return true;138 }139 FATAL("Unable to validate client");140 return false;125 if (_currentFPVersion == 0) { 126 WARN("This version of player doesn't support validation"); 127 return true; 128 } 129 if (ValidateClientScheme(inputBuffer, 0)) { 130 _validationScheme = 0; 131 return true; 132 } 133 if (ValidateClientScheme(inputBuffer, 1)) { 134 _validationScheme = 1; 135 return true; 136 } 137 FATAL("Unable to validate client"); 138 return false; 141 139 } 142 140 143 141 bool InboundRTMPProtocol::ValidateClientScheme(IOBuffer &inputBuffer, uint8_t scheme) { 144 uint8_t *pBuffer = GETIBPOINTER(inputBuffer);145 146 uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme);147 148 uint8_t *pTempBuffer = new uint8_t[1536 - 32];149 memcpy(pTempBuffer, pBuffer, clientDigestOffset);150 memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32,151 1536 - clientDigestOffset - 32);152 153 //uint8_t *pTempHash = new uint8_t[mhash_get_hash_pblock(MHASH_SHA256)];154 uint8_t *pTempHash = new uint8_t[512];155 HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash);156 157 bool result = true;158 for (uint32_t i = 0; i < 32; i++) {159 if (pBuffer[clientDigestOffset + i] != pTempHash[i]) {160 result = false;161 break;162 }163 }164 165 delete[] pTempBuffer;166 delete[] pTempHash;167 168 return result;142 uint8_t *pBuffer = GETIBPOINTER(inputBuffer); 143 144 uint32_t clientDigestOffset = GetDigestOffset(pBuffer, scheme); 145 146 uint8_t *pTempBuffer = new uint8_t[1536 - 32]; 147 memcpy(pTempBuffer, pBuffer, clientDigestOffset); 148 memcpy(pTempBuffer + clientDigestOffset, pBuffer + clientDigestOffset + 32, 149 1536 - clientDigestOffset - 32); 150 151 //uint8_t *pTempHash = new uint8_t[mhash_get_hash_pblock(MHASH_SHA256)]; 152 uint8_t *pTempHash = new uint8_t[512]; 153 HMACsha256(pTempBuffer, 1536 - 32, genuineFPKey, 30, pTempHash); 154 155 bool result = true; 156 for (uint32_t i = 0; i < 32; i++) { 157 if (pBuffer[clientDigestOffset + i] != pTempHash[i]) { 158 result = false; 159 break; 160 } 161 } 162 163 delete[] pTempBuffer; 164 delete[] pTempHash; 165 166 return result; 169 167 } 170 168 171 169 bool InboundRTMPProtocol::PerformHandshake(IOBuffer &buffer, bool encrypted) { 172 if (encrypted || _pProtocolHandler->ValidateHandshake()) {173 if (!ValidateClient(buffer)) {174 FATAL("Unable to validate client");175 return false;176 }177 }178 179 //get the buffers180 uint8_t *pInputBuffer = GETIBPOINTER(buffer);181 if (_pOutputBuffer == NULL) {182 _pOutputBuffer = new uint8_t[3072];183 } else {184 delete[] _pOutputBuffer;185 _pOutputBuffer = new uint8_t[3072];186 }187 188 //timestamp189 *(uint32_t *) _pOutputBuffer = 0;190 191 //version192 *(uint32_t *) (_pOutputBuffer + 4) = htonl(0x01020304); //----MARKED-LONG---193 194 //generate random data195 srand((uint32_t) time(NULL));196 for (uint32_t i = 8; i < 3072; i++) {197 _pOutputBuffer[i] = rand() % 256;198 }199 for (uint32_t i = 0; i < 10; i++) {200 uint32_t index = rand() % (3072 - HTTP_HEADERS_SERVER_US_LEN);201 memcpy(_pOutputBuffer + index, HTTP_HEADERS_SERVER_US, HTTP_HEADERS_SERVER_US_LEN);202 }203 204 //**** FIRST 1536 bytes from server response ****//205 //compute DH key position206 uint32_t serverDHOffset = GetDHOffset(_pOutputBuffer, _validationScheme);207 uint32_t clientDHOffset = GetDHOffset(pInputBuffer, _validationScheme);208 //FINEST("serverDHOffset: %u", serverDHOffset);209 210 //generate DH key211 DHWrapper dhWrapper(1024);212 213 if (!dhWrapper.Initialize()) {214 FATAL("Unable to initialize DH wrapper");215 return false;216 }217 218 if (!dhWrapper.CreateSharedKey(pInputBuffer + clientDHOffset, 128)) {219 FATAL("Unable to create shared key");220 return false;221 }222 223 if (!dhWrapper.CopyPublicKey(_pOutputBuffer + serverDHOffset, 128)) {224 FATAL("Couldn't write public key!");225 return false;226 }227 228 if (encrypted) {229 uint8_t secretKey[128];230 if (!dhWrapper.CopySharedKey(secretKey, sizeof (secretKey))) {231 FATAL("Unable to copy shared key");232 return false;233 }234 235 _pKeyIn = new RC4_KEY;236 _pKeyOut = new RC4_KEY;237 InitRC4Encryption(238 secretKey,239 (uint8_t*) & pInputBuffer[clientDHOffset],240 (uint8_t*) & _pOutputBuffer[serverDHOffset],241 _pKeyIn,242 _pKeyOut);243 244 //bring the keys to correct cursor245 uint8_t data[1536];246 RC4(_pKeyIn, 1536, data, data);247 RC4(_pKeyOut, 1536, data, data);248 }249 250 //generate the digest251 uint32_t serverDigestOffset = GetDigestOffset(_pOutputBuffer, _validationScheme);252 //FINEST("serverDigestOffset: %u", serverDigestOffset);253 254 uint8_t *pTempBuffer = new uint8_t[1536 - 32];255 memcpy(pTempBuffer, _pOutputBuffer, serverDigestOffset);256 memcpy(pTempBuffer + serverDigestOffset, _pOutputBuffer + serverDigestOffset + 32,257 1536 - serverDigestOffset - 32);258 259 uint8_t *pTempHash = new uint8_t[512];260 HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pTempHash);261 262 //put the digest in place263 memcpy(_pOutputBuffer + serverDigestOffset, pTempHash, 32);264 265 //cleanup266 delete[] pTempBuffer;267 delete[] pTempHash;268 269 270 //**** SECOND 1536 bytes from server response ****//271 //Compute the chalange index from the initial client request272 uint32_t keyChallengeIndex = GetDigestOffset(pInputBuffer, _validationScheme);273 //FINEST("keyChallengeIndex: %u", keyChallengeIndex);274 275 //compute the key276 pTempHash = new uint8_t[512];277 HMACsha256(pInputBuffer + keyChallengeIndex, //pData278 32, //dataLength279 BaseRTMPProtocol::genuineFMSKey, //key280 68, //keyLength281 pTempHash //pResult282 );283 284 //generate the hash285 uint8_t *pLastHash = new uint8_t[512];286 HMACsha256(_pOutputBuffer + 1536, //pData287 1536 - 32, //dataLength288 pTempHash, //key289 32, //keyLength290 pLastHash //pResult291 );292 293 //put the hash where it belongs294 memcpy(_pOutputBuffer + 1536 * 2 - 32, pLastHash, 32);295 296 297 //cleanup298 delete[] pTempHash;299 delete[] pLastHash;300 //***** DONE BUILDING THE RESPONSE ***//301 302 303 //wire the response304 if (encrypted)305 _outputBuffer.ReadFromByte(6);306 else307 _outputBuffer.ReadFromByte(3);308 _outputBuffer.ReadFromBuffer(_pOutputBuffer, 3072);309 310 //final cleanup311 delete[] _pOutputBuffer;312 _pOutputBuffer = NULL;313 if (!buffer.IgnoreAll()) {314 FATAL("Unable to ignore input buffer");315 return false;316 }317 318 //signal outbound data319 if (!EnqueueForOutbound()) {320 FATAL("Unable to signal outbound data");321 return false;322 }323 324 //move to the next stage in the handshake325 _rtmpState = RTMP_STATE_SERVER_RESPONSE_SENT;326 327 return true;170 if (encrypted || _pProtocolHandler->ValidateHandshake()) { 171 if (!ValidateClient(buffer)) { 172 FATAL("Unable to validate client"); 173 return false; 174 } 175 } 176 177 //get the buffers 178 uint8_t *pInputBuffer = GETIBPOINTER(buffer); 179 if (_pOutputBuffer == NULL) { 180 _pOutputBuffer = new uint8_t[3072]; 181 } else { 182 delete[] _pOutputBuffer; 183 _pOutputBuffer = new uint8_t[3072]; 184 } 185 186 //timestamp 187 *(uint32_t *) _pOutputBuffer = 0; 188 189 //version 190 *(uint32_t *) (_pOutputBuffer + 4) = htonl(0x01020304); //----MARKED-LONG--- 191 192 //generate random data 193 srand((uint32_t) time(NULL)); 194 for (uint32_t i = 8; i < 3072; i++) { 195 _pOutputBuffer[i] = rand() % 256; 196 } 197 for (uint32_t i = 0; i < 10; i++) { 198 uint32_t index = rand() % (3072 - HTTP_HEADERS_SERVER_US_LEN); 199 memcpy(_pOutputBuffer + index, HTTP_HEADERS_SERVER_US, HTTP_HEADERS_SERVER_US_LEN); 200 } 201 202 //**** FIRST 1536 bytes from server response ****// 203 //compute DH key position 204 uint32_t serverDHOffset = GetDHOffset(_pOutputBuffer, _validationScheme); 205 uint32_t clientDHOffset = GetDHOffset(pInputBuffer, _validationScheme); 206 //FINEST("serverDHOffset: %u", serverDHOffset); 207 208 //generate DH key 209 DHWrapper dhWrapper(1024); 210 211 if (!dhWrapper.Initialize()) { 212 FATAL("Unable to initialize DH wrapper"); 213 return false; 214 } 215 216 if (!dhWrapper.CreateSharedKey(pInputBuffer + clientDHOffset, 128)) { 217 FATAL("Unable to create shared key"); 218 return false; 219 } 220 221 if (!dhWrapper.CopyPublicKey(_pOutputBuffer + serverDHOffset, 128)) { 222 FATAL("Couldn't write public key!"); 223 return false; 224 } 225 226 if (encrypted) { 227 uint8_t secretKey[128]; 228 if (!dhWrapper.CopySharedKey(secretKey, sizeof (secretKey))) { 229 FATAL("Unable to copy shared key"); 230 return false; 231 } 232 233 _pKeyIn = new RC4_KEY; 234 _pKeyOut = new RC4_KEY; 235 InitRC4Encryption( 236 secretKey, 237 (uint8_t*) & pInputBuffer[clientDHOffset], 238 (uint8_t*) & _pOutputBuffer[serverDHOffset], 239 _pKeyIn, 240 _pKeyOut); 241 242 //bring the keys to correct cursor 243 uint8_t data[1536]; 244 RC4(_pKeyIn, 1536, data, data); 245 RC4(_pKeyOut, 1536, data, data); 246 } 247 248 //generate the digest 249 uint32_t serverDigestOffset = GetDigestOffset(_pOutputBuffer, _validationScheme); 250 //FINEST("serverDigestOffset: %u", serverDigestOffset); 251 252 uint8_t *pTempBuffer = new uint8_t[1536 - 32]; 253 memcpy(pTempBuffer, _pOutputBuffer, serverDigestOffset); 254 memcpy(pTempBuffer + serverDigestOffset, _pOutputBuffer + serverDigestOffset + 32, 255 1536 - serverDigestOffset - 32); 256 257 uint8_t *pTempHash = new uint8_t[512]; 258 HMACsha256(pTempBuffer, 1536 - 32, genuineFMSKey, 36, pTempHash); 259 260 //put the digest in place 261 memcpy(_pOutputBuffer + serverDigestOffset, pTempHash, 32); 262 263 //cleanup 264 delete[] pTempBuffer; 265 delete[] pTempHash; 266 267 268 //**** SECOND 1536 bytes from server response ****// 269 //Compute the chalange index from the initial client request 270 uint32_t keyChallengeIndex = GetDigestOffset(pInputBuffer, _validationScheme); 271 //FINEST("keyChallengeIndex: %u", keyChallengeIndex); 272 273 //compute the key 274 pTempHash = new uint8_t[512]; 275 HMACsha256(pInputBuffer + keyChallengeIndex, //pData 276 32, //dataLength 277 BaseRTMPProtocol::genuineFMSKey, //key 278 68, //keyLength 279 pTempHash //pResult 280 ); 281 282 //generate the hash 283 uint8_t *pLastHash = new uint8_t[512]; 284 HMACsha256(_pOutputBuffer + 1536, //pData 285 1536 - 32, //dataLength 286 pTempHash, //key 287 32, //keyLength 288 pLastHash //pResult 289 ); 290 291 //put the hash where it belongs 292 memcpy(_pOutputBuffer + 1536 * 2 - 32, pLastHash, 32); 293 294 295 //cleanup 296 delete[] pTempHash; 297 delete[] pLastHash; 298 //***** DONE BUILDING THE RESPONSE ***// 299 300 301 //wire the response 302 if (encrypted) 303 _outputBuffer.ReadFromByte(6); 304 else 305 _outputBuffer.ReadFromByte(3); 306 _outputBuffer.ReadFromBuffer(_pOutputBuffer, 3072); 307 308 //final cleanup 309 delete[] _pOutputBuffer; 310 _pOutputBuffer = NULL; 311 if (!buffer.IgnoreAll()) { 312 FATAL("Unable to ignore input buffer"); 313 return false; 314 } 315 316 //signal outbound data 317 if (!EnqueueForOutbound()) { 318 FATAL("Unable to signal outbound data"); 319 return false; 320 } 321 322 //move to the next stage in the handshake 323 _rtmpState = RTMP_STATE_SERVER_RESPONSE_SENT; 324 325 return true; 328 326 } 329 327
Note: See TracChangeset
for help on using the changeset viewer.
