2013-11-23 03:36:07 +00:00
|
|
|
/*
|
|
|
|
The MIT License (MIT)
|
|
|
|
|
2014-01-01 02:37:12 +00:00
|
|
|
Copyright (c) 2013-2014 winlin
|
2013-11-23 03:36:07 +00:00
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
|
|
this software and associated documentation files (the "Software"), to deal in
|
|
|
|
the Software without restriction, including without limitation the rights to
|
|
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
|
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
|
|
subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
|
|
copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
|
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
|
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2014-03-01 06:03:02 +00:00
|
|
|
#include <srs_protocol_handshake.hpp>
|
2013-11-23 03:36:07 +00:00
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
2014-03-01 06:03:02 +00:00
|
|
|
#include <srs_core_autofree.hpp>
|
2014-03-01 02:30:16 +00:00
|
|
|
#include <srs_kernel_error.hpp>
|
2014-03-01 02:42:55 +00:00
|
|
|
#include <srs_kernel_log.hpp>
|
2014-03-01 04:43:04 +00:00
|
|
|
#include <srs_protocol_io.hpp>
|
2014-03-19 06:58:29 +00:00
|
|
|
#include <srs_protocol_utility.hpp>
|
|
|
|
#include <srs_protocol_rtmp.hpp>
|
2014-05-08 04:12:01 +00:00
|
|
|
#include <srs_kernel_stream.hpp>
|
2013-11-23 03:36:07 +00:00
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifdef SRS_AUTO_SSL
|
2013-11-27 14:41:58 +00:00
|
|
|
|
2014-07-06 09:25:25 +00:00
|
|
|
using namespace _srs_internal;
|
2013-11-23 03:36:07 +00:00
|
|
|
|
2014-03-19 14:45:58 +00:00
|
|
|
// for openssl_HMACsha256
|
2013-11-23 03:36:07 +00:00
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <openssl/hmac.h>
|
2014-03-19 14:45:58 +00:00
|
|
|
// for __openssl_generate_key
|
2013-11-23 03:36:07 +00:00
|
|
|
#include <openssl/dh.h>
|
|
|
|
|
2014-07-06 09:25:25 +00:00
|
|
|
namespace _srs_internal
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-19 14:45:58 +00:00
|
|
|
// 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
|
|
|
|
|
2014-08-08 01:57:36 +00:00
|
|
|
int __openssl_HMACsha256(HMAC_CTX* ctx, const void* data, int data_size, void* digest, unsigned int* digest_size)
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
2014-08-08 01:54:33 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-08-08 01:54:33 +00:00
|
|
|
if (HMAC_Update(ctx, (unsigned char *) data, data_size) < 0) {
|
|
|
|
ret = ERROR_OpenSslSha256Update;
|
|
|
|
return ret;
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-08-08 01:54:33 +00:00
|
|
|
if (HMAC_Final(ctx, (unsigned char *) digest, digest_size) < 0) {
|
|
|
|
ret = ERROR_OpenSslSha256Final;
|
|
|
|
return ret;
|
|
|
|
}
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-08-08 01:54:33 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* sha256 digest algorithm.
|
|
|
|
* @param key the sha256 key, NULL to use EVP_Digest, for instance,
|
|
|
|
* hashlib.sha256(data).digest().
|
|
|
|
*/
|
|
|
|
int openssl_HMACsha256(const void* key, int key_size, const void* data, int data_size, void* digest)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
unsigned int digest_size = 0;
|
|
|
|
|
|
|
|
unsigned char* __key = (unsigned char*)key;
|
|
|
|
unsigned char* __digest = (unsigned char*)digest;
|
|
|
|
|
|
|
|
if (key == NULL) {
|
|
|
|
// use data to digest.
|
|
|
|
// @see ./crypto/sha/sha256t.c
|
|
|
|
// @see ./crypto/evp/digest.c
|
2014-08-08 01:57:36 +00:00
|
|
|
if (EVP_Digest(data, data_size, __digest, &digest_size, EVP_sha256(), NULL) < 0)
|
2014-08-08 01:54:33 +00:00
|
|
|
{
|
|
|
|
ret = ERROR_OpenSslSha256EvpDigest;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// use key-data to digest.
|
|
|
|
HMAC_CTX ctx;
|
|
|
|
|
|
|
|
// @remark, if no key, use EVP_Digest to digest,
|
|
|
|
// for instance, in python, hashlib.sha256(data).digest().
|
|
|
|
HMAC_CTX_init(&ctx);
|
|
|
|
|
|
|
|
if (HMAC_Init_ex(&ctx, __key, key_size, EVP_sha256(), NULL) < 0) {
|
|
|
|
ret = ERROR_OpenSslSha256Init;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-08-08 01:57:36 +00:00
|
|
|
ret = __openssl_HMACsha256(&ctx, data, data_size, __digest, &digest_size);
|
2014-08-08 01:54:33 +00:00
|
|
|
HMAC_CTX_cleanup(&ctx);
|
|
|
|
|
|
|
|
if (ret != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2014-03-19 14:45:58 +00:00
|
|
|
|
|
|
|
if (digest_size != 32) {
|
2014-08-08 01:54:33 +00:00
|
|
|
ret = ERROR_OpenSslSha256DigestSize;
|
|
|
|
return ret;
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
2014-08-08 01:54:33 +00:00
|
|
|
return ret;
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define RFC2409_PRIME_1024 \
|
|
|
|
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
|
|
|
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
|
|
|
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
|
|
|
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
|
|
|
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
|
|
|
|
"FFFFFFFFFFFFFFFF"
|
|
|
|
|
2014-08-22 04:47:50 +00:00
|
|
|
SrsDH::SrsDH()
|
|
|
|
{
|
|
|
|
pdh = NULL;
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-08-22 04:47:50 +00:00
|
|
|
SrsDH::~SrsDH()
|
|
|
|
{
|
|
|
|
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;
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
2014-08-22 04:47:50 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-08-22 04:47:50 +00:00
|
|
|
int SrsDH::initialize(bool ensure_128bytes_public_key)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if ((ret = do_initialize()) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ensure_128bytes_public_key) {
|
|
|
|
int32_t key_size = BN_num_bytes(pdh->pub_key);
|
|
|
|
if (key_size != 128) {
|
|
|
|
srs_warn("regenerate 128B key, current=%dB", key_size);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
2014-08-06 07:45:40 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-08-22 04:47:50 +00:00
|
|
|
|
2014-08-22 05:10:11 +00:00
|
|
|
int SrsDH::copy_public_key(char* pkey, int32_t& pkey_size)
|
2014-08-06 07:45:40 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// copy public key to bytes.
|
2014-08-13 10:09:35 +00:00
|
|
|
// sometimes, the key_size is 127, seems ok.
|
2014-08-13 02:58:53 +00:00
|
|
|
int32_t key_size = BN_num_bytes(pdh->pub_key);
|
2014-08-13 10:09:35 +00:00
|
|
|
srs_assert(key_size > 0);
|
2014-08-06 07:45:40 +00:00
|
|
|
|
2014-08-22 05:10:11 +00:00
|
|
|
// maybe the key_size is 127, but dh will write all 128bytes pkey,
|
|
|
|
// so, donot need to set/initialize the pkey.
|
|
|
|
// @see https://github.com/winlinvip/simple-rtmp-server/issues/165
|
2014-08-22 04:47:50 +00:00
|
|
|
key_size = BN_bn2bin(pdh->pub_key, (unsigned char*)pkey);
|
|
|
|
srs_assert(key_size > 0);
|
|
|
|
|
2014-08-22 05:10:11 +00:00
|
|
|
// output the size of public key.
|
|
|
|
// @see https://github.com/winlinvip/simple-rtmp-server/issues/165
|
|
|
|
srs_assert(key_size <= pkey_size);
|
|
|
|
pkey_size = key_size;
|
2014-03-19 14:45:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2014-08-22 04:47:50 +00:00
|
|
|
|
2014-08-22 05:10:11 +00:00
|
|
|
int SrsDH::copy_shared_key(const char* ppkey, int32_t ppkey_size, char* skey, int32_t& skey_size)
|
2014-08-08 03:34:17 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
BIGNUM* ppk = NULL;
|
2014-08-22 04:47:50 +00:00
|
|
|
if ((ppk = BN_bin2bn((const unsigned char*)ppkey, ppkey_size, 0)) == NULL) {
|
2014-08-08 03:34:17 +00:00
|
|
|
ret = ERROR_OpenSslGetPeerPublicKey;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-08-22 04:47:50 +00:00
|
|
|
// if failed, donot return, do cleanup, @see ./test/dhtest.c:168
|
2014-08-22 05:10:11 +00:00
|
|
|
// maybe the key_size is 127, but dh will write all 128bytes skey,
|
|
|
|
// so, donot need to set/initialize the skey.
|
|
|
|
// @see https://github.com/winlinvip/simple-rtmp-server/issues/165
|
2014-08-22 04:47:50 +00:00
|
|
|
int32_t key_size = DH_compute_key((unsigned char*)skey, ppk, pdh);
|
|
|
|
|
|
|
|
if (key_size < ppkey_size) {
|
|
|
|
srs_warn("shared key size=%d, ppk_size=%d", key_size, ppkey_size);
|
|
|
|
}
|
|
|
|
|
2014-08-22 05:10:11 +00:00
|
|
|
if (key_size < 0 || key_size > skey_size) {
|
2014-08-08 03:34:17 +00:00
|
|
|
ret = ERROR_OpenSslComputeSharedKey;
|
2014-08-22 04:47:50 +00:00
|
|
|
} else {
|
2014-08-22 05:10:11 +00:00
|
|
|
skey_size = key_size;
|
2014-08-08 03:34:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ppk) {
|
|
|
|
BN_free(ppk);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2014-08-22 04:47:50 +00:00
|
|
|
|
|
|
|
int SrsDH::do_initialize()
|
2014-08-13 10:09:35 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-08-22 04:47:50 +00:00
|
|
|
int32_t bits_count = 1024;
|
|
|
|
|
|
|
|
//1. Create the DH
|
|
|
|
if ((pdh = DH_new()) == NULL) {
|
|
|
|
ret = ERROR_OpenSslCreateDH;
|
2014-08-13 10:09:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-08-22 04:47:50 +00:00
|
|
|
|
|
|
|
//2. Create his internal p and g
|
|
|
|
if ((pdh->p = BN_new()) == NULL) {
|
|
|
|
ret = ERROR_OpenSslCreateP;
|
2014-08-13 10:09:35 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-08-22 04:47:50 +00:00
|
|
|
if ((pdh->g = BN_new()) == NULL) {
|
|
|
|
ret = ERROR_OpenSslCreateG;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
//3. initialize p and g, @see ./test/ectest.c:260
|
|
|
|
if (!BN_hex2bn(&pdh->p, RFC2409_PRIME_1024)) {
|
|
|
|
ret = ERROR_OpenSslParseP1024;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
// @see ./test/bntest.c:1764
|
|
|
|
if (!BN_set_word(pdh->g, 2)) {
|
|
|
|
ret = ERROR_OpenSslSetG;
|
|
|
|
return ret;
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-08-22 04:47:50 +00:00
|
|
|
// 4. Set the key length
|
|
|
|
pdh->length = bits_count;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-08-22 04:47:50 +00:00
|
|
|
// 5. Generate private and public key
|
|
|
|
// @see ./test/dhtest.c:152
|
|
|
|
if (!DH_generate_key(pdh)) {
|
|
|
|
ret = ERROR_OpenSslGenerateDHKeys;
|
2014-08-06 07:45:40 +00:00
|
|
|
return ret;
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
2014-08-06 07:45:40 +00:00
|
|
|
|
2014-03-19 14:45:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
key_block::key_block()
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
2014-11-29 10:10:33 +00:00
|
|
|
offset = (int32_t)rand();
|
|
|
|
random0 = NULL;
|
|
|
|
random1 = NULL;
|
|
|
|
|
|
|
|
int valid_offset = calc_valid_offset();
|
|
|
|
srs_assert(valid_offset >= 0);
|
|
|
|
|
|
|
|
random0_size = valid_offset;
|
|
|
|
if (random0_size > 0) {
|
|
|
|
random0 = new char[random0_size];
|
|
|
|
srs_random_generate(random0, random0_size);
|
|
|
|
snprintf(random0, random0_size, "%s", RTMP_SIG_SRS_HANDSHAKE);
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
srs_random_generate(key, sizeof(key));
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
random1_size = 764 - valid_offset - 128 - 4;
|
|
|
|
if (random1_size > 0) {
|
|
|
|
random1 = new char[random1_size];
|
|
|
|
srs_random_generate(random1, random1_size);
|
|
|
|
snprintf(random1, random1_size, "%s", RTMP_SIG_SRS_HANDSHAKE);
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
key_block::~key_block()
|
2014-11-29 05:08:43 +00:00
|
|
|
{
|
2014-11-29 10:16:15 +00:00
|
|
|
srs_freep(random0);
|
|
|
|
srs_freep(random1);
|
2014-11-29 05:08:43 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int key_block::parse(SrsStream* stream)
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
2014-11-29 09:58:40 +00:00
|
|
|
|
|
|
|
// the key must be 764 bytes.
|
|
|
|
srs_assert(stream->require(764));
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
// read the last offset first, 760-763
|
|
|
|
stream->skip(764 - sizeof(int32_t));
|
2014-11-29 10:10:33 +00:00
|
|
|
offset = stream->read_4bytes();
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
// reset stream to read others.
|
|
|
|
stream->skip(-764);
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
int valid_offset = calc_valid_offset();
|
|
|
|
srs_assert(valid_offset >= 0);
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
random0_size = valid_offset;
|
|
|
|
if (random0_size > 0) {
|
2014-11-29 10:16:15 +00:00
|
|
|
srs_freep(random0);
|
2014-11-29 10:10:33 +00:00
|
|
|
random0 = new char[random0_size];
|
|
|
|
stream->read_bytes(random0, random0_size);
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
stream->read_bytes(key, 128);
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
random1_size = 764 - valid_offset - 128 - 4;
|
|
|
|
if (random1_size > 0) {
|
2014-11-29 10:16:15 +00:00
|
|
|
srs_freep(random1);
|
2014-11-29 10:10:33 +00:00
|
|
|
random1 = new char[random1_size];
|
|
|
|
stream->read_bytes(random1, random1_size);
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
int key_block::calc_valid_offset()
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
2014-11-29 10:10:33 +00:00
|
|
|
int max_offset_size = 764 - 128 - 4;
|
2014-11-29 05:08:43 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
int valid_offset = 0;
|
|
|
|
u_int8_t* pp = (u_int8_t*)&offset;
|
|
|
|
valid_offset += *pp++;
|
|
|
|
valid_offset += *pp++;
|
|
|
|
valid_offset += *pp++;
|
|
|
|
valid_offset += *pp++;
|
|
|
|
|
|
|
|
return valid_offset % max_offset_size;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
digest_block::digest_block()
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
2014-11-29 10:10:33 +00:00
|
|
|
offset = (int32_t)rand();
|
|
|
|
random0 = NULL;
|
|
|
|
random1 = NULL;
|
|
|
|
|
|
|
|
int valid_offset = calc_valid_offset();
|
|
|
|
srs_assert(valid_offset >= 0);
|
|
|
|
|
|
|
|
random0_size = valid_offset;
|
|
|
|
if (random0_size > 0) {
|
|
|
|
random0 = new char[random0_size];
|
|
|
|
srs_random_generate(random0, random0_size);
|
|
|
|
snprintf(random0, random0_size, "%s", RTMP_SIG_SRS_HANDSHAKE);
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
srs_random_generate(digest, sizeof(digest));
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
random1_size = 764 - 4 - valid_offset - 32;
|
|
|
|
if (random1_size > 0) {
|
|
|
|
random1 = new char[random1_size];
|
|
|
|
srs_random_generate(random1, random1_size);
|
|
|
|
snprintf(random1, random1_size, "%s", RTMP_SIG_SRS_HANDSHAKE);
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2014-11-29 05:08:43 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
digest_block::~digest_block()
|
2014-11-29 05:08:43 +00:00
|
|
|
{
|
2014-11-29 10:16:15 +00:00
|
|
|
srs_freep(random0);
|
|
|
|
srs_freep(random1);
|
2014-11-29 05:08:43 +00:00
|
|
|
}
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int digest_block::parse(SrsStream* stream)
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
// the digest must be 764 bytes.
|
|
|
|
srs_assert(stream->require(764));
|
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
offset = stream->read_4bytes();
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
int valid_offset = calc_valid_offset();
|
|
|
|
srs_assert(valid_offset >= 0);
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
random0_size = valid_offset;
|
|
|
|
if (random0_size > 0) {
|
2014-11-29 10:16:15 +00:00
|
|
|
srs_freep(random0);
|
2014-11-29 10:10:33 +00:00
|
|
|
random0 = new char[random0_size];
|
|
|
|
stream->read_bytes(random0, random0_size);
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
stream->read_bytes(digest, 32);
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
random1_size = 764 - 4 - valid_offset - 32;
|
|
|
|
if (random1_size > 0) {
|
2014-11-29 10:16:15 +00:00
|
|
|
srs_freep(random1);
|
2014-11-29 10:10:33 +00:00
|
|
|
random1 = new char[random1_size];
|
|
|
|
stream->read_bytes(random1, random1_size);
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
int digest_block::calc_valid_offset()
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
2014-11-29 10:10:33 +00:00
|
|
|
int max_offset_size = 764 - 32 - 4;
|
2014-11-29 05:08:43 +00:00
|
|
|
|
2014-11-29 10:10:33 +00:00
|
|
|
int valid_offset = 0;
|
|
|
|
u_int8_t* pp = (u_int8_t*)&offset;
|
|
|
|
valid_offset += *pp++;
|
|
|
|
valid_offset += *pp++;
|
|
|
|
valid_offset += *pp++;
|
|
|
|
valid_offset += *pp++;
|
|
|
|
|
|
|
|
return valid_offset % max_offset_size;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 08:17:07 +00:00
|
|
|
c1s1_strategy::c1s1_strategy()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
c1s1_strategy::~c1s1_strategy()
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
char* c1s1_strategy::get_digest()
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
return digest.digest;
|
|
|
|
}
|
|
|
|
|
2014-11-29 10:33:43 +00:00
|
|
|
char* c1s1_strategy::get_key()
|
|
|
|
{
|
|
|
|
return key.key;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int c1s1_strategy::dump(c1s1* owner, char* _c1s1, int size)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
2014-11-29 10:33:43 +00:00
|
|
|
srs_assert(size == 1536);
|
2014-11-29 09:58:40 +00:00
|
|
|
return copy_to(owner, _c1s1, size, true);
|
2014-11-29 08:17:07 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
int c1s1_strategy::c1_create(c1s1* owner)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
// generate digest
|
|
|
|
char* c1_digest = NULL;
|
|
|
|
|
|
|
|
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(c1_digest != NULL);
|
|
|
|
SrsAutoFree(char, c1_digest);
|
|
|
|
|
|
|
|
memcpy(digest.digest, c1_digest, 32);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
int c1s1_strategy::c1_validate_digest(c1s1* owner, bool& is_valid)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
char* c1_digest = NULL;
|
|
|
|
|
|
|
|
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_assert(c1_digest != NULL);
|
|
|
|
SrsAutoFree(char, c1_digest);
|
|
|
|
|
|
|
|
is_valid = srs_bytes_equals(digest.digest, c1_digest, 32);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 10:41:14 +00:00
|
|
|
int c1s1_strategy::s1_create(c1s1* owner, c1s1* c1)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
SrsDH dh;
|
|
|
|
|
|
|
|
// 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;
|
2014-11-29 10:41:14 +00:00
|
|
|
if ((ret = dh.copy_shared_key(c1->get_key(), 128, key.key, pkey_size)) != ERROR_SUCCESS) {
|
2014-11-29 08:17:07 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
memcpy(digest.digest, s1_digest, 32);
|
|
|
|
srs_verbose("copy s1 key success.");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
int c1s1_strategy::s1_validate_digest(c1s1* owner, bool& is_valid)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
int c1s1_strategy::calc_c1_digest(c1s1* owner, char*& c1_digest)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
/**
|
|
|
|
* 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* c1s1_joined_bytes = new char[1536 -32];
|
2014-11-29 08:17:07 +00:00
|
|
|
SrsAutoFree(char, c1s1_joined_bytes);
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = copy_to(owner, c1s1_joined_bytes, 1536 - 32, false)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-11-29 08:17:07 +00:00
|
|
|
|
|
|
|
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");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
int c1s1_strategy::calc_s1_digest(c1s1* owner, char*& s1_digest)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
2014-11-29 09:04:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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* c1s1_joined_bytes = new char[1536 -32];
|
2014-11-29 08:17:07 +00:00
|
|
|
SrsAutoFree(char, c1s1_joined_bytes);
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = copy_to(owner, c1s1_joined_bytes, 1536 - 32, false)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-11-29 08:17:07 +00:00
|
|
|
|
|
|
|
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("digest calculated for s1");
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
void c1s1_strategy::copy_time_version(SrsStream* stream, c1s1* owner)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
2014-11-29 09:58:40 +00:00
|
|
|
srs_assert(stream->require(8));
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
// 4bytes time
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_4bytes(owner->time);
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
// 4bytes version
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_4bytes(owner->version);
|
2014-11-29 08:17:07 +00:00
|
|
|
}
|
2014-11-29 09:58:40 +00:00
|
|
|
void c1s1_strategy::copy_key(SrsStream* stream)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
2014-11-29 09:58:40 +00:00
|
|
|
srs_assert(key.random0_size >= 0);
|
|
|
|
srs_assert(key.random1_size >= 0);
|
|
|
|
|
|
|
|
int total = key.random0_size + 128 + key.random1_size + 4;
|
|
|
|
srs_assert(stream->require(total));
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
// 764bytes key block
|
|
|
|
if (key.random0_size > 0) {
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_bytes(key.random0, key.random0_size);
|
2014-11-29 09:04:24 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_bytes(key.key, 128);
|
2014-11-29 09:04:24 +00:00
|
|
|
|
|
|
|
if (key.random1_size > 0) {
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_bytes(key.random1, key.random1_size);
|
2014-11-29 09:04:24 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_4bytes(key.offset);
|
2014-11-29 09:04:24 +00:00
|
|
|
}
|
2014-11-29 09:58:40 +00:00
|
|
|
void c1s1_strategy::copy_digest(SrsStream* stream, bool with_digest)
|
2014-11-29 09:04:24 +00:00
|
|
|
{
|
2014-11-29 09:58:40 +00:00
|
|
|
srs_assert(key.random0_size >= 0);
|
|
|
|
srs_assert(key.random1_size >= 0);
|
|
|
|
|
|
|
|
int total = 4 + digest.random0_size + digest.random1_size;
|
|
|
|
if (with_digest) {
|
|
|
|
total += 32;
|
|
|
|
}
|
|
|
|
srs_assert(stream->require(total));
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
// 732bytes digest block without the 32bytes digest-data
|
|
|
|
// nbytes digest block part1
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_4bytes(digest.offset);
|
2014-11-29 09:04:24 +00:00
|
|
|
|
|
|
|
// digest random padding.
|
|
|
|
if (digest.random0_size > 0) {
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_bytes(digest.random0, digest.random0_size);
|
2014-11-29 09:04:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// digest
|
|
|
|
if (with_digest) {
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_bytes(digest.digest, 32);
|
2014-11-29 09:04:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// nbytes digest block part2
|
|
|
|
if (digest.random1_size > 0) {
|
2014-11-29 09:58:40 +00:00
|
|
|
stream->write_bytes(digest.random1, digest.random1_size);
|
2014-11-29 09:04:24 +00:00
|
|
|
}
|
2014-11-29 08:17:07 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
c1s1_strategy_schema0::c1s1_strategy_schema0()
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
c1s1_strategy_schema0::~c1s1_strategy_schema0()
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
srs_schema_type c1s1_strategy_schema0::schema()
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
2014-11-29 09:04:24 +00:00
|
|
|
return srs_schema0;
|
2014-11-29 08:17:07 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int c1s1_strategy_schema0::parse(char* _c1s1, int size)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
srs_assert(size == 1536);
|
|
|
|
|
|
|
|
SrsStream stream;
|
|
|
|
|
|
|
|
if ((ret = stream.initialize(_c1s1 + 8, 764)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = key.parse(&stream)) != ERROR_SUCCESS) {
|
2014-11-29 09:04:24 +00:00
|
|
|
srs_error("parse the c1 key failed. ret=%d", ret);
|
2014-11-29 08:17:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = stream.initialize(_c1s1 + 8 + 764, 764)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = digest.parse(&stream)) != ERROR_SUCCESS) {
|
2014-11-29 09:04:24 +00:00
|
|
|
srs_error("parse the c1 digest failed. ret=%d", ret);
|
2014-11-29 08:17:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
srs_verbose("parse c1 key-digest success");
|
2014-11-29 08:17:07 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int c1s1_strategy_schema0::copy_to(c1s1* owner, char* bytes, int size, bool with_digest)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
2014-11-29 09:58:40 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
2014-11-29 08:17:07 +00:00
|
|
|
|
2014-11-29 10:33:43 +00:00
|
|
|
if (with_digest) {
|
|
|
|
srs_assert(size == 1536);
|
|
|
|
} else {
|
|
|
|
srs_assert(size == 1504);
|
|
|
|
}
|
|
|
|
|
2014-11-29 10:16:15 +00:00
|
|
|
SrsStream stream;
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = stream.initialize(bytes, size)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
2014-11-29 08:17:07 +00:00
|
|
|
}
|
2014-11-29 09:58:40 +00:00
|
|
|
|
|
|
|
copy_time_version(&stream, owner);
|
|
|
|
copy_key(&stream);
|
|
|
|
copy_digest(&stream, with_digest);
|
|
|
|
|
|
|
|
srs_assert(stream.empty());
|
2014-11-29 10:16:15 +00:00
|
|
|
|
|
|
|
return ret;
|
2014-11-29 08:17:07 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
c1s1_strategy_schema1::c1s1_strategy_schema1()
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
c1s1_strategy_schema1::~c1s1_strategy_schema1()
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:04:24 +00:00
|
|
|
srs_schema_type c1s1_strategy_schema1::schema()
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
2014-11-29 09:04:24 +00:00
|
|
|
return srs_schema1;
|
2014-11-29 08:17:07 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int c1s1_strategy_schema1::parse(char* _c1s1, int size)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
srs_assert(size == 1536);
|
|
|
|
|
|
|
|
SrsStream stream;
|
|
|
|
|
|
|
|
if ((ret = stream.initialize(_c1s1 + 8, 764)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = digest.parse(&stream)) != ERROR_SUCCESS) {
|
2014-11-29 09:04:24 +00:00
|
|
|
srs_error("parse the c1 digest failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-11-29 08:17:07 +00:00
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = stream.initialize(_c1s1 + 8 + 764, 764)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = key.parse(&stream)) != ERROR_SUCCESS) {
|
2014-11-29 09:04:24 +00:00
|
|
|
srs_error("parse the c1 key failed. ret=%d", ret);
|
2014-11-29 08:17:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-11-29 09:04:24 +00:00
|
|
|
|
|
|
|
srs_verbose("parse c1 digest-key success");
|
2014-11-29 08:17:07 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int c1s1_strategy_schema1::copy_to(c1s1* owner, char* bytes, int size, bool with_digest)
|
2014-11-29 08:17:07 +00:00
|
|
|
{
|
2014-11-29 09:58:40 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
2014-11-29 08:17:07 +00:00
|
|
|
|
2014-11-29 10:33:43 +00:00
|
|
|
if (with_digest) {
|
|
|
|
srs_assert(size == 1536);
|
|
|
|
} else {
|
|
|
|
srs_assert(size == 1504);
|
|
|
|
}
|
|
|
|
|
2014-11-29 10:16:15 +00:00
|
|
|
SrsStream stream;
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = stream.initialize(bytes, size)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
2014-11-29 08:17:07 +00:00
|
|
|
}
|
2014-11-29 09:58:40 +00:00
|
|
|
|
|
|
|
copy_time_version(&stream, owner);
|
|
|
|
copy_digest(&stream, with_digest);
|
|
|
|
copy_key(&stream);
|
|
|
|
|
|
|
|
srs_assert(stream.empty());
|
2014-11-29 10:16:15 +00:00
|
|
|
|
|
|
|
return ret;
|
2014-11-29 08:17:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-19 14:45:58 +00:00
|
|
|
c1s1::c1s1()
|
|
|
|
{
|
2014-11-29 08:17:07 +00:00
|
|
|
payload = NULL;
|
2014-03-19 08:30:43 +00:00
|
|
|
}
|
2014-03-19 14:45:58 +00:00
|
|
|
c1s1::~c1s1()
|
|
|
|
{
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_freep(payload);
|
|
|
|
}
|
|
|
|
|
|
|
|
srs_schema_type c1s1::schema()
|
|
|
|
{
|
|
|
|
srs_assert(payload != NULL);
|
|
|
|
return payload->schema();
|
2014-03-19 08:30:43 +00:00
|
|
|
}
|
|
|
|
|
2014-03-19 14:45:58 +00:00
|
|
|
char* c1s1::get_digest()
|
|
|
|
{
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_assert(payload != NULL);
|
|
|
|
return payload->get_digest();
|
2014-03-19 08:30:43 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:33:43 +00:00
|
|
|
char* c1s1::get_key()
|
|
|
|
{
|
|
|
|
srs_assert(payload != NULL);
|
|
|
|
return payload->get_key();
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int c1s1::dump(char* _c1s1, int size)
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
2014-11-29 10:33:43 +00:00
|
|
|
srs_assert(size == 1536);
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_assert(payload != NULL);
|
2014-11-29 09:58:40 +00:00
|
|
|
return payload->dump(this, _c1s1, size);
|
2014-03-19 08:30:43 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int c1s1::parse(char* _c1s1, int size, srs_schema_type schema)
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
srs_assert(size == 1536);
|
|
|
|
|
2014-11-29 08:17:07 +00:00
|
|
|
if (schema != srs_schema0 && schema != srs_schema1) {
|
2014-03-19 14:45:58 +00:00
|
|
|
ret = ERROR_RTMP_CH_SCHEMA;
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_error("parse c1 failed. invalid schema=%d, ret=%d", schema, ret);
|
2014-03-19 14:45:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
SrsStream stream;
|
|
|
|
|
|
|
|
if ((ret = stream.initialize(_c1s1, size)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
time = stream.read_4bytes();
|
|
|
|
version = stream.read_4bytes(); // client c1 version
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_freep(payload);
|
|
|
|
if (schema == srs_schema0) {
|
|
|
|
payload = new c1s1_strategy_schema0();
|
2014-03-19 14:45:58 +00:00
|
|
|
} else {
|
2014-11-29 08:17:07 +00:00
|
|
|
payload = new c1s1_strategy_schema1();
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
2014-11-29 08:17:07 +00:00
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
return payload->parse(_c1s1, size);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 08:17:07 +00:00
|
|
|
int c1s1::c1_create(srs_schema_type schema)
|
2014-03-19 14:45:58 +00:00
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-11-29 08:17:07 +00:00
|
|
|
if (schema != srs_schema0 && schema != srs_schema1) {
|
2014-03-19 14:45:58 +00:00
|
|
|
ret = ERROR_RTMP_CH_SCHEMA;
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_error("create c1 failed. invalid schema=%d, ret=%d", schema, ret);
|
2014-03-19 14:45:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-05-08 04:12:01 +00:00
|
|
|
// client c1 time and version
|
2014-03-19 14:45:58 +00:00
|
|
|
time = ::time(NULL);
|
2014-05-08 04:12:01 +00:00
|
|
|
version = 0x80000702; // client c1 version
|
2014-11-29 08:17:07 +00:00
|
|
|
|
2014-05-08 04:12:01 +00:00
|
|
|
// generate signature by schema
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_freep(payload);
|
2014-03-19 14:45:58 +00:00
|
|
|
if (schema == srs_schema0) {
|
2014-11-29 08:17:07 +00:00
|
|
|
payload = new c1s1_strategy_schema0();
|
2014-03-19 14:45:58 +00:00
|
|
|
} else {
|
2014-11-29 08:17:07 +00:00
|
|
|
payload = new c1s1_strategy_schema1();
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 08:17:07 +00:00
|
|
|
return payload->c1_create(this);
|
2014-03-19 05:10:25 +00:00
|
|
|
}
|
|
|
|
|
2014-03-19 14:45:58 +00:00
|
|
|
int c1s1::c1_validate_digest(bool& is_valid)
|
|
|
|
{
|
|
|
|
is_valid = false;
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_assert(payload);
|
|
|
|
return payload->c1_validate_digest(this, is_valid);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-03-19 14:45:58 +00:00
|
|
|
int c1s1::s1_create(c1s1* c1)
|
|
|
|
{
|
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2014-11-29 08:17:07 +00:00
|
|
|
if (c1->schema() != srs_schema0 && c1->schema() != srs_schema1) {
|
2014-03-19 14:45:58 +00:00
|
|
|
ret = ERROR_RTMP_CH_SCHEMA;
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_error("create s1 failed. invalid schema=%d, ret=%d", c1->schema(), ret);
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-03-19 14:45:58 +00:00
|
|
|
|
|
|
|
time = ::time(NULL);
|
|
|
|
version = 0x01000504; // server s1 version
|
|
|
|
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_freep(payload);
|
|
|
|
if (c1->schema() == srs_schema0) {
|
|
|
|
payload = new c1s1_strategy_schema0();
|
2014-03-19 14:45:58 +00:00
|
|
|
} else {
|
2014-11-29 08:17:07 +00:00
|
|
|
payload = new c1s1_strategy_schema1();
|
2014-03-19 14:45:58 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 10:41:14 +00:00
|
|
|
return payload->s1_create(this, c1);
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
2014-11-29 09:05:54 +00:00
|
|
|
|
|
|
|
int c1s1::s1_validate_digest(bool& is_valid)
|
|
|
|
{
|
|
|
|
is_valid = false;
|
|
|
|
srs_assert(payload);
|
|
|
|
return payload->s1_validate_digest(this, is_valid);
|
|
|
|
}
|
|
|
|
|
|
|
|
c2s2::c2s2()
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
|
|
|
srs_random_generate(digest, 32);
|
|
|
|
}
|
|
|
|
|
|
|
|
c2s2::~c2s2()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int c2s2::dump(char* _c2s2, int size)
|
2014-11-29 09:05:54 +00:00
|
|
|
{
|
2014-11-29 09:58:40 +00:00
|
|
|
srs_assert(size == 1536);
|
|
|
|
|
2014-11-29 09:05:54 +00:00
|
|
|
memcpy(_c2s2, random, 1504);
|
|
|
|
memcpy(_c2s2 + 1504, digest, 32);
|
2014-11-29 09:58:40 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
2014-11-29 09:05:54 +00:00
|
|
|
}
|
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
int c2s2::parse(char* _c2s2, int size)
|
2014-11-29 09:05:54 +00:00
|
|
|
{
|
2014-11-29 09:58:40 +00:00
|
|
|
srs_assert(size == 1536);
|
|
|
|
|
2014-11-29 09:05:54 +00:00
|
|
|
memcpy(random, _c2s2, 1504);
|
|
|
|
memcpy(digest, _c2s2 + 1504, 32);
|
2014-11-29 09:58:40 +00:00
|
|
|
|
|
|
|
return ERROR_SUCCESS;
|
2014-11-29 09:05:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int c2s2::c2_create(c1s1* s1)
|
|
|
|
{
|
|
|
|
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.");
|
|
|
|
|
|
|
|
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.");
|
|
|
|
|
|
|
|
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[__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 _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 c2s2::s2_create(c1s1* c1)
|
|
|
|
{
|
|
|
|
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 _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.");
|
|
|
|
|
|
|
|
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[__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.");
|
|
|
|
|
|
|
|
is_valid = srs_bytes_equals(digest, _digest, 32);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2013-11-27 14:41:58 +00:00
|
|
|
#endif
|
|
|
|
|
2013-11-23 03:36:07 +00:00
|
|
|
SrsSimpleHandshake::SrsSimpleHandshake()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsSimpleHandshake::~SrsSimpleHandshake()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
int SrsSimpleHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
|
|
|
|
2013-11-23 03:36:07 +00:00
|
|
|
ssize_t nsize;
|
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = hs_bytes->read_c0c1(io)) != ERROR_SUCCESS) {
|
2013-11-23 03:36:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// plain text required.
|
2014-03-19 06:58:29 +00:00
|
|
|
if (hs_bytes->c0c1[0] != 0x03) {
|
2014-03-18 03:32:58 +00:00
|
|
|
ret = ERROR_RTMP_PLAIN_REQUIRED;
|
|
|
|
srs_warn("only support rtmp plain text. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2013-11-23 03:36:07 +00:00
|
|
|
srs_verbose("check c0 success, required plain text.");
|
|
|
|
|
2014-04-13 13:55:01 +00:00
|
|
|
if ((ret = hs_bytes->create_s0s1s2(hs_bytes->c0c1 + 1)) != ERROR_SUCCESS) {
|
2014-03-19 06:58:29 +00:00
|
|
|
return ret;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = io->write(hs_bytes->s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) {
|
2013-11-23 03:36:07 +00:00
|
|
|
srs_warn("simple handshake send s0s1s2 failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("simple handshake send s0s1s2 success.");
|
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = hs_bytes->read_c2(io)) != ERROR_SUCCESS) {
|
2013-11-23 03:36:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
srs_trace("simple handshake success.");
|
2013-11-23 03:36:07 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
int SrsSimpleHandshake::handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io)
|
2013-11-29 07:07:05 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
2013-11-29 07:07:05 +00:00
|
|
|
|
|
|
|
ssize_t nsize;
|
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
// simple handshake
|
|
|
|
if ((ret = hs_bytes->create_c0c1()) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = io->write(hs_bytes->c0c1, 1537, &nsize)) != ERROR_SUCCESS) {
|
2013-11-29 07:07:05 +00:00
|
|
|
srs_warn("write c0c1 failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("write c0c1 success.");
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = hs_bytes->read_s0s1s2(io)) != ERROR_SUCCESS) {
|
2013-11-29 07:07:05 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
// plain text required.
|
2014-03-19 06:58:29 +00:00
|
|
|
if (hs_bytes->s0s1s2[0] != 0x03) {
|
2013-11-29 07:07:05 +00:00
|
|
|
ret = ERROR_RTMP_HANDSHAKE;
|
|
|
|
srs_warn("handshake failed, plain text required. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = hs_bytes->create_c2()) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if ((ret = io->write(hs_bytes->c2, 1536, &nsize)) != ERROR_SUCCESS) {
|
2013-11-29 07:07:05 +00:00
|
|
|
srs_warn("simple handshake write c2 failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("simple handshake write c2 success.");
|
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
srs_trace("simple handshake success.");
|
2013-11-29 07:07:05 +00:00
|
|
|
|
2014-03-18 03:32:58 +00:00
|
|
|
return ret;
|
2013-11-29 07:07:05 +00:00
|
|
|
}
|
|
|
|
|
2013-11-23 03:36:07 +00:00
|
|
|
SrsComplexHandshake::SrsComplexHandshake()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SrsComplexHandshake::~SrsComplexHandshake()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifndef SRS_AUTO_SSL
|
2014-03-19 06:58:29 +00:00
|
|
|
int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* /*hs_bytes*/, ISrsProtocolReaderWriter* /*io*/)
|
2013-11-27 14:41:58 +00:00
|
|
|
{
|
2014-03-18 09:44:43 +00:00
|
|
|
srs_trace("directly use simple handshake for ssl disabled.");
|
2014-03-18 03:32:58 +00:00
|
|
|
return ERROR_RTMP_TRY_SIMPLE_HS;
|
2013-11-27 14:41:58 +00:00
|
|
|
}
|
|
|
|
#else
|
2014-03-19 06:58:29 +00:00
|
|
|
int SrsComplexHandshake::handshake_with_client(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io)
|
2013-11-23 03:36:07 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
2013-11-27 14:41:58 +00:00
|
|
|
|
2013-11-23 03:36:07 +00:00
|
|
|
ssize_t nsize;
|
2014-03-18 03:32:58 +00:00
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = hs_bytes->read_c0c1(io)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// decode c1
|
|
|
|
c1s1 c1;
|
|
|
|
// try schema0.
|
2014-11-29 08:17:07 +00:00
|
|
|
// @remark, use schema0 to make flash player happy.
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = c1.parse(hs_bytes->c0c1 + 1, 1536, srs_schema0)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("parse c1 schema%d error. ret=%d", srs_schema0, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
// try schema1
|
|
|
|
bool is_valid = false;
|
|
|
|
if ((ret = c1.c1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
|
2014-11-29 08:17:07 +00:00
|
|
|
srs_info("schema0 failed, try schema1.");
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = c1.parse(hs_bytes->c0c1 + 1, 1536, srs_schema1)) != ERROR_SUCCESS) {
|
2014-03-18 03:32:58 +00:00
|
|
|
srs_error("parse c1 schema%d error. ret=%d", srs_schema1, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = c1.c1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
|
|
|
|
ret = ERROR_RTMP_TRY_SIMPLE_HS;
|
|
|
|
srs_info("all schema valid failed, try simple handshake. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
2014-11-29 08:17:07 +00:00
|
|
|
} else {
|
|
|
|
srs_info("schema0 is ok.");
|
2014-03-18 03:32:58 +00:00
|
|
|
}
|
|
|
|
srs_verbose("decode c1 success.");
|
|
|
|
|
|
|
|
// encode s1
|
|
|
|
c1s1 s1;
|
|
|
|
if ((ret = s1.s1_create(&c1)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("create s1 from c1 failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("create s1 from c1 success.");
|
2014-03-19 05:10:25 +00:00
|
|
|
// verify s1
|
|
|
|
if ((ret = s1.s1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
|
|
|
|
ret = ERROR_RTMP_TRY_SIMPLE_HS;
|
2014-03-19 06:58:29 +00:00
|
|
|
srs_info("verify s1 failed, try simple handshake. ret=%d", ret);
|
2014-03-19 05:10:25 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-03-19 06:58:29 +00:00
|
|
|
srs_verbose("verify s1 success.");
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
c2s2 s2;
|
|
|
|
if ((ret = s2.s2_create(&c1)) != ERROR_SUCCESS) {
|
|
|
|
srs_error("create s2 from c1 failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("create s2 from c1 success.");
|
2014-03-19 06:58:29 +00:00
|
|
|
// 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.");
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
// sendout s0s1s2
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = hs_bytes->create_s0s1s2()) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = s1.dump(hs_bytes->s0s1s2 + 1, 1536)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if ((ret = s2.dump(hs_bytes->s0s1s2 + 1537, 1536)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = io->write(hs_bytes->s0s1s2, 3073, &nsize)) != ERROR_SUCCESS) {
|
2013-11-23 03:36:07 +00:00
|
|
|
srs_warn("complex handshake send s0s1s2 failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("complex handshake send s0s1s2 success.");
|
|
|
|
|
|
|
|
// recv c2
|
2014-03-19 06:58:29 +00:00
|
|
|
if ((ret = hs_bytes->read_c2(io)) != ERROR_SUCCESS) {
|
2013-11-23 03:36:07 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-03-19 06:58:29 +00:00
|
|
|
c2s2 c2;
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = c2.parse(hs_bytes->c2, 1536)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2013-11-23 03:36:07 +00:00
|
|
|
srs_verbose("complex handshake read c2 success.");
|
2014-03-19 14:45:58 +00:00
|
|
|
|
2014-03-19 06:58:29 +00:00
|
|
|
// verify c2
|
2014-03-19 14:45:58 +00:00
|
|
|
// never verify c2, for ffmpeg will failed.
|
|
|
|
// it's ok for flash.
|
2014-03-19 06:58:29 +00:00
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
srs_trace("complex handshake success");
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-11-23 03:36:07 +00:00
|
|
|
}
|
2013-11-27 14:41:58 +00:00
|
|
|
#endif
|
2013-11-23 03:36:07 +00:00
|
|
|
|
2014-04-15 06:01:57 +00:00
|
|
|
#ifndef SRS_AUTO_SSL
|
2014-03-19 06:58:29 +00:00
|
|
|
int SrsComplexHandshake::handshake_with_server(SrsHandshakeBytes* /*hs_bytes*/, ISrsProtocolReaderWriter* /*io*/)
|
2013-11-29 07:07:05 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
return ERROR_RTMP_TRY_SIMPLE_HS;
|
2013-11-29 07:07:05 +00:00
|
|
|
}
|
|
|
|
#else
|
2014-03-19 08:30:43 +00:00
|
|
|
int SrsComplexHandshake::handshake_with_server(SrsHandshakeBytes* hs_bytes, ISrsProtocolReaderWriter* io)
|
2013-11-29 07:07:05 +00:00
|
|
|
{
|
2014-03-18 03:32:58 +00:00
|
|
|
int ret = ERROR_SUCCESS;
|
2014-09-27 06:18:02 +00:00
|
|
|
|
2014-03-19 08:30:43 +00:00
|
|
|
ssize_t nsize;
|
|
|
|
|
|
|
|
// complex handshake
|
|
|
|
if ((ret = hs_bytes->create_c0c1()) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// sign c1
|
|
|
|
c1s1 c1;
|
2014-05-08 03:51:49 +00:00
|
|
|
// @remark, FMS requires the schema1(digest-key), or connect failed.
|
|
|
|
if ((ret = c1.c1_create(srs_schema1)) != ERROR_SUCCESS) {
|
2014-03-19 08:30:43 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = c1.dump(hs_bytes->c0c1 + 1, 1536)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-09-27 06:18:02 +00:00
|
|
|
|
2014-03-19 08:30:43 +00:00
|
|
|
// verify c1
|
|
|
|
bool is_valid;
|
|
|
|
if ((ret = c1.c1_validate_digest(is_valid)) != ERROR_SUCCESS || !is_valid) {
|
|
|
|
ret = ERROR_RTMP_TRY_SIMPLE_HS;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = io->write(hs_bytes->c0c1, 1537, &nsize)) != ERROR_SUCCESS) {
|
|
|
|
srs_warn("write c0c1 failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("write c0c1 success.");
|
|
|
|
|
|
|
|
// s0s1s2
|
|
|
|
if ((ret = hs_bytes->read_s0s1s2(io)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// plain text required.
|
|
|
|
if (hs_bytes->s0s1s2[0] != 0x03) {
|
|
|
|
ret = ERROR_RTMP_HANDSHAKE;
|
|
|
|
srs_warn("handshake failed, plain text required. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify s1s2
|
|
|
|
c1s1 s1;
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = s1.parse(hs_bytes->s0s1s2 + 1, 1536, c1.schema())) != ERROR_SUCCESS) {
|
2014-03-19 08:30:43 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2014-03-26 03:39:10 +00:00
|
|
|
|
|
|
|
// never verify the s1,
|
|
|
|
// for if forward to nginx-rtmp, verify s1 will failed,
|
|
|
|
// TODO: FIXME: find the handshake schema of nginx-rtmp.
|
2014-03-19 08:30:43 +00:00
|
|
|
|
|
|
|
// c2
|
|
|
|
if ((ret = hs_bytes->create_c2()) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-09-27 06:18:02 +00:00
|
|
|
|
2014-03-19 08:30:43 +00:00
|
|
|
c2s2 c2;
|
|
|
|
if ((ret = c2.c2_create(&s1)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-09-27 06:18:02 +00:00
|
|
|
|
2014-11-29 09:58:40 +00:00
|
|
|
if ((ret = c2.dump(hs_bytes->c2, 1536)) != ERROR_SUCCESS) {
|
|
|
|
return ret;
|
|
|
|
}
|
2014-03-19 08:30:43 +00:00
|
|
|
if ((ret = io->write(hs_bytes->c2, 1536, &nsize)) != ERROR_SUCCESS) {
|
|
|
|
srs_warn("complex handshake write c2 failed. ret=%d", ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
srs_verbose("complex handshake write c2 success.");
|
|
|
|
|
2014-05-29 06:16:34 +00:00
|
|
|
srs_trace("complex handshake success.");
|
2014-03-18 03:32:58 +00:00
|
|
|
|
|
|
|
return ret;
|
2013-11-29 07:07:05 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-08-02 14:18:39 +00:00
|
|
|
|