winlin

for bug #235, use strategy to implements the schema0 and schema1.

... ... @@ -638,261 +638,273 @@ namespace _srs_internal
return bytes;
}
c2s2::c2s2()
c1s1_strategy::c1s1_strategy()
{
srs_random_generate(random, 1504);
}
int size = snprintf(random, 1504, "%s", RTMP_SIG_SRS_HANDSHAKE);
srs_assert(++size < 1504);
snprintf(random + 1504 - size, size, "%s", RTMP_SIG_SRS_HANDSHAKE);
c1s1_strategy::~c1s1_strategy()
{
}
srs_random_generate(digest, 32);
c1s1_strategy_schema0::c1s1_strategy_schema0()
{
key.init();
digest.init();
}
c2s2::~c2s2()
c1s1_strategy_schema0::~c1s1_strategy_schema0()
{
key.free();
digest.free();
}
void c2s2::dump(char* _c2s2)
srs_schema_type c1s1_strategy_schema0::schema()
{
memcpy(_c2s2, random, 1504);
memcpy(_c2s2 + 1504, digest, 32);
return srs_schema0;
}
void c2s2::parse(char* _c2s2)
char* c1s1_strategy_schema0::get_digest()
{
memcpy(random, _c2s2, 1504);
memcpy(digest, _c2s2 + 1504, 32);
return digest.digest;
}
int c2s2::c2_create(c1s1* s1)
void c1s1_strategy_schema0::dump(c1s1* owner, char* _c1s1)
{
srs_schema0_copy_to(_c1s1, true, owner->time, owner->version, &key, &digest);
}
int c1s1_strategy_schema0::parse(char* _c1s1)
{
int ret = ERROR_SUCCESS;
char temp_key[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFPKey, 62, s1->get_digest(), 32, temp_key)) != ERROR_SUCCESS) {
srs_error("create c2 temp key failed. ret=%d", ret);
if ((ret = key.parse(_c1s1 + 8)) != ERROR_SUCCESS) {
srs_error("parse the c1 key failed. ret=%d", ret);
return ret;
}
srs_verbose("generate c2 temp key success.");
char _digest[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(temp_key, 32, random, 1504, _digest)) != ERROR_SUCCESS) {
srs_error("create c2 digest failed. ret=%d", ret);
if ((ret = digest.parse(_c1s1 + 8 + 764)) != ERROR_SUCCESS) {
srs_error("parse the c1 digest failed. ret=%d", ret);
return ret;
}
srs_verbose("generate c2 digest success.");
memcpy(digest, _digest, 32);
srs_verbose("parse c1 key-digest success");
return ret;
}
int c2s2::c2_validate(c1s1* s1, bool& is_valid)
int c1s1_strategy_schema0::c1_create(c1s1* owner)
{
is_valid = false;
int ret = ERROR_SUCCESS;
char temp_key[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFPKey, 62, s1->get_digest(), 32, temp_key)) != ERROR_SUCCESS) {
srs_error("create c2 temp key failed. ret=%d", ret);
return ret;
}
srs_verbose("generate c2 temp key success.");
// generate digest
char* c1_digest = NULL;
char _digest[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(temp_key, 32, random, 1504, _digest)) != ERROR_SUCCESS) {
srs_error("create c2 digest failed. ret=%d", ret);
if ((ret = calc_c1_digest(owner, c1_digest)) != ERROR_SUCCESS) {
srs_error("sign c1 error, failed to calc digest. ret=%d", ret);
return ret;
}
srs_verbose("generate c2 digest success.");
is_valid = srs_bytes_equals(digest, _digest, 32);
srs_assert(c1_digest != NULL);
SrsAutoFree(char, c1_digest);
memcpy(digest.digest, c1_digest, 32);
return ret;
}
int c2s2::s2_create(c1s1* c1)
int c1s1_strategy_schema0::c1_validate_digest(c1s1* owner, bool& is_valid)
{
int ret = ERROR_SUCCESS;
char temp_key[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFMSKey, 68, c1->get_digest(), 32, temp_key)) != ERROR_SUCCESS) {
srs_error("create s2 temp key failed. ret=%d", ret);
return ret;
}
srs_verbose("generate s2 temp key success.");
char* c1_digest = NULL;
char _digest[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(temp_key, 32, random, 1504, _digest)) != ERROR_SUCCESS) {
srs_error("create s2 digest failed. ret=%d", ret);
if ((ret = calc_c1_digest(owner, c1_digest)) != ERROR_SUCCESS) {
srs_error("validate c1 error, failed to calc digest. ret=%d", ret);
return ret;
}
srs_verbose("generate s2 digest success.");
memcpy(digest, _digest, 32);
srs_assert(c1_digest != NULL);
SrsAutoFree(char, c1_digest);
is_valid = srs_bytes_equals(digest.digest, c1_digest, 32);
return ret;
}
int c2s2::s2_validate(c1s1* c1, bool& is_valid)
int c1s1_strategy_schema0::s1_create(c1s1* owner)
{
is_valid = false;
int ret = ERROR_SUCCESS;
char temp_key[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFMSKey, 68, c1->get_digest(), 32, temp_key)) != ERROR_SUCCESS) {
srs_error("create s2 temp key failed. ret=%d", ret);
SrsDH dh;
// ensure generate 128bytes public key.
if ((ret = dh.initialize(true)) != ERROR_SUCCESS) {
return ret;
}
srs_verbose("generate s2 temp key success.");
char _digest[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(temp_key, 32, random, 1504, _digest)) != ERROR_SUCCESS) {
srs_error("create s2 digest failed. ret=%d", ret);
// directly generate the public key.
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/148
int pkey_size = 128;
// TODO: FIXME: use c1 public key to calc the shared key.
if ((ret = dh.copy_public_key(key.key, pkey_size)) != ERROR_SUCCESS) {
srs_error("calc s1 key failed. ret=%d", ret);
return ret;
}
srs_verbose("generate s2 digest success.");
is_valid = srs_bytes_equals(digest, _digest, 32);
srs_assert(pkey_size == 128);
srs_verbose("calc s1 key success.");
char* s1_digest = NULL;
if ((ret = calc_s1_digest(owner, s1_digest)) != ERROR_SUCCESS) {
srs_error("calc s1 digest failed. ret=%d", ret);
return ret;
}
srs_verbose("calc s1 digest success.");
// TODO: FIXME: move to the right position.
c1s1::c1s1()
{
schema = srs_schema_invalid;
}
c1s1::~c1s1()
{
destroy_blocks();
}
srs_assert(s1_digest != NULL);
SrsAutoFree(char, s1_digest);
char* c1s1::get_digest()
{
srs_assert(schema != srs_schema_invalid);
memcpy(digest.digest, s1_digest, 32);
srs_verbose("copy s1 key success.");
if (schema == srs_schema0) {
return block1.digest.digest;
} else {
return block0.digest.digest;
}
return ret;
}
void c1s1::dump(char* _c1s1)
int c1s1_strategy_schema0::s1_validate_digest(c1s1* owner, bool& is_valid)
{
srs_assert(schema != srs_schema_invalid);
int ret = ERROR_SUCCESS;
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);
char* s1_digest = NULL;
if ((ret = calc_s1_digest(owner, 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);
is_valid = srs_bytes_equals(digest.digest, s1_digest, 32);
return ret;
}
int c1s1::parse(char* _c1s1, srs_schema_type _schema)
int c1s1_strategy_schema0::calc_c1_digest(c1s1* owner, char*& c1_digest)
{
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);
char* c1s1_joined_bytes = NULL;
c1s1_joined_bytes = srs_bytes_join_schema0(owner->time, owner->version, &key, &digest);
srs_assert(c1s1_joined_bytes != NULL);
SrsAutoFree(char, c1s1_joined_bytes);
c1_digest = new char[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFPKey, 30, c1s1_joined_bytes, 1536 - 32, c1_digest)) != ERROR_SUCCESS) {
srs_freep(c1_digest);
srs_error("calc digest for c1 failed. ret=%d", ret);
return ret;
}
srs_verbose("digest calculated for c1");
destroy_blocks();
return ret;
}
int c1s1_strategy_schema0::calc_s1_digest(c1s1* owner, char*& s1_digest)
{
int ret = ERROR_SUCCESS;
char* c1s1_joined_bytes = NULL;
time = __srs_stream_read_4bytes(_c1s1);
version = __srs_stream_read_4bytes(_c1s1 + 4); // client c1 version
c1s1_joined_bytes = srs_bytes_join_schema0(owner->time, owner->version, &key, &digest);
if (_schema == srs_schema0) {
if ((ret = block0.key.parse(_c1s1 + 8)) != ERROR_SUCCESS) {
srs_error("parse the c1 key failed. ret=%d", ret);
srs_assert(c1s1_joined_bytes != NULL);
SrsAutoFree(char, c1s1_joined_bytes);
s1_digest = new char[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFMSKey, 36, c1s1_joined_bytes, 1536 - 32, s1_digest)) != ERROR_SUCCESS) {
srs_freep(s1_digest);
srs_error("calc digest for s1 failed. ret=%d", ret);
return ret;
}
if ((ret = block1.digest.parse(_c1s1 + 8 + 764)) != ERROR_SUCCESS) {
srs_error("parse the c1 digest failed. ret=%d", ret);
srs_verbose("digest calculated for s1");
return ret;
}
srs_verbose("parse c1 key-digest success");
} else if (_schema == srs_schema1) {
if ((ret = block0.digest.parse(_c1s1 + 8)) != ERROR_SUCCESS) {
srs_error("parse the c1 key failed. ret=%d", ret);
return ret;
c1s1_strategy_schema1::c1s1_strategy_schema1()
{
key.init();
digest.init();
}
if ((ret = block1.key.parse(_c1s1 + 8 + 764)) != ERROR_SUCCESS) {
srs_error("parse the c1 digest failed. ret=%d", ret);
return ret;
c1s1_strategy_schema1::~c1s1_strategy_schema1()
{
key.free();
digest.free();
}
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;
srs_schema_type c1s1_strategy_schema1::schema()
{
return srs_schema1;
}
schema = _schema;
char* c1s1_strategy_schema1::get_digest()
{
return digest.digest;
}
return ret;
void c1s1_strategy_schema1::dump(c1s1* owner, char* _c1s1)
{
srs_schema0_copy_to(_c1s1, true, owner->time, owner->version, &key, &digest);
}
int c1s1::c1_create(srs_schema_type _schema)
int c1s1_strategy_schema1::parse(char* _c1s1)
{
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);
if ((ret = digest.parse(_c1s1 + 8)) != ERROR_SUCCESS) {
srs_error("parse the c1 digest failed. ret=%d", ret);
return ret;
}
destroy_blocks();
if ((ret = key.parse(_c1s1 + 8 + 764)) != ERROR_SUCCESS) {
srs_error("parse the c1 key failed. ret=%d", ret);
return ret;
}
// client c1 time and version
time = ::time(NULL);
version = 0x80000702; // client c1 version
srs_verbose("parse c1 digest-key success");
// generate signature by schema
if (_schema == srs_schema0) {
block0.key.init();
block1.digest.init();
} else {
block0.digest.init();
block1.key.init();
return ret;
}
schema = _schema;
int c1s1_strategy_schema1::c1_create(c1s1* owner)
{
int ret = ERROR_SUCCESS;
// generate digest
char* digest = NULL;
char* c1_digest = NULL;
if ((ret = calc_c1_digest(digest)) != ERROR_SUCCESS) {
if ((ret = calc_c1_digest(owner, c1_digest)) != ERROR_SUCCESS) {
srs_error("sign c1 error, failed to calc digest. ret=%d", ret);
return ret;
}
srs_assert(digest != NULL);
SrsAutoFree(char, digest);
srs_assert(c1_digest != NULL);
SrsAutoFree(char, c1_digest);
if (schema == srs_schema0) {
memcpy(block1.digest.digest, digest, 32);
} else {
memcpy(block0.digest.digest, digest, 32);
}
memcpy(digest.digest, c1_digest, 32);
return ret;
}
int c1s1::c1_validate_digest(bool& is_valid)
int c1s1_strategy_schema1::c1_validate_digest(c1s1* owner, bool& is_valid)
{
is_valid = false;
int ret = ERROR_SUCCESS;
char* c1_digest = NULL;
if ((ret = calc_c1_digest(c1_digest)) != ERROR_SUCCESS) {
if ((ret = calc_c1_digest(owner, c1_digest)) != ERROR_SUCCESS) {
srs_error("validate c1 error, failed to calc digest. ret=%d", ret);
return ret;
}
... ... @@ -900,163 +912,241 @@ namespace _srs_internal
srs_assert(c1_digest != NULL);
SrsAutoFree(char, c1_digest);
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);
}
is_valid = srs_bytes_equals(digest.digest, c1_digest, 32);
return ret;
}
int c1s1::s1_validate_digest(bool& is_valid)
int c1s1_strategy_schema1::s1_create(c1s1* owner)
{
is_valid = false;
int ret = ERROR_SUCCESS;
char* s1_digest = NULL;
SrsDH dh;
if ((ret = calc_s1_digest(s1_digest)) != ERROR_SUCCESS) {
srs_error("validate s1 error, failed to calc digest. ret=%d", ret);
// ensure generate 128bytes public key.
if ((ret = dh.initialize(true)) != ERROR_SUCCESS) {
return ret;
}
// directly generate the public key.
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/148
int pkey_size = 128;
if ((ret = dh.copy_public_key(key.key, pkey_size)) != ERROR_SUCCESS) {
srs_error("calc s1 key failed. ret=%d", ret);
return ret;
}
srs_assert(pkey_size == 128);
srs_verbose("calc s1 key success.");
char* s1_digest = NULL;
if ((ret = calc_s1_digest(owner, 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);
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);
}
memcpy(digest.digest, s1_digest, 32);
srs_verbose("copy s1 key success.");
return ret;
}
int c1s1::s1_create(c1s1* c1)
int c1s1_strategy_schema1::s1_validate_digest(c1s1* owner, bool& is_valid)
{
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);
char* s1_digest = NULL;
if ((ret = calc_s1_digest(owner, s1_digest)) != ERROR_SUCCESS) {
srs_error("validate s1 error, failed to calc digest. ret=%d", ret);
return ret;
}
destroy_blocks();
schema = c1->schema;
srs_assert(s1_digest != NULL);
SrsAutoFree(char, s1_digest);
time = ::time(NULL);
version = 0x01000504; // server s1 version
is_valid = srs_bytes_equals(digest.digest, s1_digest, 32);
SrsDH dh;
// ensure generate 128bytes public key.
if ((ret = dh.initialize(true)) != ERROR_SUCCESS) {
return ret;
}
if (schema == srs_schema0) {
block0.key.init();
block1.digest.init();
int c1s1_strategy_schema1::calc_c1_digest(c1s1* owner, char*& c1_digest)
{
int ret = ERROR_SUCCESS;
// directly generate the public key.
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/148
int pkey_size = 128;
if ((ret = dh.copy_public_key(block0.key.key, pkey_size)) != ERROR_SUCCESS) {
srs_error("calc s1 key failed. ret=%d", ret);
char* c1s1_joined_bytes = NULL;
c1s1_joined_bytes = srs_bytes_join_schema1(owner->time, owner->version, &digest, &key);
srs_assert(c1s1_joined_bytes != NULL);
SrsAutoFree(char, c1s1_joined_bytes);
c1_digest = new char[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFPKey, 30, c1s1_joined_bytes, 1536 - 32, c1_digest)) != ERROR_SUCCESS) {
srs_freep(c1_digest);
srs_error("calc digest for c1 failed. ret=%d", ret);
return ret;
}
srs_assert(pkey_size == 128);
} else {
block0.digest.init();
block1.key.init();
srs_verbose("digest calculated for c1");
// directly generate the public key.
// @see: https://github.com/winlinvip/simple-rtmp-server/issues/148
int pkey_size = 128;
if ((ret = dh.copy_public_key(block1.key.key, pkey_size)) != ERROR_SUCCESS) {
srs_error("calc s1 key failed. ret=%d", ret);
return ret;
}
srs_assert(pkey_size == 128);
int c1s1_strategy_schema1::calc_s1_digest(c1s1* owner, char*& s1_digest)
{
int ret = ERROR_SUCCESS;
char* c1s1_joined_bytes = NULL;
c1s1_joined_bytes = srs_bytes_join_schema1(owner->time, owner->version, &digest, &key);
srs_assert(c1s1_joined_bytes != NULL);
SrsAutoFree(char, c1s1_joined_bytes);
s1_digest = new char[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFMSKey, 36, c1s1_joined_bytes, 1536 - 32, s1_digest)) != ERROR_SUCCESS) {
srs_freep(s1_digest);
srs_error("calc digest for s1 failed. ret=%d", ret);
return ret;
}
srs_verbose("calc s1 key success.");
srs_verbose("digest calculated for s1");
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);
c2s2::c2s2()
{
srs_random_generate(random, 1504);
if (schema == srs_schema0) {
memcpy(block1.digest.digest, s1_digest, 32);
} else {
memcpy(block0.digest.digest, s1_digest, 32);
int size = snprintf(random, 1504, "%s", RTMP_SIG_SRS_HANDSHAKE);
srs_assert(++size < 1504);
snprintf(random + 1504 - size, size, "%s", RTMP_SIG_SRS_HANDSHAKE);
srs_random_generate(digest, 32);
}
srs_verbose("copy s1 key success.");
return ret;
c2s2::~c2s2()
{
}
void c2s2::dump(char* _c2s2)
{
memcpy(_c2s2, random, 1504);
memcpy(_c2s2 + 1504, digest, 32);
}
int c1s1::calc_s1_digest(char*& digest)
void c2s2::parse(char* _c2s2)
{
memcpy(random, _c2s2, 1504);
memcpy(digest, _c2s2 + 1504, 32);
}
int c2s2::c2_create(c1s1* s1)
{
int ret = ERROR_SUCCESS;
srs_assert(schema == srs_schema0 || schema == srs_schema1);
char temp_key[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFPKey, 62, s1->get_digest(), 32, temp_key)) != ERROR_SUCCESS) {
srs_error("create c2 temp key failed. ret=%d", ret);
return ret;
}
srs_verbose("generate c2 temp key success.");
char* c1s1_joined_bytes = NULL;
char _digest[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(temp_key, 32, random, 1504, _digest)) != ERROR_SUCCESS) {
srs_error("create c2 digest failed. ret=%d", ret);
return ret;
}
srs_verbose("generate c2 digest success.");
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);
memcpy(digest, _digest, 32);
return ret;
}
srs_assert(c1s1_joined_bytes != NULL);
SrsAutoFree(char, c1s1_joined_bytes);
int c2s2::c2_validate(c1s1* s1, bool& is_valid)
{
is_valid = false;
int ret = ERROR_SUCCESS;
digest = new char[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFMSKey, 36, c1s1_joined_bytes, 1536 - 32, digest)) != ERROR_SUCCESS) {
srs_error("calc digest for s1 failed. ret=%d", ret);
char temp_key[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFPKey, 62, s1->get_digest(), 32, temp_key)) != ERROR_SUCCESS) {
srs_error("create c2 temp key failed. ret=%d", ret);
return ret;
}
srs_verbose("digest calculated for s1");
srs_verbose("generate c2 temp key success.");
char _digest[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(temp_key, 32, random, 1504, _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 c1s1::calc_c1_digest(char*& digest)
int c2s2::s2_create(c1s1* c1)
{
int ret = ERROR_SUCCESS;
srs_assert(schema == srs_schema0 || schema == srs_schema1);
char temp_key[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFMSKey, 68, c1->get_digest(), 32, 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[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(temp_key, 32, random, 1504, _digest)) != ERROR_SUCCESS) {
srs_error("create s2 digest failed. ret=%d", ret);
return ret;
}
srs_verbose("generate s2 digest success.");
char* c1s1_joined_bytes = NULL;
memcpy(digest, _digest, 32);
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 ret;
}
srs_assert(c1s1_joined_bytes != NULL);
SrsAutoFree(char, c1s1_joined_bytes);
int c2s2::s2_validate(c1s1* c1, bool& is_valid)
{
is_valid = false;
int ret = ERROR_SUCCESS;
digest = new char[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFPKey, 30, c1s1_joined_bytes, 1536 - 32, digest)) != ERROR_SUCCESS) {
srs_error("calc digest for c1 failed. ret=%d", ret);
char temp_key[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(SrsGenuineFMSKey, 68, c1->get_digest(), 32, temp_key)) != ERROR_SUCCESS) {
srs_error("create s2 temp key failed. ret=%d", ret);
return ret;
}
srs_verbose("digest calculated for c1");
srs_verbose("generate s2 temp key success.");
char _digest[__SRS_OpensslHashSize];
if ((ret = openssl_HMACsha256(temp_key, 32, random, 1504, _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()
{
payload = NULL;
}
c1s1::~c1s1()
{
srs_freep(payload);
/*
void c1s1::destroy_blocks()
{
if (schema == srs_schema_invalid) {
... ... @@ -1070,6 +1160,110 @@ namespace _srs_internal
block0.digest.free();
block1.key.free();
}
}*/
}
srs_schema_type c1s1::schema()
{
srs_assert(payload != NULL);
return payload->schema();
}
char* c1s1::get_digest()
{
srs_assert(payload != NULL);
return payload->get_digest();
}
void c1s1::dump(char* _c1s1)
{
srs_assert(payload != NULL);
return payload->dump(this, _c1s1);
}
int c1s1::parse(char* _c1s1, srs_schema_type schema)
{
int ret = ERROR_SUCCESS;
if (schema != srs_schema0 && schema != srs_schema1) {
ret = ERROR_RTMP_CH_SCHEMA;
srs_error("parse c1 failed. invalid schema=%d, ret=%d", schema, ret);
return ret;
}
time = __srs_stream_read_4bytes(_c1s1);
version = __srs_stream_read_4bytes(_c1s1 + 4); // client c1 version
srs_freep(payload);
if (schema == srs_schema0) {
payload = new c1s1_strategy_schema0();
} else {
payload = new c1s1_strategy_schema1();
}
return payload->parse(_c1s1);
}
int c1s1::c1_create(srs_schema_type schema)
{
int ret = ERROR_SUCCESS;
if (schema != srs_schema0 && schema != srs_schema1) {
ret = ERROR_RTMP_CH_SCHEMA;
srs_error("create c1 failed. invalid schema=%d, ret=%d", schema, ret);
return ret;
}
// client c1 time and version
time = ::time(NULL);
version = 0x80000702; // client c1 version
// generate signature by schema
srs_freep(payload);
if (schema == srs_schema0) {
payload = new c1s1_strategy_schema0();
} else {
payload = new c1s1_strategy_schema1();
}
return payload->c1_create(this);
}
int c1s1::c1_validate_digest(bool& is_valid)
{
is_valid = false;
srs_assert(payload);
return payload->c1_validate_digest(this, is_valid);
}
int c1s1::s1_validate_digest(bool& is_valid)
{
is_valid = false;
srs_assert(payload);
return payload->s1_validate_digest(this, is_valid);
}
int c1s1::s1_create(c1s1* c1)
{
int ret = ERROR_SUCCESS;
if (c1->schema() != srs_schema0 && c1->schema() != srs_schema1) {
ret = ERROR_RTMP_CH_SCHEMA;
srs_error("create s1 failed. invalid schema=%d, ret=%d", c1->schema(), ret);
return ret;
}
time = ::time(NULL);
version = 0x01000504; // server s1 version
srs_freep(payload);
if (c1->schema() == srs_schema0) {
payload = new c1s1_strategy_schema0();
} else {
payload = new c1s1_strategy_schema1();
}
return payload->s1_create(this);
}
}
... ... @@ -1190,6 +1384,7 @@ int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrs
// decode c1
c1s1 c1;
// try schema0.
// @remark, use schema0 to make flash player happy.
if ((ret = c1.parse(hs_bytes->c0c1 + 1, srs_schema0)) != ERROR_SUCCESS) {
srs_error("parse c1 schema%d error. ret=%d", srs_schema0, ret);
return ret;
... ... @@ -1197,6 +1392,7 @@ int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrs
// try schema1
bool is_valid = false;
if ((ret = c1.c1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
srs_info("schema0 failed, try schema1.");
if ((ret = c1.parse(hs_bytes->c0c1 + 1, srs_schema1)) != ERROR_SUCCESS) {
srs_error("parse c1 schema%d error. ret=%d", srs_schema1, ret);
return ret;
... ... @@ -1207,6 +1403,8 @@ int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrs
srs_info("all schema valid failed, try simple handshake. ret=%d", ret);
return ret;
}
} else {
srs_info("schema0 is ok.");
}
srs_verbose("decode c1 success.");
... ... @@ -1321,7 +1519,7 @@ int SrsComplexHandshake::handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrs
// verify s1s2
c1s1 s1;
if ((ret = s1.parse(hs_bytes->s0s1s2 + 1, c1.schema)) != ERROR_SUCCESS) {
if ((ret = s1.parse(hs_bytes->s0s1s2 + 1, c1.schema())) != ERROR_SUCCESS) {
return ret;
}
... ...
... ... @@ -219,6 +219,121 @@ namespace _srs_internal
*/
char* srs_bytes_join_schema1(int32_t time, int32_t version, digest_block* digest, key_block* key);
class c1s1;
/**
* the c1s1 strategy, use schema0 or schema1.
* the template method class to defines common behaviors,
* while the concrete class to implements in schema0 or schema1.
*/
class c1s1_strategy
{
public:
c1s1_strategy();
virtual ~c1s1_strategy();
public:
/**
* get the scema.
*/
virtual srs_schema_type schema() = 0;
/**
* get the digest key.
*/
virtual char* get_digest() = 0;
/**
* copy to bytes.
*/
virtual void dump(c1s1* owner, char* _c1s1) = 0;
/**
* server: parse the c1s1, discovery the key and digest by schema.
* use the c1_validate_digest() to valid the digest of c1.
*/
virtual int parse(char* _c1s1) = 0;
public:
/**
* client: create and sign c1 by schema.
* sign the c1, generate the digest.
* calc_c1_digest(c1, schema) {
* get c1s1-joined from c1 by specified schema
* digest-data = HMACsha256(c1s1-joined, FPKey, 30)
* return digest-data;
* }
* random fill 1536bytes c1 // also fill the c1-128bytes-key
* time = time() // c1[0-3]
* version = [0x80, 0x00, 0x07, 0x02] // c1[4-7]
* schema = choose schema0 or schema1
* digest-data = calc_c1_digest(c1, schema)
* copy digest-data to c1
*/
virtual int c1_create(c1s1* owner) = 0;
/**
* server: validate the parsed c1 schema
*/
virtual int c1_validate_digest(c1s1* owner, bool& is_valid) = 0;
/**
* server: create and sign the s1 from c1.
*/
virtual int s1_create(c1s1* owner) = 0;
/**
* server: validate the parsed s1 schema
*/
virtual int s1_validate_digest(c1s1* owner, bool& is_valid) = 0;
};
/**
* c1s1 schema0
* key: 764bytes
* digest: 764bytes
*/
class c1s1_strategy_schema0 : public c1s1_strategy
{
private:
key_block key;
digest_block digest;
public:
c1s1_strategy_schema0();
virtual ~c1s1_strategy_schema0();
public:
virtual srs_schema_type schema();
virtual char* get_digest();
virtual void dump(c1s1* owner, char* _c1s1);
virtual int parse(char* _c1s1);
virtual int c1_create(c1s1* owner);
virtual int c1_validate_digest(c1s1* owner, bool& is_valid);
virtual int s1_create(c1s1* owner);
virtual int s1_validate_digest(c1s1* owner, bool& is_valid);
private:
virtual int calc_c1_digest(c1s1* owner, char*& c1_digest);
virtual int calc_s1_digest(c1s1* owner, char*& s1_digest);
};
/**
* c1s1 schema1
* digest: 764bytes
* key: 764bytes
*/
class c1s1_strategy_schema1 : public c1s1_strategy
{
private:
digest_block digest;
key_block key;
public:
c1s1_strategy_schema1();
virtual ~c1s1_strategy_schema1();
public:
virtual srs_schema_type schema();
virtual char* get_digest();
virtual void dump(c1s1* owner, char* _c1s1);
virtual int parse(char* _c1s1);
virtual int c1_create(c1s1* owner);
virtual int c1_validate_digest(c1s1* owner, bool& is_valid);
virtual int s1_create(c1s1* owner);
virtual int s1_validate_digest(c1s1* owner, bool& is_valid);
private:
virtual int calc_c1_digest(c1s1* owner, char*& c1_digest);
virtual int calc_s1_digest(c1s1* owner, char*& s1_digest);
};
/**
* c1s1 schema0
* time: 4bytes
... ... @@ -235,30 +350,20 @@ namespace _srs_internal
class c1s1
{
public:
union block {
key_block key;
digest_block digest;
};
// 4bytes
int32_t time;
// 4bytes
int32_t version;
// 764bytes
// if schema0, use key
// if schema1, use digest
block block0;
// 764bytes
// if schema0, use digest
// if schema1, use key
block block1;
// the logic schema
srs_schema_type schema;
// 764bytes+764bytes
c1s1_strategy* payload;
c1s1();
virtual ~c1s1();
/**
* get the scema.
*/
virtual srs_schema_type schema();
/**
* get the digest key.
*/
virtual char* get_digest();
... ... @@ -269,6 +374,7 @@ namespace _srs_internal
/**
* server: parse the c1s1, discovery the key and digest by schema.
* use the c1_validate_digest() to valid the digest of c1.
* use the s1_validate_digest() to valid the digest of s1.
*/
virtual int parse(char* _c1s1, srs_schema_type _schema);
... ... @@ -294,16 +400,35 @@ namespace _srs_internal
virtual int c1_validate_digest(bool& is_valid);
/**
* server: create and sign the s1 from c1.
* // decode c1 try schema0 then schema1
* c1-digest-data = get-c1-digest-data(schema0)
* if c1-digest-data equals to calc_c1_digest(c1, schema0) {
* c1-key-data = get-c1-key-data(schema0)
* schema = schema0
* } else {
* c1-digest-data = get-c1-digest-data(schema1)
* if c1-digest-data not equals to calc_c1_digest(c1, schema1) {
* switch to simple handshake.
* return
* }
* c1-key-data = get-c1-key-data(schema1)
* schema = schema1
* }
*
* // generate s1
* random fill 1536bytes s1
* time = time() // c1[0-3]
* version = [0x04, 0x05, 0x00, 0x01] // s1[4-7]
* s1-key-data=shared_key=DH_compute_key(peer_pub_key=c1-key-data)
* get c1s1-joined by specified schema
* s1-digest-data = HMACsha256(c1s1-joined, FMSKey, 36)
* copy s1-digest-data and s1-key-data to s1.
*/
virtual int s1_create(c1s1* c1);
/**
* server: validate the parsed s1 schema
*/
virtual int s1_validate_digest(bool& is_valid);
private:
virtual int calc_s1_digest(char*& digest);
virtual int calc_c1_digest(char*& digest);
virtual void destroy_blocks();
};
/**
... ...