mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
change to 0.9.19, verify the s1/s2/c2, refine the handshake.
This commit is contained in:
parent
152d3539d8
commit
841f0f8899
8 changed files with 349 additions and 118 deletions
|
@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// current release version
|
// current release version
|
||||||
#define VERSION_MAJOR "0"
|
#define VERSION_MAJOR "0"
|
||||||
#define VERSION_MINOR "9"
|
#define VERSION_MINOR "9"
|
||||||
#define VERSION_REVISION "18"
|
#define VERSION_REVISION "19"
|
||||||
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
|
#define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION
|
||||||
// server info.
|
// server info.
|
||||||
#define RTMP_SIG_SRS_KEY "srs"
|
#define RTMP_SIG_SRS_KEY "srs"
|
||||||
|
|
|
@ -34,7 +34,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
* auto free the instance in the current scope.
|
* auto free the instance in the current scope.
|
||||||
*/
|
*/
|
||||||
#define SrsAutoFree(className, instance, is_array) \
|
#define SrsAutoFree(className, instance, is_array) \
|
||||||
__SrsAutoFree<className> _auto_free_##instance(&instance, is_array)
|
__SrsAutoFree<className> _auto_free_##instance((className**)&instance, is_array)
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
class __SrsAutoFree
|
class __SrsAutoFree
|
||||||
|
|
|
@ -24,28 +24,16 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
#include <srs_protocol_handshake.hpp>
|
#include <srs_protocol_handshake.hpp>
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include <srs_core_autofree.hpp>
|
#include <srs_core_autofree.hpp>
|
||||||
#include <srs_kernel_error.hpp>
|
#include <srs_kernel_error.hpp>
|
||||||
#include <srs_kernel_log.hpp>
|
#include <srs_kernel_log.hpp>
|
||||||
#include <srs_protocol_io.hpp>
|
#include <srs_protocol_io.hpp>
|
||||||
|
#include <srs_protocol_utility.hpp>
|
||||||
|
#include <srs_protocol_rtmp.hpp>
|
||||||
|
|
||||||
using namespace srs;
|
using namespace srs;
|
||||||
|
|
||||||
void srs_random_generate(char* bytes, int size)
|
|
||||||
{
|
|
||||||
static char cdata[] = {
|
|
||||||
0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x72, 0x74, 0x6d, 0x70, 0x2d, 0x73, 0x65,
|
|
||||||
0x72, 0x76, 0x65, 0x72, 0x2d, 0x77, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x2d, 0x77, 0x69,
|
|
||||||
0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x40, 0x31, 0x32, 0x36,
|
|
||||||
0x2e, 0x63, 0x6f, 0x6d
|
|
||||||
};
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
bytes[i] = cdata[rand() % (sizeof(cdata) - 1)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SRS_SSL
|
#ifdef SRS_SSL
|
||||||
|
|
||||||
// 68bytes FMS key which is used to sign the sever packet.
|
// 68bytes FMS key which is used to sign the sever packet.
|
||||||
|
@ -569,6 +557,12 @@ void c2s2::dump(char* _c2s2)
|
||||||
memcpy(_c2s2 + 1504, digest, 32);
|
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 c2s2::c2_create(c1s1* s1)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
@ -592,6 +586,30 @@ int c2s2::c2_create(c1s1* s1)
|
||||||
return ret;
|
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 c2s2::s2_create(c1s1* c1)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
@ -615,6 +633,30 @@ int c2s2::s2_create(c1s1* c1)
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
c1s1::c1s1()
|
c1s1::c1s1()
|
||||||
{
|
{
|
||||||
schema = srs_schema_invalid;
|
schema = srs_schema_invalid;
|
||||||
|
@ -738,6 +780,7 @@ int c1s1::c1_parse(char* _c1s1, srs_schema_type _schema)
|
||||||
|
|
||||||
int c1s1::c1_validate_digest(bool& is_valid)
|
int c1s1::c1_validate_digest(bool& is_valid)
|
||||||
{
|
{
|
||||||
|
is_valid = false;
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
char* c1_digest = NULL;
|
char* c1_digest = NULL;
|
||||||
|
@ -761,6 +804,7 @@ int c1s1::c1_validate_digest(bool& is_valid)
|
||||||
|
|
||||||
int c1s1::s1_validate_digest(bool& is_valid)
|
int c1s1::s1_validate_digest(bool& is_valid)
|
||||||
{
|
{
|
||||||
|
is_valid = false;
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
char* s1_digest = NULL;
|
char* s1_digest = NULL;
|
||||||
|
@ -918,125 +962,85 @@ SrsSimpleHandshake::~SrsSimpleHandshake()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsSimpleHandshake::handshake_with_client(ISrsProtocolReaderWriter* skt, SrsComplexHandshake* complex_hs)
|
int SrsSimpleHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
ssize_t nsize;
|
ssize_t nsize;
|
||||||
|
|
||||||
char* c0c1 = new char[1537];
|
if ((ret = hs_bytes->read_c0c1(io)) != ERROR_SUCCESS) {
|
||||||
SrsAutoFree(char, c0c1, true);
|
|
||||||
if ((ret = skt->read_fully(c0c1, 1537, &nsize)) != ERROR_SUCCESS) {
|
|
||||||
srs_warn("read c0c1 failed. ret=%d", ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("read c0c1 success.");
|
|
||||||
|
|
||||||
// plain text required.
|
// plain text required.
|
||||||
if (c0c1[0] != 0x03) {
|
if (hs_bytes->c0c1[0] != 0x03) {
|
||||||
ret = ERROR_RTMP_PLAIN_REQUIRED;
|
ret = ERROR_RTMP_PLAIN_REQUIRED;
|
||||||
srs_warn("only support rtmp plain text. ret=%d", ret);
|
srs_warn("only support rtmp plain text. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("check c0 success, required plain text.");
|
srs_verbose("check c0 success, required plain text.");
|
||||||
|
|
||||||
// try complex handshake
|
if ((ret = hs_bytes->create_s0s1s2()) != ERROR_SUCCESS) {
|
||||||
if (complex_hs) {
|
return ret;
|
||||||
ret = complex_hs->handshake_with_client(skt, c0c1 + 1);
|
|
||||||
if (ret == ERROR_SUCCESS) {
|
|
||||||
srs_trace("complex handshake success.");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (ret != ERROR_RTMP_TRY_SIMPLE_HS) {
|
|
||||||
srs_error("complex handshake failed. ret=%d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
srs_info("rollback complex to simple handshake. ret=%d", ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char* s0s1s2 = new char[3073];
|
|
||||||
srs_random_generate(s0s1s2, 3073);
|
|
||||||
SrsAutoFree(char, s0s1s2, true);
|
|
||||||
// plain text required.
|
// plain text required.
|
||||||
s0s1s2[0] = 0x03;
|
hs_bytes->s0s1s2[0] = 0x03;
|
||||||
if ((ret = skt->write(s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) {
|
if ((ret = io->write(hs_bytes->s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) {
|
||||||
srs_warn("simple handshake send s0s1s2 failed. ret=%d", ret);
|
srs_warn("simple handshake send s0s1s2 failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("simple handshake send s0s1s2 success.");
|
srs_verbose("simple handshake send s0s1s2 success.");
|
||||||
|
|
||||||
char* c2 = new char[1536];
|
if ((ret = hs_bytes->read_c2(io)) != ERROR_SUCCESS) {
|
||||||
SrsAutoFree(char, c2, true);
|
|
||||||
if ((ret = skt->read_fully(c2, 1536, &nsize)) != ERROR_SUCCESS) {
|
|
||||||
srs_warn("simple handshake read c2 failed. ret=%d", ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("simple handshake read c2 success.");
|
|
||||||
|
|
||||||
srs_trace("simple handshake success.");
|
srs_trace("simple handshake with client success.");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsSimpleHandshake::handshake_with_server(ISrsProtocolReaderWriter* skt, SrsComplexHandshake* complex_hs)
|
int SrsSimpleHandshake::handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
// try complex handshake
|
|
||||||
if (complex_hs) {
|
|
||||||
ret = complex_hs->handshake_with_server(skt);
|
|
||||||
if (ret == ERROR_SUCCESS) {
|
|
||||||
srs_trace("complex handshake success.");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (ret != ERROR_RTMP_TRY_SIMPLE_HS) {
|
|
||||||
srs_error("complex handshake failed. ret=%d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
srs_info("rollback complex to simple handshake. ret=%d", ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
// simple handshake
|
|
||||||
ssize_t nsize;
|
ssize_t nsize;
|
||||||
|
|
||||||
char* c0c1 = new char[1537];
|
// simple handshake
|
||||||
SrsAutoFree(char, c0c1, true);
|
if ((ret = hs_bytes->create_c0c1()) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
srs_random_generate(c0c1, 1537);
|
}
|
||||||
// plain text required.
|
// plain text required.
|
||||||
c0c1[0] = 0x03;
|
hs_bytes->c0c1[0] = 0x03;
|
||||||
|
|
||||||
if ((ret = skt->write(c0c1, 1537, &nsize)) != ERROR_SUCCESS) {
|
if ((ret = io->write(hs_bytes->c0c1, 1537, &nsize)) != ERROR_SUCCESS) {
|
||||||
srs_warn("write c0c1 failed. ret=%d", ret);
|
srs_warn("write c0c1 failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("write c0c1 success.");
|
srs_verbose("write c0c1 success.");
|
||||||
|
|
||||||
char* s0s1s2 = new char[3073];
|
if ((ret = hs_bytes->read_s0s1s2(io)) != ERROR_SUCCESS) {
|
||||||
SrsAutoFree(char, s0s1s2, true);
|
|
||||||
if ((ret = skt->read_fully(s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) {
|
|
||||||
srs_warn("simple handshake recv s0s1s2 failed. ret=%d", ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("simple handshake recv s0s1s2 success.");
|
|
||||||
|
|
||||||
// plain text required.
|
// plain text required.
|
||||||
if (s0s1s2[0] != 0x03) {
|
if (hs_bytes->s0s1s2[0] != 0x03) {
|
||||||
ret = ERROR_RTMP_HANDSHAKE;
|
ret = ERROR_RTMP_HANDSHAKE;
|
||||||
srs_warn("handshake failed, plain text required. ret=%d", ret);
|
srs_warn("handshake failed, plain text required. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* c2 = new char[1536];
|
if ((ret = hs_bytes->create_c2()) != ERROR_SUCCESS) {
|
||||||
SrsAutoFree(char, c2, true);
|
return ret;
|
||||||
srs_random_generate(c2, 1536);
|
}
|
||||||
if ((ret = skt->write(c2, 1536, &nsize)) != ERROR_SUCCESS) {
|
if ((ret = io->write(hs_bytes->c2, 1536, &nsize)) != ERROR_SUCCESS) {
|
||||||
srs_warn("simple handshake write c2 failed. ret=%d", ret);
|
srs_warn("simple handshake write c2 failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("simple handshake write c2 success.");
|
srs_verbose("simple handshake write c2 success.");
|
||||||
|
|
||||||
srs_trace("simple handshake success.");
|
srs_trace("simple handshake with server success.");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1050,36 +1054,33 @@ SrsComplexHandshake::~SrsComplexHandshake()
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SRS_SSL
|
#ifndef SRS_SSL
|
||||||
int SrsComplexHandshake::handshake_with_client(ISrsProtocolReaderWriter* /*skt*/, char* /*_c1*/)
|
int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* /*hs_bytes*/, ISrsProtocolReaderWriter* /*io*/)
|
||||||
{
|
{
|
||||||
srs_trace("directly use simple handshake for ssl disabled.");
|
srs_trace("directly use simple handshake for ssl disabled.");
|
||||||
return ERROR_RTMP_TRY_SIMPLE_HS;
|
return ERROR_RTMP_TRY_SIMPLE_HS;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int SrsComplexHandshake::handshake_with_client(ISrsProtocolReaderWriter* skt, char* _c1)
|
int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
ssize_t nsize;
|
ssize_t nsize;
|
||||||
|
|
||||||
static bool _random_initialized = false;
|
if ((ret = hs_bytes->read_c0c1(io)) != ERROR_SUCCESS) {
|
||||||
if (!_random_initialized) {
|
return ret;
|
||||||
srand(0);
|
|
||||||
_random_initialized = true;
|
|
||||||
srs_trace("srand initialized the random.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode c1
|
// decode c1
|
||||||
c1s1 c1;
|
c1s1 c1;
|
||||||
// try schema0.
|
// try schema0.
|
||||||
if ((ret = c1.c1_parse(_c1, srs_schema0)) != ERROR_SUCCESS) {
|
if ((ret = c1.c1_parse(hs_bytes->c0c1 + 1, srs_schema0)) != ERROR_SUCCESS) {
|
||||||
srs_error("parse c1 schema%d error. ret=%d", srs_schema0, ret);
|
srs_error("parse c1 schema%d error. ret=%d", srs_schema0, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
// try schema1
|
// try schema1
|
||||||
bool is_valid = false;
|
bool is_valid = false;
|
||||||
if ((ret = c1.c1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
|
if ((ret = c1.c1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
|
||||||
if ((ret = c1.c1_parse(_c1, srs_schema1)) != ERROR_SUCCESS) {
|
if ((ret = c1.c1_parse(hs_bytes->c0c1 + 1, srs_schema1)) != ERROR_SUCCESS) {
|
||||||
srs_error("parse c1 schema%d error. ret=%d", srs_schema1, ret);
|
srs_error("parse c1 schema%d error. ret=%d", srs_schema1, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1102,10 +1103,10 @@ int SrsComplexHandshake::handshake_with_client(ISrsProtocolReaderWriter* skt, ch
|
||||||
// verify s1
|
// verify s1
|
||||||
if ((ret = s1.s1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
|
if ((ret = s1.s1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
|
||||||
ret = ERROR_RTMP_TRY_SIMPLE_HS;
|
ret = ERROR_RTMP_TRY_SIMPLE_HS;
|
||||||
srs_info("valid s1 failed, try simple handshake. ret=%d", ret);
|
srs_info("verify s1 failed, try simple handshake. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("verify s1 from c1 success.");
|
srs_verbose("verify s1 success.");
|
||||||
|
|
||||||
c2s2 s2;
|
c2s2 s2;
|
||||||
if ((ret = s2.s2_create(&c1)) != ERROR_SUCCESS) {
|
if ((ret = s2.s2_create(&c1)) != ERROR_SUCCESS) {
|
||||||
|
@ -1113,40 +1114,56 @@ int SrsComplexHandshake::handshake_with_client(ISrsProtocolReaderWriter* skt, ch
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("create s2 from c1 success.");
|
srs_verbose("create s2 from c1 success.");
|
||||||
|
// verify s2
|
||||||
|
if ((ret = s2.s2_validate(&c1, is_valid)) != ERROR_SUCCESS || !is_valid) {
|
||||||
|
ret = ERROR_RTMP_TRY_SIMPLE_HS;
|
||||||
|
srs_info("verify s2 failed, try simple handshake. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
srs_verbose("verify s2 success.");
|
||||||
|
|
||||||
// sendout s0s1s2
|
// sendout s0s1s2
|
||||||
char* s0s1s2 = new char[3073];
|
if ((ret = hs_bytes->create_s0s1s2()) != ERROR_SUCCESS) {
|
||||||
SrsAutoFree(char, s0s1s2, true);
|
return ret;
|
||||||
|
}
|
||||||
// plain text required.
|
// plain text required.
|
||||||
s0s1s2[0] = 0x03;
|
hs_bytes->s0s1s2[0] = 0x03;
|
||||||
s1.dump(s0s1s2 + 1);
|
s1.dump(hs_bytes->s0s1s2 + 1);
|
||||||
s2.dump(s0s1s2 + 1537);
|
s2.dump(hs_bytes->s0s1s2 + 1537);
|
||||||
if ((ret = skt->write(s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) {
|
if ((ret = io->write(hs_bytes->s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) {
|
||||||
srs_warn("complex handshake send s0s1s2 failed. ret=%d", ret);
|
srs_warn("complex handshake send s0s1s2 failed. ret=%d", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
srs_verbose("complex handshake send s0s1s2 success.");
|
srs_verbose("complex handshake send s0s1s2 success.");
|
||||||
|
|
||||||
// recv c2
|
// recv c2
|
||||||
char* c2 = new char[1536];
|
if ((ret = hs_bytes->read_c2(io)) != ERROR_SUCCESS) {
|
||||||
SrsAutoFree(char, c2, true);
|
|
||||||
if ((ret = skt->read_fully(c2, 1536, &nsize)) != ERROR_SUCCESS) {
|
|
||||||
srs_warn("complex handshake read c2 failed. ret=%d", ret);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
c2s2 c2;
|
||||||
|
c2.parse(hs_bytes->c2);
|
||||||
srs_verbose("complex handshake read c2 success.");
|
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.");
|
||||||
|
|
||||||
|
srs_trace("comple handshake with client success");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SRS_SSL
|
#ifndef SRS_SSL
|
||||||
int SrsComplexHandshake::handshake_with_server(ISrsProtocolReaderWriter* /*skt*/)
|
int SrsComplexHandshake::handshake_with_server(SrsHandshakeBytes* /*hs_bytes*/, ISrsProtocolReaderWriter* /*io*/)
|
||||||
{
|
{
|
||||||
return ERROR_RTMP_TRY_SIMPLE_HS;
|
return ERROR_RTMP_TRY_SIMPLE_HS;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int SrsComplexHandshake::handshake_with_server(ISrsProtocolReaderWriter* /*skt*/)
|
int SrsComplexHandshake::handshake_with_server(SrsHandshakeBytes* /*hs_bytes*/, ISrsProtocolReaderWriter* /*io*/)
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
class ISrsProtocolReaderWriter;
|
class ISrsProtocolReaderWriter;
|
||||||
class SrsComplexHandshake;
|
class SrsComplexHandshake;
|
||||||
|
class SrsHandshakeBytes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* try complex handshake, if failed, fallback to simple handshake.
|
* try complex handshake, if failed, fallback to simple handshake.
|
||||||
|
@ -44,12 +45,9 @@ public:
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* simple handshake.
|
* simple handshake.
|
||||||
* @param complex_hs, try complex handshake first,
|
|
||||||
* if NULL, use simple handshake.
|
|
||||||
* if failed, rollback to simple handshake.
|
|
||||||
*/
|
*/
|
||||||
virtual int handshake_with_client(ISrsProtocolReaderWriter* io, SrsComplexHandshake* complex_hs);
|
virtual int handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io);
|
||||||
virtual int handshake_with_server(ISrsProtocolReaderWriter* io, SrsComplexHandshake* complex_hs);
|
virtual int handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,15 +63,13 @@ public:
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* complex hanshake.
|
* complex hanshake.
|
||||||
* @_c1, size of c1 must be 1536.
|
|
||||||
* @remark, user must free the c1.
|
|
||||||
* @return user must:
|
* @return user must:
|
||||||
* continue connect app if success,
|
* continue connect app if success,
|
||||||
* try simple handshake if error is ERROR_RTMP_TRY_SIMPLE_HS,
|
* try simple handshake if error is ERROR_RTMP_TRY_SIMPLE_HS,
|
||||||
* otherwise, disconnect
|
* otherwise, disconnect
|
||||||
*/
|
*/
|
||||||
virtual int handshake_with_client(ISrsProtocolReaderWriter* io, char* _c1);
|
virtual int handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io);
|
||||||
virtual int handshake_with_server(ISrsProtocolReaderWriter* io);
|
virtual int handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io);
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace srs
|
namespace srs
|
||||||
|
@ -241,6 +237,10 @@ namespace srs
|
||||||
* copy to bytes.
|
* copy to bytes.
|
||||||
*/
|
*/
|
||||||
virtual void dump(char* _c2s2);
|
virtual void dump(char* _c2s2);
|
||||||
|
/**
|
||||||
|
* parse the c2s2
|
||||||
|
*/
|
||||||
|
virtual void parse(char* _c2s2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create c2.
|
* create c2.
|
||||||
|
@ -252,6 +252,11 @@ namespace srs
|
||||||
*/
|
*/
|
||||||
virtual int c2_create(c1s1* s1);
|
virtual int c2_create(c1s1* s1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate the c2 from client.
|
||||||
|
*/
|
||||||
|
virtual int c2_validate(c1s1* s1, bool& is_valid);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create s2.
|
* create s2.
|
||||||
* random fill c2s2 1536 bytes
|
* random fill c2s2 1536 bytes
|
||||||
|
@ -261,6 +266,11 @@ namespace srs
|
||||||
* s2-digest-data = HMACsha256(s2-random-data, temp-key, 32)
|
* s2-digest-data = HMACsha256(s2-random-data, temp-key, 32)
|
||||||
*/
|
*/
|
||||||
virtual int s2_create(c1s1* c1);
|
virtual int s2_create(c1s1* c1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validate the s2 from server.
|
||||||
|
*/
|
||||||
|
virtual int s2_validate(c1s1* c1, bool& is_valid);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -187,15 +187,131 @@ string srs_client_type_string(SrsClientType type)
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SrsHandshakeBytes::SrsHandshakeBytes()
|
||||||
|
{
|
||||||
|
c0c1 = s0s1s2 = c2 = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SrsHandshakeBytes::~SrsHandshakeBytes()
|
||||||
|
{
|
||||||
|
srs_freepa(c0c1);
|
||||||
|
srs_freepa(s0s1s2);
|
||||||
|
srs_freepa(c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHandshakeBytes::read_c0c1(ISrsProtocolReaderWriter* io)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if (c0c1) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t nsize;
|
||||||
|
|
||||||
|
c0c1 = new char[1537];
|
||||||
|
if ((ret = io->read_fully(c0c1, 1537, &nsize)) != ERROR_SUCCESS) {
|
||||||
|
srs_warn("read c0c1 failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
srs_verbose("read c0c1 success.");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHandshakeBytes::read_s0s1s2(ISrsProtocolReaderWriter* io)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if (s0s1s2) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t nsize;
|
||||||
|
|
||||||
|
c0c1 = new char[3073];
|
||||||
|
if ((ret = io->read_fully(s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) {
|
||||||
|
srs_warn("read s0s1s2 failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
srs_verbose("read s0s1s2 success.");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHandshakeBytes::read_c2(ISrsProtocolReaderWriter* io)
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if (c2) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t nsize;
|
||||||
|
|
||||||
|
c2 = new char[1536];
|
||||||
|
if ((ret = io->read_fully(c2, 1536, &nsize)) != ERROR_SUCCESS) {
|
||||||
|
srs_warn("read c2 failed. ret=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
srs_verbose("read c2 success.");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHandshakeBytes::create_c0c1()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if (c0c1) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
c0c1 = new char[1537];
|
||||||
|
srs_random_generate(c0c1, 1537);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHandshakeBytes::create_s0s1s2()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if (s0s1s2) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
s0s1s2 = new char[3073];
|
||||||
|
srs_random_generate(s0s1s2, 3073);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SrsHandshakeBytes::create_c2()
|
||||||
|
{
|
||||||
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
if (c2) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
c2 = new char[1536];
|
||||||
|
srs_random_generate(c2, 1536);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
SrsRtmpClient::SrsRtmpClient(ISrsProtocolReaderWriter* skt)
|
SrsRtmpClient::SrsRtmpClient(ISrsProtocolReaderWriter* skt)
|
||||||
{
|
{
|
||||||
io = skt;
|
io = skt;
|
||||||
protocol = new SrsProtocol(skt);
|
protocol = new SrsProtocol(skt);
|
||||||
|
hs_bytes = new SrsHandshakeBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtmpClient::~SrsRtmpClient()
|
SrsRtmpClient::~SrsRtmpClient()
|
||||||
{
|
{
|
||||||
srs_freep(protocol);
|
srs_freep(protocol);
|
||||||
|
srs_freep(hs_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsRtmpClient::set_recv_timeout(int64_t timeout_us)
|
void SrsRtmpClient::set_recv_timeout(int64_t timeout_us)
|
||||||
|
@ -242,12 +358,21 @@ int SrsRtmpClient::handshake()
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
srs_assert(hs_bytes);
|
||||||
|
|
||||||
SrsComplexHandshake complex_hs;
|
SrsComplexHandshake complex_hs;
|
||||||
SrsSimpleHandshake simple_hs;
|
if ((ret = complex_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) {
|
||||||
if ((ret = simple_hs.handshake_with_server(io, &complex_hs)) != ERROR_SUCCESS) {
|
if (ret == ERROR_RTMP_TRY_SIMPLE_HS) {
|
||||||
|
SrsSimpleHandshake simple_hs;
|
||||||
|
if ((ret = simple_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srs_freep(hs_bytes);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,18 +380,32 @@ int SrsRtmpClient::simple_handshake()
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
srs_assert(hs_bytes);
|
||||||
|
|
||||||
SrsSimpleHandshake simple_hs;
|
SrsSimpleHandshake simple_hs;
|
||||||
if ((ret = simple_hs.handshake_with_server(io, NULL)) != ERROR_SUCCESS) {
|
if ((ret = simple_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srs_freep(hs_bytes);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsRtmpClient::complex_handshake()
|
int SrsRtmpClient::complex_handshake()
|
||||||
{
|
{
|
||||||
// TODO: FIXME: only use complex handshake.
|
int ret = ERROR_SUCCESS;
|
||||||
return handshake();
|
|
||||||
|
srs_assert(hs_bytes);
|
||||||
|
|
||||||
|
SrsComplexHandshake complex_hs;
|
||||||
|
if ((ret = complex_hs.handshake_with_server(hs_bytes, io)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
srs_freep(hs_bytes);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SrsRtmpClient::connect_app(string app, string tc_url)
|
int SrsRtmpClient::connect_app(string app, string tc_url)
|
||||||
|
@ -537,11 +676,13 @@ SrsRtmpServer::SrsRtmpServer(ISrsProtocolReaderWriter* skt)
|
||||||
{
|
{
|
||||||
io = skt;
|
io = skt;
|
||||||
protocol = new SrsProtocol(skt);
|
protocol = new SrsProtocol(skt);
|
||||||
|
hs_bytes = new SrsHandshakeBytes();
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsRtmpServer::~SrsRtmpServer()
|
SrsRtmpServer::~SrsRtmpServer()
|
||||||
{
|
{
|
||||||
srs_freep(protocol);
|
srs_freep(protocol);
|
||||||
|
srs_freep(hs_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsProtocol* SrsRtmpServer::get_protocol()
|
SrsProtocol* SrsRtmpServer::get_protocol()
|
||||||
|
@ -603,12 +744,21 @@ int SrsRtmpServer::handshake()
|
||||||
{
|
{
|
||||||
int ret = ERROR_SUCCESS;
|
int ret = ERROR_SUCCESS;
|
||||||
|
|
||||||
|
srs_assert(hs_bytes);
|
||||||
|
|
||||||
SrsComplexHandshake complex_hs;
|
SrsComplexHandshake complex_hs;
|
||||||
SrsSimpleHandshake simple_hs;
|
if ((ret = complex_hs.handshake_with_client(hs_bytes, io)) != ERROR_SUCCESS) {
|
||||||
if ((ret = simple_hs.handshake_with_client(io, &complex_hs)) != ERROR_SUCCESS) {
|
if (ret == ERROR_RTMP_TRY_SIMPLE_HS) {
|
||||||
|
SrsSimpleHandshake simple_hs;
|
||||||
|
if ((ret = simple_hs.handshake_with_client(hs_bytes, io)) != ERROR_SUCCESS) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srs_freep(hs_bytes);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,11 +108,38 @@ enum SrsClientType
|
||||||
};
|
};
|
||||||
std::string srs_client_type_string(SrsClientType type);
|
std::string srs_client_type_string(SrsClientType type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* store the handshake bytes,
|
||||||
|
* for smart switch between complex and simple handshake.
|
||||||
|
*/
|
||||||
|
class SrsHandshakeBytes
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// [1+1536]
|
||||||
|
char* c0c1;
|
||||||
|
// [1+1536+1536]
|
||||||
|
char* s0s1s2;
|
||||||
|
// [1536]
|
||||||
|
char* c2;
|
||||||
|
public:
|
||||||
|
SrsHandshakeBytes();
|
||||||
|
virtual ~SrsHandshakeBytes();
|
||||||
|
public:
|
||||||
|
virtual int read_c0c1(ISrsProtocolReaderWriter* io);
|
||||||
|
virtual int read_s0s1s2(ISrsProtocolReaderWriter* io);
|
||||||
|
virtual int read_c2(ISrsProtocolReaderWriter* io);
|
||||||
|
virtual int create_c0c1();
|
||||||
|
virtual int create_s0s1s2();
|
||||||
|
virtual int create_c2();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* implements the client role protocol.
|
* implements the client role protocol.
|
||||||
*/
|
*/
|
||||||
class SrsRtmpClient
|
class SrsRtmpClient
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
SrsHandshakeBytes* hs_bytes;
|
||||||
protected:
|
protected:
|
||||||
SrsProtocol* protocol;
|
SrsProtocol* protocol;
|
||||||
ISrsProtocolReaderWriter* io;
|
ISrsProtocolReaderWriter* io;
|
||||||
|
@ -155,6 +182,7 @@ public:
|
||||||
class SrsRtmpServer
|
class SrsRtmpServer
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
SrsHandshakeBytes* hs_bytes;
|
||||||
SrsProtocol* protocol;
|
SrsProtocol* protocol;
|
||||||
ISrsProtocolReaderWriter* io;
|
ISrsProtocolReaderWriter* io;
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -23,6 +23,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
#include <srs_protocol_utility.hpp>
|
#include <srs_protocol_utility.hpp>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <srs_kernel_log.hpp>
|
||||||
|
|
||||||
void srs_vhost_resolve(std::string& vhost, std::string& app)
|
void srs_vhost_resolve(std::string& vhost, std::string& app)
|
||||||
{
|
{
|
||||||
app = srs_replace(app, "...", "?");
|
app = srs_replace(app, "...", "?");
|
||||||
|
@ -46,3 +50,23 @@ void srs_vhost_resolve(std::string& vhost, std::string& app)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void srs_random_generate(char* bytes, int size)
|
||||||
|
{
|
||||||
|
static bool _random_initialized = false;
|
||||||
|
if (!_random_initialized) {
|
||||||
|
srand(0);
|
||||||
|
_random_initialized = true;
|
||||||
|
srs_trace("srand initialized the random.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static char cdata[] = {
|
||||||
|
0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x72, 0x74, 0x6d, 0x70, 0x2d, 0x73, 0x65,
|
||||||
|
0x72, 0x76, 0x65, 0x72, 0x2d, 0x77, 0x69, 0x6e, 0x6c, 0x69, 0x6e, 0x2d, 0x77, 0x69,
|
||||||
|
0x6e, 0x74, 0x65, 0x72, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x40, 0x31, 0x32, 0x36,
|
||||||
|
0x2e, 0x63, 0x6f, 0x6d
|
||||||
|
};
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
bytes[i] = cdata[rand() % (sizeof(cdata) - 1)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -40,4 +40,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
// app...vhost...request_vhost
|
// app...vhost...request_vhost
|
||||||
extern void srs_vhost_resolve(std::string& vhost, std::string& app);
|
extern void srs_vhost_resolve(std::string& vhost, std::string& app);
|
||||||
|
|
||||||
|
extern void srs_random_generate(char* bytes, int size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue