diff --git a/trunk/conf/full.conf b/trunk/conf/full.conf old mode 100644 new mode 100755 index dbd22386f..c35c21b26 --- a/trunk/conf/full.conf +++ b/trunk/conf/full.conf @@ -291,6 +291,25 @@ vhost audio.transcode.vhost.com { } } } +# disable video, transcode/copy audio. +# for example, publish pure audio stream. +vhost vn.transcode.vhost.com { + transcode { + enabled on; + ffmpeg ./objs/ffmpeg/bin/ffmpeg; + engine vn { + enabled on; + vcodec vn; + acodec libaacplus; + abitrate 45; + asample_rate 44100; + achannels 2; + aparams { + } + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; + } + } +} # ffmpeg-copy(forward implements by ffmpeg). # copy the video and audio to a new stream. vhost copy.transcode.vhost.com { @@ -333,6 +352,7 @@ vhost all.transcode.vhost.com { # video encoder name. can be: # libx264: use h.264(libx264) video encoder. # copy: donot encoder the video stream, copy it. + # vn: disable video output. vcodec libx264; # video bitrate, in kbps vbitrate 1500; @@ -364,6 +384,7 @@ vhost all.transcode.vhost.com { # audio encoder name. can be: # libaacplus: use aac(libaacplus) audio encoder. # copy: donot encoder the audio stream, copy it. + # an: disable audio output. acodec libaacplus; # audio bitrate, in kbps. [16, 72] for libaacplus. abitrate 70; diff --git a/trunk/conf/srs.conf b/trunk/conf/srs.conf old mode 100644 new mode 100755 index 0e4140af3..127566be9 --- a/trunk/conf/srs.conf +++ b/trunk/conf/srs.conf @@ -3,4 +3,19 @@ listen 1935; vhost __defaultVhost__ { + transcode { + enabled on; + ffmpeg ./objs/ffmpeg/bin/ffmpeg; + engine vn { + enabled on; + vcodec vn; + acodec libaacplus; + abitrate 45; + asample_rate 44100; + achannels 2; + aparams { + } + output rtmp://127.0.0.1:[port]/[app]?vhost=[vhost]/[stream]_[engine]; + } + } } diff --git a/trunk/src/app/srs_app_encoder.cpp b/trunk/src/app/srs_app_encoder.cpp index 9524b0772..3fbc79787 100644 --- a/trunk/src/app/srs_app_encoder.cpp +++ b/trunk/src/app/srs_app_encoder.cpp @@ -42,6 +42,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifdef SRS_FFMPEG #define SRS_ENCODER_COPY "copy" +#define SRS_ENCODER_NO_VIDEO "vn" +#define SRS_ENCODER_NO_AUDIO "an" #define SRS_ENCODER_VCODEC "libx264" #define SRS_ENCODER_ACODEC "libaacplus" @@ -138,7 +140,13 @@ int SrsFFMPEG::initialize(SrsRequest* req, SrsConfDirective* engine) } _transcoded_url.push_back(output); - if (vcodec != SRS_ENCODER_COPY) { + if (vcodec == SRS_ENCODER_NO_VIDEO && acodec == SRS_ENCODER_NO_AUDIO) { + ret = ERROR_ENCODER_VCODEC; + srs_warn("video and audio disabled. ret=%d", ret); + return ret; + } + + if (vcodec != SRS_ENCODER_COPY && vcodec != SRS_ENCODER_NO_VIDEO) { if (vcodec != SRS_ENCODER_VCODEC) { ret = ERROR_ENCODER_VCODEC; srs_error("invalid vcodec, must be %s, actual %s, ret=%d", @@ -182,7 +190,7 @@ int SrsFFMPEG::initialize(SrsRequest* req, SrsConfDirective* engine) } } - if (acodec != SRS_ENCODER_COPY) { + if (acodec != SRS_ENCODER_COPY && acodec != SRS_ENCODER_NO_AUDIO) { if (acodec != SRS_ENCODER_ACODEC) { ret = ERROR_ENCODER_ACODEC; srs_error("invalid acodec, must be %s, actual %s, ret=%d", @@ -254,11 +262,15 @@ int SrsFFMPEG::start() } // video specified. - params.push_back("-vcodec"); - params.push_back(vcodec); + if (vcodec != SRS_ENCODER_NO_VIDEO) { + params.push_back("-vcodec"); + params.push_back(vcodec); + } else { + params.push_back("-vn"); + } // the codec params is disabled when copy - if (vcodec != SRS_ENCODER_COPY) { + if (vcodec != SRS_ENCODER_COPY && vcodec != SRS_ENCODER_NO_VIDEO) { params.push_back("-b:v"); snprintf(tmp, sizeof(tmp), "%d", vbitrate * 1000); params.push_back(tmp); @@ -299,11 +311,15 @@ int SrsFFMPEG::start() } // audio specified. - params.push_back("-acodec"); - params.push_back(acodec); + if (acodec != SRS_ENCODER_NO_AUDIO) { + params.push_back("-acodec"); + params.push_back(acodec); + } else { + params.push_back("-an"); + } // the codec params is disabled when copy - if (acodec != SRS_ENCODER_COPY) { + if (acodec != SRS_ENCODER_COPY && acodec != SRS_ENCODER_NO_AUDIO) { params.push_back("-b:a"); snprintf(tmp, sizeof(tmp), "%d", abitrate * 1000); params.push_back(tmp); diff --git a/trunk/src/rtmp/srs_protocol_handshake.cpp b/trunk/src/rtmp/srs_protocol_handshake.cpp index bd167cfad..9fbe07ece 100644 --- a/trunk/src/rtmp/srs_protocol_handshake.cpp +++ b/trunk/src/rtmp/srs_protocol_handshake.cpp @@ -32,924 +32,936 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include -using namespace srs; - #ifdef SRS_SSL -// 68bytes FMS key which is used to sign the sever packet. -u_int8_t srs::SrsGenuineFMSKey[] = { - 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, - 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, - 0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69, - 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Media Server 001 - 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, - 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, - 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, - 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae -}; // 68 - -// 62bytes FP key which is used to sign the client packet. -u_int8_t srs::SrsGenuineFPKey[] = { - 0x47, 0x65, 0x6E, 0x75, 0x69, 0x6E, 0x65, 0x20, - 0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x46, 0x6C, - 0x61, 0x73, 0x68, 0x20, 0x50, 0x6C, 0x61, 0x79, - 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Player 001 - 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, - 0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E, 0x7E, 0x57, - 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, - 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE -}; // 62 +using namespace srs; +// for openssl_HMACsha256 #include #include -int srs::openssl_HMACsha256(const void* data, int data_size, const void* key, int key_size, void* digest) -{ - HMAC_CTX ctx; - - HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, (unsigned char*) key, key_size, EVP_sha256(), NULL); - HMAC_Update(&ctx, (unsigned char *) data, data_size); - - unsigned int digest_size; - HMAC_Final(&ctx, (unsigned char *) digest, &digest_size); - - HMAC_CTX_cleanup(&ctx); - - if (digest_size != 32) { - return ERROR_OpenSslSha256DigestSize; - } - - return ERROR_SUCCESS; -} - +// for __openssl_generate_key #include -#define RFC2409_PRIME_1024 \ - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \ - "FFFFFFFFFFFFFFFF" -int __openssl_generate_key( - u_int8_t*& _private_key, u_int8_t*& _public_key, int32_t& size, - DH*& pdh, int32_t& bits_count, u_int8_t*& shared_key, int32_t& shared_key_length, BIGNUM*& peer_public_key -){ - int ret = ERROR_SUCCESS; - //1. Create the DH - if ((pdh = DH_new()) == NULL) { - ret = ERROR_OpenSslCreateDH; - return ret; - } - - //2. Create his internal p and g - if ((pdh->p = BN_new()) == NULL) { - ret = ERROR_OpenSslCreateP; - return ret; - } - if ((pdh->g = BN_new()) == NULL) { - ret = ERROR_OpenSslCreateG; - return ret; - } - - //3. initialize p, g and key length - if (BN_hex2bn(&pdh->p, RFC2409_PRIME_1024) == 0) { - ret = ERROR_OpenSslParseP1024; - return ret; - } - if (BN_set_word(pdh->g, 2) != 1) { - ret = ERROR_OpenSslSetG; - return ret; - } - - //4. Set the key length - pdh->length = bits_count; - - //5. Generate private and public key - if (DH_generate_key(pdh) != 1) { - ret = ERROR_OpenSslGenerateDHKeys; - return ret; - } - - // CreateSharedKey - if (pdh == NULL) { - ret = ERROR_OpenSslGenerateDHKeys; - return ret; - } - - if (shared_key_length != 0 || shared_key != NULL) { - ret = ERROR_OpenSslShareKeyComputed; - return ret; - } - - shared_key_length = DH_size(pdh); - if (shared_key_length <= 0 || shared_key_length > 1024) { - ret = ERROR_OpenSslGetSharedKeySize; - return ret; - } - shared_key = new u_int8_t[shared_key_length]; - memset(shared_key, 0, shared_key_length); - - peer_public_key = BN_bin2bn(_private_key, size, 0); - if (peer_public_key == NULL) { - ret = ERROR_OpenSslGetPeerPublicKey; - return ret; - } - - if (DH_compute_key(shared_key, peer_public_key, pdh) == -1) { - ret = ERROR_OpenSslComputeSharedKey; - return ret; - } - - // CopyPublicKey - if (pdh == NULL) { - ret = ERROR_OpenSslComputeSharedKey; - return ret; - } - - int32_t keySize = BN_num_bytes(pdh->pub_key); - if ((keySize <= 0) || (size <= 0) || (keySize > size)) { - //("CopyPublicKey failed due to either invalid DH state or invalid call"); return ret; - ret = ERROR_OpenSslInvalidDHState; - return ret; - } - - if (BN_bn2bin(pdh->pub_key, _public_key) != keySize) { - //("Unable to copy key"); return ret; - ret = ERROR_OpenSslCopyKey; - return ret; - } - - return ret; -} -int openssl_generate_key(char* _private_key, char* _public_key, int32_t size) +namespace srs { - int ret = ERROR_SUCCESS; - - // Initialize - DH* pdh = NULL; - int32_t bits_count = 1024; - u_int8_t* shared_key = NULL; - int32_t shared_key_length = 0; - BIGNUM* peer_public_key = NULL; - - ret = __openssl_generate_key( - (u_int8_t*&)_private_key, (u_int8_t*&)_public_key, size, - pdh, bits_count, shared_key, shared_key_length, peer_public_key - ); - - if (pdh != NULL) { - if (pdh->p != NULL) { - BN_free(pdh->p); - pdh->p = NULL; - } - if (pdh->g != NULL) { - BN_free(pdh->g); - pdh->g = NULL; - } - DH_free(pdh); - pdh = NULL; - } - - if (shared_key != NULL) { - delete[] shared_key; - shared_key = NULL; - } - - if (peer_public_key != NULL) { - BN_free(peer_public_key); - peer_public_key = NULL; - } - - return ret; -} - -// calc the offset of key, -// the key->offset cannot be used as the offset of key. -int srs_key_block_get_offset(key_block* key) -{ - int max_offset_size = 764 - 128 - 4; - - int offset = 0; - u_int8_t* pp = (u_int8_t*)&key->offset; - offset += *pp++; - offset += *pp++; - offset += *pp++; - offset += *pp++; - - return offset % max_offset_size; -} -// create new key block data. -// if created, user must free it by srs_key_block_free -void srs_key_block_init(key_block* key) -{ - key->offset = (int32_t)rand(); - key->random0 = NULL; - key->random1 = NULL; - - int offset = srs_key_block_get_offset(key); - srs_assert(offset >= 0); - - key->random0_size = offset; - if (key->random0_size > 0) { - key->random0 = new char[key->random0_size]; - srs_random_generate(key->random0, key->random0_size); - } - - srs_random_generate(key->key, sizeof(key->key)); - - key->random1_size = 764 - offset - 128 - 4; - if (key->random1_size > 0) { - key->random1 = new char[key->random1_size]; - srs_random_generate(key->random1, key->random1_size); - } -} -// parse key block from c1s1. -// if created, user must free it by srs_key_block_free -// @c1s1_key_bytes the key start bytes, maybe c1s1 or c1s1+764 -int srs_key_block_parse(key_block* key, char* c1s1_key_bytes) -{ - int ret = ERROR_SUCCESS; - - char* pp = c1s1_key_bytes + 764; - - pp -= sizeof(int32_t); - key->offset = *(int32_t*)pp; - - key->random0 = NULL; - key->random1 = NULL; - - int offset = srs_key_block_get_offset(key); - srs_assert(offset >= 0); - - pp = c1s1_key_bytes; - key->random0_size = offset; - if (key->random0_size > 0) { - key->random0 = new char[key->random0_size]; - memcpy(key->random0, pp, key->random0_size); - } - pp += key->random0_size; - - memcpy(key->key, pp, sizeof(key->key)); - pp += sizeof(key->key); - - key->random1_size = 764 - offset - 128 - 4; - if (key->random1_size > 0) { - key->random1 = new char[key->random1_size]; - memcpy(key->random1, pp, key->random1_size); - } - - return ret; -} -// free the block data create by -// srs_key_block_init or srs_key_block_parse -void srs_key_block_free(key_block* key) -{ - if (key->random0) { - srs_freepa(key->random0); - } - if (key->random1) { - srs_freepa(key->random1); - } -} - -// calc the offset of digest, -// the key->offset cannot be used as the offset of digest. -int srs_digest_block_get_offset(digest_block* digest) -{ - int max_offset_size = 764 - 32 - 4; - - int offset = 0; - u_int8_t* pp = (u_int8_t*)&digest->offset; - offset += *pp++; - offset += *pp++; - offset += *pp++; - offset += *pp++; - - return offset % max_offset_size; -} -// create new digest block data. -// if created, user must free it by srs_digest_block_free -void srs_digest_block_init(digest_block* digest) -{ - digest->offset = (int32_t)rand(); - digest->random0 = NULL; - digest->random1 = NULL; - - int offset = srs_digest_block_get_offset(digest); - srs_assert(offset >= 0); - - digest->random0_size = offset; - if (digest->random0_size > 0) { - digest->random0 = new char[digest->random0_size]; - srs_random_generate(digest->random0, digest->random0_size); - } - - srs_random_generate(digest->digest, sizeof(digest->digest)); - - digest->random1_size = 764 - 4 - offset - 32; - if (digest->random1_size > 0) { - digest->random1 = new char[digest->random1_size]; - srs_random_generate(digest->random1, digest->random1_size); - } -} -// parse digest block from c1s1. -// if created, user must free it by srs_digest_block_free -// @c1s1_digest_bytes the digest start bytes, maybe c1s1 or c1s1+764 -int srs_digest_block_parse(digest_block* digest, char* c1s1_digest_bytes) -{ - int ret = ERROR_SUCCESS; - - char* pp = c1s1_digest_bytes; - - digest->offset = *(int32_t*)pp; - pp += sizeof(int32_t); - - digest->random0 = NULL; - digest->random1 = NULL; - - int offset = srs_digest_block_get_offset(digest); - srs_assert(offset >= 0); - - digest->random0_size = offset; - if (digest->random0_size > 0) { - digest->random0 = new char[digest->random0_size]; - memcpy(digest->random0, pp, digest->random0_size); - } - pp += digest->random0_size; - - memcpy(digest->digest, pp, sizeof(digest->digest)); - pp += sizeof(digest->digest); - - digest->random1_size = 764 - 4 - offset - 32; - if (digest->random1_size > 0) { - digest->random1 = new char[digest->random1_size]; - memcpy(digest->random1, pp, digest->random1_size); - } - - return ret; -} -// free the block data create by -// srs_digest_block_init or srs_digest_block_parse -void srs_digest_block_free(digest_block* digest) -{ - if (digest->random0) { - srs_freepa(digest->random0); - } - if (digest->random1) { - srs_freepa(digest->random1); - } -} - -void __srs_time_copy_to(char*& pp, int32_t time) -{ - // 4bytes time - *(int32_t*)pp = time; - pp += 4; -} -void __srs_version_copy_to(char*& pp, int32_t version) -{ - // 4bytes version - *(int32_t*)pp = version; - pp += 4; -} -void __srs_key_copy_to(char*& pp, key_block* key) -{ - // 764bytes key block - if (key->random0_size > 0) { - memcpy(pp, key->random0, key->random0_size); - } - pp += key->random0_size; - - memcpy(pp, key->key, sizeof(key->key)); - pp += sizeof(key->key); - - if (key->random1_size > 0) { - memcpy(pp, key->random1, key->random1_size); - } - pp += key->random1_size; - - *(int32_t*)pp = key->offset; - pp += 4; -} -void __srs_digest_copy_to(char*& pp, digest_block* digest, bool with_digest) -{ - // 732bytes digest block without the 32bytes digest-data - // nbytes digest block part1 - *(int32_t*)pp = digest->offset; - pp += 4; - - if (digest->random0_size > 0) { - memcpy(pp, digest->random0, digest->random0_size); - } - pp += digest->random0_size; - - // digest - if (with_digest) { - memcpy(pp, digest->digest, 32); - pp += 32; - } - - // nbytes digest block part2 - if (digest->random1_size > 0) { - memcpy(pp, digest->random1, digest->random1_size); - } - pp += digest->random1_size; -} - -/** -* copy whole c1s1 to bytes. -*/ -void srs_schema0_copy_to(char* bytes, bool with_digest, - int32_t time, int32_t version, key_block* key, digest_block* digest) -{ - char* pp = bytes; - - __srs_time_copy_to(pp, time); - __srs_version_copy_to(pp, version); - __srs_key_copy_to(pp, key); - __srs_digest_copy_to(pp, digest, with_digest); - - if (with_digest) { - srs_assert(pp - bytes == 1536); - } else { - srs_assert(pp - bytes == 1536 - 32); - } -} -void srs_schema1_copy_to(char* bytes, bool with_digest, - int32_t time, int32_t version, digest_block* digest, key_block* key) -{ - char* pp = bytes; - - __srs_time_copy_to(pp, time); - __srs_version_copy_to(pp, version); - __srs_digest_copy_to(pp, digest, with_digest); - __srs_key_copy_to(pp, key); - - if (with_digest) { - srs_assert(pp - bytes == 1536); - } else { - srs_assert(pp - bytes == 1536 - 32); - } -} - -/** -* c1s1 is splited by digest: -* c1s1-part1: n bytes (time, version, key and digest-part1). -* digest-data: 32bytes -* c1s1-part2: (1536-n-32)bytes (digest-part2) -*/ -char* srs::srs_bytes_join_schema0(int32_t time, int32_t version, key_block* key, digest_block* digest) -{ - char* bytes = new char[1536 -32]; - - srs_schema0_copy_to(bytes, false, time, version, key, digest); - - return bytes; -} - -/** -* c1s1 is splited by digest: -* c1s1-part1: n bytes (time, version and digest-part1). -* digest-data: 32bytes -* c1s1-part2: (1536-n-32)bytes (digest-part2 and key) -*/ -char* srs::srs_bytes_join_schema1(int32_t time, int32_t version, digest_block* digest, key_block* key) -{ - char* bytes = new char[1536 -32]; - - srs_schema1_copy_to(bytes, false, time, version, digest, key); - - return bytes; -} - -/** -* compare the memory in bytes. -*/ -bool srs::srs_bytes_equals(void* pa, void* pb, int size) -{ - u_int8_t* a = (u_int8_t*)pa; - u_int8_t* b = (u_int8_t*)pb; - - for(int i = 0; i < size; i++){ - if(a[i] != b[i]){ - return false; - } - } - - return true; -} - -c2s2::c2s2() -{ - srs_random_generate(random, 1504); - srs_random_generate(digest, 32); -} - -c2s2::~c2s2() -{ -} - -void c2s2::dump(char* _c2s2) -{ - memcpy(_c2s2, random, 1504); - memcpy(_c2s2 + 1504, digest, 32); -} - -void c2s2::parse(char* _c2s2) -{ - memcpy(random, _c2s2, 1504); - memcpy(digest, _c2s2 + 1504, 32); -} - -int c2s2::c2_create(c1s1* s1) -{ - int ret = ERROR_SUCCESS; - - char temp_key[OpensslHashSize]; - if ((ret = openssl_HMACsha256(s1->get_digest(), 32, SrsGenuineFPKey, 62, temp_key)) != ERROR_SUCCESS) { - srs_error("create c2 temp key failed. ret=%d", ret); - return ret; - } - srs_verbose("generate c2 temp key success."); - - char _digest[OpensslHashSize]; - if ((ret = openssl_HMACsha256(random, 1504, temp_key, 32, _digest)) != ERROR_SUCCESS) { - srs_error("create c2 digest failed. ret=%d", ret); - return ret; - } - srs_verbose("generate c2 digest success."); - - memcpy(digest, _digest, 32); - - return ret; -} - -int c2s2::c2_validate(c1s1* s1, bool& is_valid) -{ - is_valid = false; - int ret = ERROR_SUCCESS; - - char temp_key[OpensslHashSize]; - if ((ret = openssl_HMACsha256(s1->get_digest(), 32, SrsGenuineFPKey, 62, temp_key)) != ERROR_SUCCESS) { - srs_error("create c2 temp key failed. ret=%d", ret); - return ret; - } - srs_verbose("generate c2 temp key success."); - - char _digest[OpensslHashSize]; - if ((ret = openssl_HMACsha256(random, 1504, temp_key, 32, _digest)) != ERROR_SUCCESS) { - srs_error("create c2 digest failed. ret=%d", ret); - return ret; - } - srs_verbose("generate c2 digest success."); - - is_valid = srs_bytes_equals(digest, _digest, 32); - - return ret; -} - -int c2s2::s2_create(c1s1* c1) -{ - int ret = ERROR_SUCCESS; - - char temp_key[OpensslHashSize]; - if ((ret = openssl_HMACsha256(c1->get_digest(), 32, SrsGenuineFMSKey, 68, temp_key)) != ERROR_SUCCESS) { - srs_error("create s2 temp key failed. ret=%d", ret); - return ret; - } - srs_verbose("generate s2 temp key success."); - - char _digest[OpensslHashSize]; - if ((ret = openssl_HMACsha256(random, 1504, temp_key, 32, _digest)) != ERROR_SUCCESS) { - srs_error("create s2 digest failed. ret=%d", ret); - return ret; - } - srs_verbose("generate s2 digest success."); - - memcpy(digest, _digest, 32); - - return ret; -} - -int c2s2::s2_validate(c1s1* c1, bool& is_valid) -{ - is_valid = false; - int ret = ERROR_SUCCESS; - - char temp_key[OpensslHashSize]; - if ((ret = openssl_HMACsha256(c1->get_digest(), 32, SrsGenuineFMSKey, 68, temp_key)) != ERROR_SUCCESS) { - srs_error("create s2 temp key failed. ret=%d", ret); - return ret; - } - srs_verbose("generate s2 temp key success."); - - char _digest[OpensslHashSize]; - if ((ret = openssl_HMACsha256(random, 1504, temp_key, 32, _digest)) != ERROR_SUCCESS) { - srs_error("create s2 digest failed. ret=%d", ret); - return ret; - } - srs_verbose("generate s2 digest success."); - - is_valid = srs_bytes_equals(digest, _digest, 32); - - return ret; -} - -// TODO: FIXME: move to the right position. -c1s1::c1s1() -{ - schema = srs_schema_invalid; -} -c1s1::~c1s1() -{ - destroy_blocks(); -} - -char* c1s1::get_digest() -{ - srs_assert(schema != srs_schema_invalid); - - if (schema == srs_schema0) { - return block1.digest.digest; - } else { - return block0.digest.digest; - } -} - -void c1s1::dump(char* _c1s1) -{ - srs_assert(schema != srs_schema_invalid); - - if (schema == srs_schema0) { - srs_schema0_copy_to(_c1s1, true, time, version, &block0.key, &block1.digest); - } else { - srs_schema1_copy_to(_c1s1, true, time, version, &block0.digest, &block1.key); - } -} - -int c1s1::parse(char* _c1s1, srs_schema_type _schema) -{ - int ret = ERROR_SUCCESS; - - if (_schema == srs_schema_invalid) { - ret = ERROR_RTMP_CH_SCHEMA; - srs_error("parse c1 failed. invalid schema=%d, ret=%d", _schema, ret); - return ret; - } - - destroy_blocks(); - - time = *(int32_t*)_c1s1; - version = *(int32_t*)(_c1s1 + 4); // client c1 version - - if (_schema == srs_schema0) { - if ((ret = srs_key_block_parse(&block0.key, _c1s1 + 8)) != ERROR_SUCCESS) { - srs_error("parse the c1 key failed. ret=%d", ret); - return ret; - } - if ((ret = srs_digest_block_parse(&block1.digest, _c1s1 + 8 + 764)) != ERROR_SUCCESS) { - srs_error("parse the c1 digest failed. ret=%d", ret); - return ret; - } - srs_verbose("parse c1 key-digest success"); - } else if (_schema == srs_schema1) { - if ((ret = srs_digest_block_parse(&block0.digest, _c1s1 + 8)) != ERROR_SUCCESS) { - srs_error("parse the c1 key failed. ret=%d", ret); - return ret; - } - if ((ret = srs_key_block_parse(&block1.key, _c1s1 + 8 + 764)) != ERROR_SUCCESS) { - srs_error("parse the c1 digest failed. ret=%d", ret); - return ret; - } - srs_verbose("parse c1 digest-key success"); - } else { - ret = ERROR_RTMP_CH_SCHEMA; - srs_error("parse c1 failed. invalid schema=%d, ret=%d", _schema, ret); - return ret; - } - - schema = _schema; - - return ret; -} - -int c1s1::c1_create(srs_schema_type _schema) -{ - int ret = ERROR_SUCCESS; - - if (_schema == srs_schema_invalid) { - ret = ERROR_RTMP_CH_SCHEMA; - srs_error("create c1 failed. invalid schema=%d, ret=%d", _schema, ret); - return ret; - } - - destroy_blocks(); - - time = ::time(NULL); - version = 0x02070080; // client c1 version - - if (_schema == srs_schema0) { - srs_key_block_init(&block0.key); - srs_digest_block_init(&block1.digest); - } else { - srs_digest_block_init(&block0.digest); - srs_key_block_init(&block1.key); - } - - schema = _schema; - - char* digest = NULL; - - if ((ret = calc_c1_digest(digest)) != ERROR_SUCCESS) { - srs_error("sign c1 error, failed to calc digest. ret=%d", ret); - return ret; - } - - srs_assert(digest != NULL); - SrsAutoFree(char, digest, true); - - if (schema == srs_schema0) { - memcpy(block1.digest.digest, digest, 32); - } else { - memcpy(block0.digest.digest, digest, 32); - } - - return ret; -} - -int c1s1::c1_validate_digest(bool& is_valid) -{ - is_valid = false; - int ret = ERROR_SUCCESS; - - char* c1_digest = NULL; - - if ((ret = calc_c1_digest(c1_digest)) != ERROR_SUCCESS) { - srs_error("validate c1 error, failed to calc digest. ret=%d", ret); - return ret; - } - - srs_assert(c1_digest != NULL); - SrsAutoFree(char, c1_digest, true); - - if (schema == srs_schema0) { - is_valid = srs_bytes_equals(block1.digest.digest, c1_digest, 32); - } else { - is_valid = srs_bytes_equals(block0.digest.digest, c1_digest, 32); - } - - return ret; -} - -int c1s1::s1_validate_digest(bool& is_valid) -{ - is_valid = false; - int ret = ERROR_SUCCESS; - - char* s1_digest = NULL; - - if ((ret = calc_s1_digest(s1_digest)) != ERROR_SUCCESS) { - srs_error("validate s1 error, failed to calc digest. ret=%d", ret); - return ret; - } - - srs_assert(s1_digest != NULL); - SrsAutoFree(char, s1_digest, true); - - if (schema == srs_schema0) { - is_valid = srs_bytes_equals(block1.digest.digest, s1_digest, 32); - } else { - is_valid = srs_bytes_equals(block0.digest.digest, s1_digest, 32); - } - - return ret; -} - -int c1s1::s1_create(c1s1* c1) -{ - int ret = ERROR_SUCCESS; - - if (c1->schema == srs_schema_invalid) { - ret = ERROR_RTMP_CH_SCHEMA; - srs_error("create s1 failed. invalid schema=%d, ret=%d", c1->schema, ret); - return ret; - } - - destroy_blocks(); - schema = c1->schema; - - time = ::time(NULL); - version = 0x01000504; // server s1 version - - if (schema == srs_schema0) { - srs_key_block_init(&block0.key); - srs_digest_block_init(&block1.digest); - } else { - srs_digest_block_init(&block0.digest); - srs_key_block_init(&block1.key); - } - - if (schema == srs_schema0) { - if ((ret = openssl_generate_key(c1->block0.key.key, block0.key.key, 128)) != ERROR_SUCCESS) { - srs_error("calc s1 key failed. ret=%d", ret); - return ret; - } - } else { - if ((ret = openssl_generate_key(c1->block1.key.key, block1.key.key, 128)) != ERROR_SUCCESS) { - srs_error("calc s1 key failed. ret=%d", ret); - return ret; - } - } - srs_verbose("calc s1 key success."); + // 68bytes FMS key which is used to sign the sever packet. + u_int8_t SrsGenuineFMSKey[] = { + 0x47, 0x65, 0x6e, 0x75, 0x69, 0x6e, 0x65, 0x20, + 0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x6c, + 0x61, 0x73, 0x68, 0x20, 0x4d, 0x65, 0x64, 0x69, + 0x61, 0x20, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Media Server 001 + 0xf0, 0xee, 0xc2, 0x4a, 0x80, 0x68, 0xbe, 0xe8, + 0x2e, 0x00, 0xd0, 0xd1, 0x02, 0x9e, 0x7e, 0x57, + 0x6e, 0xec, 0x5d, 0x2d, 0x29, 0x80, 0x6f, 0xab, + 0x93, 0xb8, 0xe6, 0x36, 0xcf, 0xeb, 0x31, 0xae + }; // 68 + + // 62bytes FP key which is used to sign the client packet. + u_int8_t SrsGenuineFPKey[] = { + 0x47, 0x65, 0x6E, 0x75, 0x69, 0x6E, 0x65, 0x20, + 0x41, 0x64, 0x6F, 0x62, 0x65, 0x20, 0x46, 0x6C, + 0x61, 0x73, 0x68, 0x20, 0x50, 0x6C, 0x61, 0x79, + 0x65, 0x72, 0x20, 0x30, 0x30, 0x31, // Genuine Adobe Flash Player 001 + 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, + 0x2E, 0x00, 0xD0, 0xD1, 0x02, 0x9E, 0x7E, 0x57, + 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, + 0x93, 0xB8, 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE + }; // 62 + + int openssl_HMACsha256(const void* data, int data_size, const void* key, int key_size, void* digest) + { + HMAC_CTX ctx; + + HMAC_CTX_init(&ctx); + HMAC_Init_ex(&ctx, (unsigned char*) key, key_size, EVP_sha256(), NULL); + HMAC_Update(&ctx, (unsigned char *) data, data_size); + + unsigned int digest_size; + HMAC_Final(&ctx, (unsigned char *) digest, &digest_size); + + HMAC_CTX_cleanup(&ctx); + + if (digest_size != 32) { + return ERROR_OpenSslSha256DigestSize; + } + + return ERROR_SUCCESS; + } + + #define RFC2409_PRIME_1024 \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \ + "FFFFFFFFFFFFFFFF" + int __openssl_generate_key( + u_int8_t*& _private_key, u_int8_t*& _public_key, int32_t& size, + DH*& pdh, int32_t& bits_count, u_int8_t*& shared_key, int32_t& shared_key_length, BIGNUM*& peer_public_key + ){ + int ret = ERROR_SUCCESS; + + //1. Create the DH + if ((pdh = DH_new()) == NULL) { + ret = ERROR_OpenSslCreateDH; + return ret; + } + + //2. Create his internal p and g + if ((pdh->p = BN_new()) == NULL) { + ret = ERROR_OpenSslCreateP; + return ret; + } + if ((pdh->g = BN_new()) == NULL) { + ret = ERROR_OpenSslCreateG; + return ret; + } + + //3. initialize p, g and key length + if (BN_hex2bn(&pdh->p, RFC2409_PRIME_1024) == 0) { + ret = ERROR_OpenSslParseP1024; + return ret; + } + if (BN_set_word(pdh->g, 2) != 1) { + ret = ERROR_OpenSslSetG; + return ret; + } + + //4. Set the key length + pdh->length = bits_count; + + //5. Generate private and public key + if (DH_generate_key(pdh) != 1) { + ret = ERROR_OpenSslGenerateDHKeys; + return ret; + } + + // CreateSharedKey + if (pdh == NULL) { + ret = ERROR_OpenSslGenerateDHKeys; + return ret; + } + + if (shared_key_length != 0 || shared_key != NULL) { + ret = ERROR_OpenSslShareKeyComputed; + return ret; + } + + shared_key_length = DH_size(pdh); + if (shared_key_length <= 0 || shared_key_length > 1024) { + ret = ERROR_OpenSslGetSharedKeySize; + return ret; + } + shared_key = new u_int8_t[shared_key_length]; + memset(shared_key, 0, shared_key_length); + + peer_public_key = BN_bin2bn(_private_key, size, 0); + if (peer_public_key == NULL) { + ret = ERROR_OpenSslGetPeerPublicKey; + return ret; + } + + if (DH_compute_key(shared_key, peer_public_key, pdh) == -1) { + ret = ERROR_OpenSslComputeSharedKey; + return ret; + } + + // CopyPublicKey + if (pdh == NULL) { + ret = ERROR_OpenSslComputeSharedKey; + return ret; + } + + int32_t keySize = BN_num_bytes(pdh->pub_key); + if ((keySize <= 0) || (size <= 0) || (keySize > size)) { + //("CopyPublicKey failed due to either invalid DH state or invalid call"); return ret; + ret = ERROR_OpenSslInvalidDHState; + return ret; + } + + if (BN_bn2bin(pdh->pub_key, _public_key) != keySize) { + //("Unable to copy key"); return ret; + ret = ERROR_OpenSslCopyKey; + return ret; + } - char* s1_digest = NULL; - if ((ret = calc_s1_digest(s1_digest)) != ERROR_SUCCESS) { - srs_error("calc s1 digest failed. ret=%d", ret); return ret; } - srs_verbose("calc s1 digest success."); + int openssl_generate_key(char* _private_key, char* _public_key, int32_t size) + { + int ret = ERROR_SUCCESS; - srs_assert(s1_digest != NULL); - SrsAutoFree(char, s1_digest, true); + // Initialize + DH* pdh = NULL; + int32_t bits_count = 1024; + u_int8_t* shared_key = NULL; + int32_t shared_key_length = 0; + BIGNUM* peer_public_key = NULL; + + ret = __openssl_generate_key( + (u_int8_t*&)_private_key, (u_int8_t*&)_public_key, size, + pdh, bits_count, shared_key, shared_key_length, peer_public_key + ); + + if (pdh != NULL) { + if (pdh->p != NULL) { + BN_free(pdh->p); + pdh->p = NULL; + } + if (pdh->g != NULL) { + BN_free(pdh->g); + pdh->g = NULL; + } + DH_free(pdh); + pdh = NULL; + } - if (schema == srs_schema0) { - memcpy(block1.digest.digest, s1_digest, 32); - } else { - memcpy(block0.digest.digest, s1_digest, 32); - } - srs_verbose("copy s1 key success."); + if (shared_key != NULL) { + delete[] shared_key; + shared_key = NULL; + } - return ret; -} - -int c1s1::calc_s1_digest(char*& digest) -{ - int ret = ERROR_SUCCESS; + if (peer_public_key != NULL) { + BN_free(peer_public_key); + peer_public_key = NULL; + } - srs_assert(schema == srs_schema0 || schema == srs_schema1); - - char* c1s1_joined_bytes = NULL; - - if (schema == srs_schema0) { - c1s1_joined_bytes = srs_bytes_join_schema0(time, version, &block0.key, &block1.digest); - } else { - c1s1_joined_bytes = srs_bytes_join_schema1(time, version, &block0.digest, &block1.key); - } - - srs_assert(c1s1_joined_bytes != NULL); - SrsAutoFree(char, c1s1_joined_bytes, true); - - digest = new char[OpensslHashSize]; - if ((ret = openssl_HMACsha256(c1s1_joined_bytes, 1536 - 32, SrsGenuineFMSKey, 36, digest)) != ERROR_SUCCESS) { - srs_error("calc digest for s1 failed. ret=%d", ret); return ret; } - srs_verbose("digest calculated for s1"); - return ret; -} - -int c1s1::calc_c1_digest(char*& digest) -{ - int ret = ERROR_SUCCESS; + // calc the offset of key, + // the key->offset cannot be used as the offset of key. + int srs_key_block_get_offset(key_block* key) + { + int max_offset_size = 764 - 128 - 4; + + int offset = 0; + u_int8_t* pp = (u_int8_t*)&key->offset; + offset += *pp++; + offset += *pp++; + offset += *pp++; + offset += *pp++; - srs_assert(schema == srs_schema0 || schema == srs_schema1); - - char* c1s1_joined_bytes = NULL; - - if (schema == srs_schema0) { - c1s1_joined_bytes = srs_bytes_join_schema0(time, version, &block0.key, &block1.digest); - } else { - c1s1_joined_bytes = srs_bytes_join_schema1(time, version, &block0.digest, &block1.key); + return offset % max_offset_size; } - srs_assert(c1s1_joined_bytes != NULL); - SrsAutoFree(char, c1s1_joined_bytes, true); + // create new key block data. + // if created, user must free it by srs_key_block_free + void srs_key_block_init(key_block* key) + { + key->offset = (int32_t)rand(); + key->random0 = NULL; + key->random1 = NULL; + + int offset = srs_key_block_get_offset(key); + srs_assert(offset >= 0); + + key->random0_size = offset; + if (key->random0_size > 0) { + key->random0 = new char[key->random0_size]; + srs_random_generate(key->random0, key->random0_size); + } + + srs_random_generate(key->key, sizeof(key->key)); + + key->random1_size = 764 - offset - 128 - 4; + if (key->random1_size > 0) { + key->random1 = new char[key->random1_size]; + srs_random_generate(key->random1, key->random1_size); + } + } - digest = new char[OpensslHashSize]; - if ((ret = openssl_HMACsha256(c1s1_joined_bytes, 1536 - 32, SrsGenuineFPKey, 30, digest)) != ERROR_SUCCESS) { - srs_error("calc digest for c1 failed. ret=%d", ret); + // parse key block from c1s1. + // if created, user must free it by srs_key_block_free + // @c1s1_key_bytes the key start bytes, maybe c1s1 or c1s1+764 + int srs_key_block_parse(key_block* key, char* c1s1_key_bytes) + { + int ret = ERROR_SUCCESS; + + char* pp = c1s1_key_bytes + 764; + + pp -= sizeof(int32_t); + key->offset = *(int32_t*)pp; + + key->random0 = NULL; + key->random1 = NULL; + + int offset = srs_key_block_get_offset(key); + srs_assert(offset >= 0); + + pp = c1s1_key_bytes; + key->random0_size = offset; + if (key->random0_size > 0) { + key->random0 = new char[key->random0_size]; + memcpy(key->random0, pp, key->random0_size); + } + pp += key->random0_size; + + memcpy(key->key, pp, sizeof(key->key)); + pp += sizeof(key->key); + + key->random1_size = 764 - offset - 128 - 4; + if (key->random1_size > 0) { + key->random1 = new char[key->random1_size]; + memcpy(key->random1, pp, key->random1_size); + } + return ret; } - srs_verbose("digest calculated for c1"); - return ret; -} - -void c1s1::destroy_blocks() -{ - if (schema == srs_schema_invalid) { - return; + // free the block data create by + // srs_key_block_init or srs_key_block_parse + void srs_key_block_free(key_block* key) + { + if (key->random0) { + srs_freepa(key->random0); + } + if (key->random1) { + srs_freepa(key->random1); + } } - if (schema == srs_schema0) { - srs_key_block_free(&block0.key); - srs_digest_block_free(&block1.digest); - } else { - srs_digest_block_free(&block0.digest); - srs_key_block_free(&block1.key); + // calc the offset of digest, + // the key->offset cannot be used as the offset of digest. + int srs_digest_block_get_offset(digest_block* digest) + { + int max_offset_size = 764 - 32 - 4; + + int offset = 0; + u_int8_t* pp = (u_int8_t*)&digest->offset; + offset += *pp++; + offset += *pp++; + offset += *pp++; + offset += *pp++; + + return offset % max_offset_size; + } + + // create new digest block data. + // if created, user must free it by srs_digest_block_free + void srs_digest_block_init(digest_block* digest) + { + digest->offset = (int32_t)rand(); + digest->random0 = NULL; + digest->random1 = NULL; + + int offset = srs_digest_block_get_offset(digest); + srs_assert(offset >= 0); + + digest->random0_size = offset; + if (digest->random0_size > 0) { + digest->random0 = new char[digest->random0_size]; + srs_random_generate(digest->random0, digest->random0_size); + } + + srs_random_generate(digest->digest, sizeof(digest->digest)); + + digest->random1_size = 764 - 4 - offset - 32; + if (digest->random1_size > 0) { + digest->random1 = new char[digest->random1_size]; + srs_random_generate(digest->random1, digest->random1_size); + } + } + + // parse digest block from c1s1. + // if created, user must free it by srs_digest_block_free + // @c1s1_digest_bytes the digest start bytes, maybe c1s1 or c1s1+764 + int srs_digest_block_parse(digest_block* digest, char* c1s1_digest_bytes) + { + int ret = ERROR_SUCCESS; + + char* pp = c1s1_digest_bytes; + + digest->offset = *(int32_t*)pp; + pp += sizeof(int32_t); + + digest->random0 = NULL; + digest->random1 = NULL; + + int offset = srs_digest_block_get_offset(digest); + srs_assert(offset >= 0); + + digest->random0_size = offset; + if (digest->random0_size > 0) { + digest->random0 = new char[digest->random0_size]; + memcpy(digest->random0, pp, digest->random0_size); + } + pp += digest->random0_size; + + memcpy(digest->digest, pp, sizeof(digest->digest)); + pp += sizeof(digest->digest); + + digest->random1_size = 764 - 4 - offset - 32; + if (digest->random1_size > 0) { + digest->random1 = new char[digest->random1_size]; + memcpy(digest->random1, pp, digest->random1_size); + } + + return ret; + } + + // free the block data create by + // srs_digest_block_init or srs_digest_block_parse + void srs_digest_block_free(digest_block* digest) + { + if (digest->random0) { + srs_freepa(digest->random0); + } + if (digest->random1) { + srs_freepa(digest->random1); + } + } + + void __srs_time_copy_to(char*& pp, int32_t time) + { + // 4bytes time + *(int32_t*)pp = time; + pp += 4; + } + void __srs_version_copy_to(char*& pp, int32_t version) + { + // 4bytes version + *(int32_t*)pp = version; + pp += 4; + } + void __srs_key_copy_to(char*& pp, key_block* key) + { + // 764bytes key block + if (key->random0_size > 0) { + memcpy(pp, key->random0, key->random0_size); + } + pp += key->random0_size; + + memcpy(pp, key->key, sizeof(key->key)); + pp += sizeof(key->key); + + if (key->random1_size > 0) { + memcpy(pp, key->random1, key->random1_size); + } + pp += key->random1_size; + + *(int32_t*)pp = key->offset; + pp += 4; + } + void __srs_digest_copy_to(char*& pp, digest_block* digest, bool with_digest) + { + // 732bytes digest block without the 32bytes digest-data + // nbytes digest block part1 + *(int32_t*)pp = digest->offset; + pp += 4; + + if (digest->random0_size > 0) { + memcpy(pp, digest->random0, digest->random0_size); + } + pp += digest->random0_size; + + // digest + if (with_digest) { + memcpy(pp, digest->digest, 32); + pp += 32; + } + + // nbytes digest block part2 + if (digest->random1_size > 0) { + memcpy(pp, digest->random1, digest->random1_size); + } + pp += digest->random1_size; + } + + /** + * copy whole c1s1 to bytes. + */ + void srs_schema0_copy_to(char* bytes, bool with_digest, + int32_t time, int32_t version, key_block* key, digest_block* digest) + { + char* pp = bytes; + + __srs_time_copy_to(pp, time); + __srs_version_copy_to(pp, version); + __srs_key_copy_to(pp, key); + __srs_digest_copy_to(pp, digest, with_digest); + + if (with_digest) { + srs_assert(pp - bytes == 1536); + } else { + srs_assert(pp - bytes == 1536 - 32); + } + } + void srs_schema1_copy_to(char* bytes, bool with_digest, + int32_t time, int32_t version, digest_block* digest, key_block* key) + { + char* pp = bytes; + + __srs_time_copy_to(pp, time); + __srs_version_copy_to(pp, version); + __srs_digest_copy_to(pp, digest, with_digest); + __srs_key_copy_to(pp, key); + + if (with_digest) { + srs_assert(pp - bytes == 1536); + } else { + srs_assert(pp - bytes == 1536 - 32); + } + } + + /** + * c1s1 is splited by digest: + * c1s1-part1: n bytes (time, version, key and digest-part1). + * digest-data: 32bytes + * c1s1-part2: (1536-n-32)bytes (digest-part2) + */ + char* srs_bytes_join_schema0(int32_t time, int32_t version, key_block* key, digest_block* digest) + { + char* bytes = new char[1536 -32]; + + srs_schema0_copy_to(bytes, false, time, version, key, digest); + + return bytes; + } + + /** + * c1s1 is splited by digest: + * c1s1-part1: n bytes (time, version and digest-part1). + * digest-data: 32bytes + * c1s1-part2: (1536-n-32)bytes (digest-part2 and key) + */ + char* srs_bytes_join_schema1(int32_t time, int32_t version, digest_block* digest, key_block* key) + { + char* bytes = new char[1536 -32]; + + srs_schema1_copy_to(bytes, false, time, version, digest, key); + + return bytes; + } + + /** + * compare the memory in bytes. + */ + bool srs_bytes_equals(void* pa, void* pb, int size) + { + u_int8_t* a = (u_int8_t*)pa; + u_int8_t* b = (u_int8_t*)pb; + + for(int i = 0; i < size; i++){ + if(a[i] != b[i]){ + return false; + } + } + + return true; + } + + c2s2::c2s2() + { + srs_random_generate(random, 1504); + srs_random_generate(digest, 32); + } + + c2s2::~c2s2() + { + } + + void c2s2::dump(char* _c2s2) + { + memcpy(_c2s2, random, 1504); + memcpy(_c2s2 + 1504, digest, 32); + } + + void c2s2::parse(char* _c2s2) + { + memcpy(random, _c2s2, 1504); + memcpy(digest, _c2s2 + 1504, 32); + } + + int c2s2::c2_create(c1s1* s1) + { + int ret = ERROR_SUCCESS; + + char temp_key[OpensslHashSize]; + if ((ret = openssl_HMACsha256(s1->get_digest(), 32, SrsGenuineFPKey, 62, temp_key)) != ERROR_SUCCESS) { + srs_error("create c2 temp key failed. ret=%d", ret); + return ret; + } + srs_verbose("generate c2 temp key success."); + + char _digest[OpensslHashSize]; + if ((ret = openssl_HMACsha256(random, 1504, temp_key, 32, _digest)) != ERROR_SUCCESS) { + srs_error("create c2 digest failed. ret=%d", ret); + return ret; + } + srs_verbose("generate c2 digest success."); + + memcpy(digest, _digest, 32); + + return ret; + } + + int c2s2::c2_validate(c1s1* s1, bool& is_valid) + { + is_valid = false; + int ret = ERROR_SUCCESS; + + char temp_key[OpensslHashSize]; + if ((ret = openssl_HMACsha256(s1->get_digest(), 32, SrsGenuineFPKey, 62, temp_key)) != ERROR_SUCCESS) { + srs_error("create c2 temp key failed. ret=%d", ret); + return ret; + } + srs_verbose("generate c2 temp key success."); + + char _digest[OpensslHashSize]; + if ((ret = openssl_HMACsha256(random, 1504, temp_key, 32, _digest)) != ERROR_SUCCESS) { + srs_error("create c2 digest failed. ret=%d", ret); + return ret; + } + srs_verbose("generate c2 digest success."); + + is_valid = srs_bytes_equals(digest, _digest, 32); + + return ret; + } + + int c2s2::s2_create(c1s1* c1) + { + int ret = ERROR_SUCCESS; + + char temp_key[OpensslHashSize]; + if ((ret = openssl_HMACsha256(c1->get_digest(), 32, SrsGenuineFMSKey, 68, temp_key)) != ERROR_SUCCESS) { + srs_error("create s2 temp key failed. ret=%d", ret); + return ret; + } + srs_verbose("generate s2 temp key success."); + + char _digest[OpensslHashSize]; + if ((ret = openssl_HMACsha256(random, 1504, temp_key, 32, _digest)) != ERROR_SUCCESS) { + srs_error("create s2 digest failed. ret=%d", ret); + return ret; + } + srs_verbose("generate s2 digest success."); + + memcpy(digest, _digest, 32); + + return ret; + } + + int c2s2::s2_validate(c1s1* c1, bool& is_valid) + { + is_valid = false; + int ret = ERROR_SUCCESS; + + char temp_key[OpensslHashSize]; + if ((ret = openssl_HMACsha256(c1->get_digest(), 32, SrsGenuineFMSKey, 68, temp_key)) != ERROR_SUCCESS) { + srs_error("create s2 temp key failed. ret=%d", ret); + return ret; + } + srs_verbose("generate s2 temp key success."); + + char _digest[OpensslHashSize]; + if ((ret = openssl_HMACsha256(random, 1504, temp_key, 32, _digest)) != ERROR_SUCCESS) { + srs_error("create s2 digest failed. ret=%d", ret); + return ret; + } + srs_verbose("generate s2 digest success."); + + is_valid = srs_bytes_equals(digest, _digest, 32); + + return ret; + } + + // TODO: FIXME: move to the right position. + c1s1::c1s1() + { + schema = srs_schema_invalid; + } + c1s1::~c1s1() + { + destroy_blocks(); + } + + char* c1s1::get_digest() + { + srs_assert(schema != srs_schema_invalid); + + if (schema == srs_schema0) { + return block1.digest.digest; + } else { + return block0.digest.digest; + } + } + + void c1s1::dump(char* _c1s1) + { + srs_assert(schema != srs_schema_invalid); + + if (schema == srs_schema0) { + srs_schema0_copy_to(_c1s1, true, time, version, &block0.key, &block1.digest); + } else { + srs_schema1_copy_to(_c1s1, true, time, version, &block0.digest, &block1.key); + } + } + + int c1s1::parse(char* _c1s1, srs_schema_type _schema) + { + int ret = ERROR_SUCCESS; + + if (_schema == srs_schema_invalid) { + ret = ERROR_RTMP_CH_SCHEMA; + srs_error("parse c1 failed. invalid schema=%d, ret=%d", _schema, ret); + return ret; + } + + destroy_blocks(); + + time = *(int32_t*)_c1s1; + version = *(int32_t*)(_c1s1 + 4); // client c1 version + + if (_schema == srs_schema0) { + if ((ret = srs_key_block_parse(&block0.key, _c1s1 + 8)) != ERROR_SUCCESS) { + srs_error("parse the c1 key failed. ret=%d", ret); + return ret; + } + if ((ret = srs_digest_block_parse(&block1.digest, _c1s1 + 8 + 764)) != ERROR_SUCCESS) { + srs_error("parse the c1 digest failed. ret=%d", ret); + return ret; + } + srs_verbose("parse c1 key-digest success"); + } else if (_schema == srs_schema1) { + if ((ret = srs_digest_block_parse(&block0.digest, _c1s1 + 8)) != ERROR_SUCCESS) { + srs_error("parse the c1 key failed. ret=%d", ret); + return ret; + } + if ((ret = srs_key_block_parse(&block1.key, _c1s1 + 8 + 764)) != ERROR_SUCCESS) { + srs_error("parse the c1 digest failed. ret=%d", ret); + return ret; + } + srs_verbose("parse c1 digest-key success"); + } else { + ret = ERROR_RTMP_CH_SCHEMA; + srs_error("parse c1 failed. invalid schema=%d, ret=%d", _schema, ret); + return ret; + } + + schema = _schema; + + return ret; + } + + int c1s1::c1_create(srs_schema_type _schema) + { + int ret = ERROR_SUCCESS; + + if (_schema == srs_schema_invalid) { + ret = ERROR_RTMP_CH_SCHEMA; + srs_error("create c1 failed. invalid schema=%d, ret=%d", _schema, ret); + return ret; + } + + destroy_blocks(); + + time = ::time(NULL); + version = 0x02070080; // client c1 version + + if (_schema == srs_schema0) { + srs_key_block_init(&block0.key); + srs_digest_block_init(&block1.digest); + } else { + srs_digest_block_init(&block0.digest); + srs_key_block_init(&block1.key); + } + + schema = _schema; + + char* digest = NULL; + + if ((ret = calc_c1_digest(digest)) != ERROR_SUCCESS) { + srs_error("sign c1 error, failed to calc digest. ret=%d", ret); + return ret; + } + + srs_assert(digest != NULL); + SrsAutoFree(char, digest, true); + + if (schema == srs_schema0) { + memcpy(block1.digest.digest, digest, 32); + } else { + memcpy(block0.digest.digest, digest, 32); + } + + return ret; + } + + int c1s1::c1_validate_digest(bool& is_valid) + { + is_valid = false; + int ret = ERROR_SUCCESS; + + char* c1_digest = NULL; + + if ((ret = calc_c1_digest(c1_digest)) != ERROR_SUCCESS) { + srs_error("validate c1 error, failed to calc digest. ret=%d", ret); + return ret; + } + + srs_assert(c1_digest != NULL); + SrsAutoFree(char, c1_digest, true); + + if (schema == srs_schema0) { + is_valid = srs_bytes_equals(block1.digest.digest, c1_digest, 32); + } else { + is_valid = srs_bytes_equals(block0.digest.digest, c1_digest, 32); + } + + return ret; + } + + int c1s1::s1_validate_digest(bool& is_valid) + { + is_valid = false; + int ret = ERROR_SUCCESS; + + char* s1_digest = NULL; + + if ((ret = calc_s1_digest(s1_digest)) != ERROR_SUCCESS) { + srs_error("validate s1 error, failed to calc digest. ret=%d", ret); + return ret; + } + + srs_assert(s1_digest != NULL); + SrsAutoFree(char, s1_digest, true); + + if (schema == srs_schema0) { + is_valid = srs_bytes_equals(block1.digest.digest, s1_digest, 32); + } else { + is_valid = srs_bytes_equals(block0.digest.digest, s1_digest, 32); + } + + return ret; + } + + int c1s1::s1_create(c1s1* c1) + { + int ret = ERROR_SUCCESS; + + if (c1->schema == srs_schema_invalid) { + ret = ERROR_RTMP_CH_SCHEMA; + srs_error("create s1 failed. invalid schema=%d, ret=%d", c1->schema, ret); + return ret; + } + + destroy_blocks(); + schema = c1->schema; + + time = ::time(NULL); + version = 0x01000504; // server s1 version + + if (schema == srs_schema0) { + srs_key_block_init(&block0.key); + srs_digest_block_init(&block1.digest); + } else { + srs_digest_block_init(&block0.digest); + srs_key_block_init(&block1.key); + } + + if (schema == srs_schema0) { + if ((ret = openssl_generate_key(c1->block0.key.key, block0.key.key, 128)) != ERROR_SUCCESS) { + srs_error("calc s1 key failed. ret=%d", ret); + return ret; + } + } else { + if ((ret = openssl_generate_key(c1->block1.key.key, block1.key.key, 128)) != ERROR_SUCCESS) { + srs_error("calc s1 key failed. ret=%d", ret); + return ret; + } + } + srs_verbose("calc s1 key success."); + + char* s1_digest = NULL; + if ((ret = calc_s1_digest(s1_digest)) != ERROR_SUCCESS) { + srs_error("calc s1 digest failed. ret=%d", ret); + return ret; + } + srs_verbose("calc s1 digest success."); + + srs_assert(s1_digest != NULL); + SrsAutoFree(char, s1_digest, true); + + if (schema == srs_schema0) { + memcpy(block1.digest.digest, s1_digest, 32); + } else { + memcpy(block0.digest.digest, s1_digest, 32); + } + srs_verbose("copy s1 key success."); + + return ret; + } + + int c1s1::calc_s1_digest(char*& digest) + { + int ret = ERROR_SUCCESS; + + srs_assert(schema == srs_schema0 || schema == srs_schema1); + + char* c1s1_joined_bytes = NULL; + + if (schema == srs_schema0) { + c1s1_joined_bytes = srs_bytes_join_schema0(time, version, &block0.key, &block1.digest); + } else { + c1s1_joined_bytes = srs_bytes_join_schema1(time, version, &block0.digest, &block1.key); + } + + srs_assert(c1s1_joined_bytes != NULL); + SrsAutoFree(char, c1s1_joined_bytes, true); + + digest = new char[OpensslHashSize]; + if ((ret = openssl_HMACsha256(c1s1_joined_bytes, 1536 - 32, SrsGenuineFMSKey, 36, digest)) != ERROR_SUCCESS) { + srs_error("calc digest for s1 failed. ret=%d", ret); + return ret; + } + srs_verbose("digest calculated for s1"); + + return ret; + } + + int c1s1::calc_c1_digest(char*& digest) + { + int ret = ERROR_SUCCESS; + + srs_assert(schema == srs_schema0 || schema == srs_schema1); + + char* c1s1_joined_bytes = NULL; + + if (schema == srs_schema0) { + c1s1_joined_bytes = srs_bytes_join_schema0(time, version, &block0.key, &block1.digest); + } else { + c1s1_joined_bytes = srs_bytes_join_schema1(time, version, &block0.digest, &block1.key); + } + + srs_assert(c1s1_joined_bytes != NULL); + SrsAutoFree(char, c1s1_joined_bytes, true); + + digest = new char[OpensslHashSize]; + if ((ret = openssl_HMACsha256(c1s1_joined_bytes, 1536 - 32, SrsGenuineFPKey, 30, digest)) != ERROR_SUCCESS) { + srs_error("calc digest for c1 failed. ret=%d", ret); + return ret; + } + srs_verbose("digest calculated for c1"); + + return ret; + } + + void c1s1::destroy_blocks() + { + if (schema == srs_schema_invalid) { + return; + } + + if (schema == srs_schema0) { + srs_key_block_free(&block0.key); + srs_digest_block_free(&block1.digest); + } else { + srs_digest_block_free(&block0.digest); + srs_key_block_free(&block1.key); + } } } @@ -1144,13 +1156,10 @@ int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrs c2s2 c2; c2.parse(hs_bytes->c2); srs_verbose("complex handshake read c2 success."); + // verify c2 - if ((ret = c2.c2_validate(&s1, is_valid)) != ERROR_SUCCESS || !is_valid) { - ret = ERROR_RTMP_HANDSHAKE; - srs_trace("verify c2 failed. ret=%d", ret); - return ret; - } - srs_verbose("verify c2 success."); + // never verify c2, for ffmpeg will failed. + // it's ok for flash. srs_trace("comple handshake with client success"); diff --git a/trunk/src/rtmp/srs_protocol_handshake.hpp b/trunk/src/rtmp/srs_protocol_handshake.hpp index 4ac93e624..8a5ab77b7 100644 --- a/trunk/src/rtmp/srs_protocol_handshake.hpp +++ b/trunk/src/rtmp/srs_protocol_handshake.hpp @@ -97,6 +97,78 @@ namespace srs int random1_size; }; + // the digest key generate size. + #define OpensslHashSize 512 + extern u_int8_t SrsGenuineFMSKey[]; + extern u_int8_t SrsGenuineFPKey[]; + int openssl_HMACsha256(const void* data, int data_size, const void* key, int key_size, void* digest); + int openssl_generate_key(char* _private_key, char* _public_key, int32_t size); + + // calc the offset of key, + // the key->offset cannot be used as the offset of key. + int srs_key_block_get_offset(key_block* key); + + // create new key block data. + // if created, user must free it by srs_key_block_free + void srs_key_block_init(key_block* key); + + // parse key block from c1s1. + // if created, user must free it by srs_key_block_free + // @c1s1_key_bytes the key start bytes, maybe c1s1 or c1s1+764 + int srs_key_block_parse(key_block* key, char* c1s1_key_bytes); + + // free the block data create by + // srs_key_block_init or srs_key_block_parse + void srs_key_block_free(key_block* key); + + // calc the offset of digest, + // the key->offset cannot be used as the offset of digest. + int srs_digest_block_get_offset(digest_block* digest); + + // create new digest block data. + // if created, user must free it by srs_digest_block_free + void srs_digest_block_init(digest_block* digest); + + // parse digest block from c1s1. + // if created, user must free it by srs_digest_block_free + // @c1s1_digest_bytes the digest start bytes, maybe c1s1 or c1s1+764 + int srs_digest_block_parse(digest_block* digest, char* c1s1_digest_bytes); + + // free the block data create by + // srs_digest_block_init or srs_digest_block_parse + void srs_digest_block_free(digest_block* digest); + + /** + * copy whole c1s1 to bytes. + */ + void srs_schema0_copy_to(char* bytes, bool with_digest, + int32_t time, int32_t version, key_block* key, digest_block* digest); + void srs_schema1_copy_to(char* bytes, bool with_digest, + int32_t time, int32_t version, digest_block* digest, key_block* key); + + /** + * c1s1 is splited by digest: + * c1s1-part1: n bytes (time, version, key and digest-part1). + * digest-data: 32bytes + * c1s1-part2: (1536-n-32)bytes (digest-part2) + * @return a new allocated bytes, user must free it. + */ + char* srs_bytes_join_schema0(int32_t time, int32_t version, key_block* key, digest_block* digest); + + /** + * c1s1 is splited by digest: + * c1s1-part1: n bytes (time, version and digest-part1). + * digest-data: 32bytes + * c1s1-part2: (1536-n-32)bytes (digest-part2 and key) + * @return a new allocated bytes, user must free it. + */ + char* srs_bytes_join_schema1(int32_t time, int32_t version, digest_block* digest, key_block* key); + + /** + * compare the memory in bytes. + */ + bool srs_bytes_equals(void* pa, void* pb, int size); + /** * c1s1 schema0 * time: 4bytes @@ -236,35 +308,6 @@ namespace srs */ virtual int s2_validate(c1s1* c1, bool& is_valid); }; - - /** - * compare the memory in bytes. - */ - bool srs_bytes_equals(void* pa, void* pb, int size); - - /** - * c1s1 is splited by digest: - * c1s1-part1: n bytes (time, version, key and digest-part1). - * digest-data: 32bytes - * c1s1-part2: (1536-n-32)bytes (digest-part2) - * @return a new allocated bytes, user must free it. - */ - char* srs_bytes_join_schema0(int32_t time, int32_t version, key_block* key, digest_block* digest); - - /** - * c1s1 is splited by digest: - * c1s1-part1: n bytes (time, version and digest-part1). - * digest-data: 32bytes - * c1s1-part2: (1536-n-32)bytes (digest-part2 and key) - * @return a new allocated bytes, user must free it. - */ - char* srs_bytes_join_schema1(int32_t time, int32_t version, digest_block* digest, key_block* key); - - // the digest key generate size. - #define OpensslHashSize 512 - extern u_int8_t SrsGenuineFMSKey[]; - extern u_int8_t SrsGenuineFPKey[]; - int openssl_HMACsha256(const void* data, int data_size, const void* key, int key_size, void* digest); } #endif diff --git a/trunk/src/utest/srs_utest_handshake.cpp b/trunk/src/utest/srs_utest_handshake.cpp index 2e005b512..bf0f7e38b 100644 --- a/trunk/src/utest/srs_utest_handshake.cpp +++ b/trunk/src/utest/srs_utest_handshake.cpp @@ -172,7 +172,7 @@ VOID TEST(HandshakeTest, VerifyFPC0C1) 0xb1, 0xb5, 0xbc, 0xa6, 0xd6, 0xd6, 0x1d, 0xce, 0x93, 0x78, 0xb3, 0xec, 0xa8, 0x64, 0x19, 0x13 }; EXPECT_TRUE(srs_bytes_equals(c1.block1.digest.digest, digest, 32)); -} +} VOID TEST(HandshakeTest, SimpleHandshake) { @@ -260,3 +260,8 @@ VOID TEST(HandshakeTest, ComplexHandshake) ASSERT_TRUE(is_valid); } } + +VOID TEST(HandshakeTest, BytesEqual) +{ + //srs_bytes_equals +}