diff --git a/circle.yml b/circle.yml index e0927d6a8..ed5eaf8ab 100644 --- a/circle.yml +++ b/circle.yml @@ -17,6 +17,6 @@ dependencies: test: override: - - (cd trunk && ./configure --with-ssl=openssl --without-valgrind && make) + - (cd trunk && ./configure --without-ssl --without-valgrind && make) - (cd trunk && ./objs/srs_utest) diff --git a/trunk/configure b/trunk/configure index 2a55d2946..7cdc239cd 100755 --- a/trunk/configure +++ b/trunk/configure @@ -154,7 +154,7 @@ CORE_OBJS="${MODULE_OBJS[@]}" #Kernel, depends on core, provides error/log/config, nothing about stream information. MODULE_ID="KERNEL" MODULE_DEPENDS=("CORE") -ModuleLibIncs=(${SRS_OBJS_DIR}) +ModuleLibIncs=(${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_kernel_error" "srs_kernel_log" "srs_kernel_buffer" "srs_kernel_utility" "srs_kernel_flv" "srs_kernel_codec" "srs_kernel_io" "srs_kernel_consts" "srs_kernel_aac" "srs_kernel_mp3" "srs_kernel_ts" @@ -177,7 +177,7 @@ PROTOCOL_OBJS="${MODULE_OBJS[@]}" if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVICE" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_service_log" "srs_service_st" "srs_service_http_client" "srs_service_http_conn" "srs_service_rtmp_conn" "srs_service_utility" "srs_service_conn") @@ -190,7 +190,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="APP" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibSSLRoot}) MODULE_FILES=("srs_app_server" "srs_app_conn" "srs_app_rtmp_conn" "srs_app_source" "srs_app_refer" "srs_app_hls" "srs_app_forward" "srs_app_encoder" "srs_app_http_stream" "srs_app_thread" "srs_app_bandwidth" "srs_app_st" "srs_app_log" "srs_app_config" @@ -225,7 +225,7 @@ LIBS_OBJS="${MODULE_OBJS[@]}" if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="SERVER" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE" "APP") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) MODULE_FILES=("srs_main_server") SERVER_INCS="src/main"; MODULE_DIR=${SERVER_INCS} . auto/modules.sh SERVER_OBJS="${MODULE_OBJS[@]}" @@ -235,7 +235,7 @@ fi if [ $SRS_EXPORT_LIBRTMP_PROJECT = NO ]; then MODULE_ID="MAIN" MODULE_DEPENDS=("CORE" "KERNEL" "PROTOCOL" "SERVICE") - ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot}) + ModuleLibIncs=(${LibSTRoot} ${SRS_OBJS_DIR} ${LibGperfRoot} ${LibSSLRoot}) MODULE_FILES=() DEFINES="" # add each modules for main diff --git a/trunk/src/app/srs_app_hls.cpp b/trunk/src/app/srs_app_hls.cpp index 96fe385e3..c036fb693 100644 --- a/trunk/src/app/srs_app_hls.cpp +++ b/trunk/src/app/srs_app_hls.cpp @@ -52,7 +52,9 @@ using namespace std; #include #include +#ifdef SRS_AUTO_SSL #include +#endif // drop the segment when duration of ts too small. #define SRS_AUTO_HLS_SEGMENT_MIN_DURATION_MS 100 @@ -62,25 +64,26 @@ using namespace std; // reset the piece id when deviation overflow this. #define SRS_JUMP_WHEN_PIECE_DEVIATION 20 -SrsHlsSegment::SrsHlsSegment(SrsTsContext* c, SrsAudioCodecId ac, SrsVideoCodecId vc, SrsFileWriter *srswriter) +SrsHlsSegment::SrsHlsSegment(SrsTsContext* c, SrsAudioCodecId ac, SrsVideoCodecId vc, SrsFileWriter* w) { sequence_no = 0; - - writer = srswriter; - + writer = w; tscw = new SrsTsContextWriter(writer, c, ac, vc); } -void SrsHlsSegment::SrsSetEncCfg(unsigned char* keyval,unsigned char *ivval) +SrsHlsSegment::~SrsHlsSegment() { - memcpy(iv,ivval,16); - dynamic_cast(writer)->SetEncCfg(keyval,ivval); + srs_freep(tscw); } -SrsHlsSegment::~SrsHlsSegment() +void SrsHlsSegment::config_cipher(unsigned char* key,unsigned char* iv) { - srs_freep(tscw); - //srs_freep(writer); + memcpy(this->iv, iv,16); + +#ifdef SRS_AUTO_SSL + SrsEncFileWriter* fw = (SrsEncFileWriter*)writer; + fw->config_cipher(key, iv); +#endif } SrsDvrAsyncCallOnHls::SrsDvrAsyncCallOnHls(int c, SrsRequest* r, string p, string t, string m, string mu, int s, double d) @@ -208,6 +211,9 @@ SrsHlsMuxer::SrsHlsMuxer() async = new SrsAsyncCallWorker(); context = new SrsTsContext(); segments = new SrsFragmentWindow(); + + memset(key, 0, 16); + memset(iv, 0, 16); } SrsHlsMuxer::~SrsHlsMuxer() @@ -280,7 +286,7 @@ srs_error_t SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, string path, string m3u8_file, string ts_file, double fragment, double window, bool ts_floor, double aof_ratio, bool cleanup, bool wait_keyframe, bool keys, int fragments_per_key, string key_file ,string key_file_path, string key_url) - { +{ srs_error_t err = srs_success; srs_freep(req); @@ -318,8 +324,7 @@ srs_error_t SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, return srs_error_wrap(err, "create dir"); } - if(hls_keys && (hls_path != hls_key_file_path) ) - { + if (hls_keys && (hls_path != hls_key_file_path)) { string key_file = hls_key_file; key_file = srs_path_build_stream(key_file, req->vhost, req->app, req->stream); @@ -329,12 +334,13 @@ srs_error_t SrsHlsMuxer::update_config(SrsRequest* r, string entry_prefix, } } - if(hls_keys) - { + if(hls_keys) { +#ifdef SRS_AUTO_SSL writer = new SrsEncFileWriter(); - } - else - { +#else + writer = new SrsFileWriter(); +#endif + } else { writer = new SrsFileWriter(); } @@ -382,54 +388,13 @@ srs_error_t SrsHlsMuxer::segment_open() } // new segment. - current = new SrsHlsSegment(context, default_acodec, default_vcodec,writer); + current = new SrsHlsSegment(context, default_acodec, default_vcodec, writer); current->sequence_no = _sequence_no++; - if(hls_keys){ - - if(current->sequence_no % hls_fragments_per_key == 0) - { - string key_file = hls_key_file; - key_file = srs_path_build_stream(key_file, req->vhost, req->app, req->stream); - - if (true) { - std::stringstream ss; - ss << current->sequence_no; - key_file = srs_string_replace(key_file, "[seq]", ss.str()); - } - - string key_full_path = hls_key_file_path + "/" + key_file; - - if (RAND_bytes(key, 16) < 0) { - srs_error_wrap(err, "rand key failed."); - } - - if (RAND_bytes(iv, 16) < 0) { - srs_error_wrap(err, "rand iv failed."); - } - - int flags = O_CREAT|O_WRONLY|O_TRUNC; - mode_t mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH; - int fd; - - if ((fd = ::open(key_full_path.c_str(), flags, mode)) < 0) { - return srs_error_new(ERROR_SYSTEM_FILE_OPENE, "open file %s failed", key_full_path.c_str()); - } - ssize_t nwrite; - if ((nwrite = ::write(fd, key, 16)) != 16) { - return srs_error_new(ERROR_SYSTEM_FILE_WRITE, "write to file %s failed", key_full_path.c_str()); - } - - if (::close(fd) < 0) { - srs_warn("close file %s failed",key_full_path.c_str()); - } - - } - current->SrsSetEncCfg(key,iv); - + if ((err = write_hls_key()) != srs_success) { + return srs_error_wrap(err, "write hls key"); } - // generate filename. std::string ts_file = hls_ts_file; ts_file = srs_path_build_stream(ts_file, req->vhost, req->app, req->stream); @@ -688,6 +653,58 @@ srs_error_t SrsHlsMuxer::segment_close() return err; } +srs_error_t SrsHlsMuxer::write_hls_key() +{ + srs_error_t err = srs_success; + +#ifndef SRS_AUTO_SSL + if (hls_keys) { + srs_warn("SSL is disabled, ignore HLS key"); + } +#endif + +#ifdef SRS_AUTO_SSL + if (hls_keys && current->sequence_no % hls_fragments_per_key == 0) { + string key_file = hls_key_file; + key_file = srs_path_build_stream(key_file, req->vhost, req->app, req->stream); + + if (true) { + std::stringstream ss; + ss << current->sequence_no; + key_file = srs_string_replace(key_file, "[seq]", ss.str()); + } + + string key_full_path = hls_key_file_path + "/" + key_file; + + if (RAND_bytes(key, 16) < 0) { + srs_error_wrap(err, "rand key failed."); + } + + if (RAND_bytes(iv, 16) < 0) { + srs_error_wrap(err, "rand iv failed."); + } + + SrsFileWriter fw; + + if ((err = fw.open(key_full_path)) != srs_success) { + return srs_error_wrap(err, "open file %s", key_full_path.c_str()); + } + + if ((err = fw.write(key, 16, NULL)) != srs_success) { + return srs_error_wrap(err, "write key"); + } + + fw.close(); + } + + if (hls_keys) { + current->config_cipher(key, iv); + } +#endif + + return err; +} + srs_error_t SrsHlsMuxer::refresh_m3u8() { srs_error_t err = srs_success; diff --git a/trunk/src/app/srs_app_hls.hpp b/trunk/src/app/srs_app_hls.hpp index 433ec513e..edb3008a7 100644 --- a/trunk/src/app/srs_app_hls.hpp +++ b/trunk/src/app/srs_app_hls.hpp @@ -71,15 +71,11 @@ public: unsigned char iv[16]; // The full key path. std::string keypath; - public: - SrsHlsSegment(SrsTsContext* c, SrsAudioCodecId ac, SrsVideoCodecId vc, SrsFileWriter *srswriter); + SrsHlsSegment(SrsTsContext* c, SrsAudioCodecId ac, SrsVideoCodecId vc, SrsFileWriter* w); virtual ~SrsHlsSegment(); public: - - void SrsSetEncCfg(unsigned char* keyval,unsigned char * ivval); - - + void config_cipher(unsigned char* key,unsigned char* iv); }; /** @@ -156,24 +152,20 @@ private: // used to detect the dup or jmp or ts. int64_t accept_floor_ts; int64_t previous_floor_ts; - private: - //encrypted or not + // encrypted or not bool hls_keys; int hls_fragments_per_key; - //key file name + // key file name std::string hls_key_file; - //key file path + // key file path std::string hls_key_file_path; - //key file url + // key file url std::string hls_key_url; - + // key and iv. unsigned char key[16]; unsigned char iv[16]; - SrsFileWriter *writer; - - private: int _sequence_no; int max_td; @@ -210,8 +202,8 @@ public: virtual srs_error_t update_config(SrsRequest* r, std::string entry_prefix, std::string path, std::string m3u8_file, std::string ts_file, double fragment, double window, bool ts_floor, double aof_ratio, - bool cleanup, bool wait_keyframe , bool keys, int fragments_per_key, - std::string key_file , std::string key_file_path,std::string key_url); + bool cleanup, bool wait_keyframe, bool keys, int fragments_per_key, + std::string key_file, std::string key_file_path, std::string key_url); /** * open a new segment(a new ts file) */ @@ -244,6 +236,7 @@ public: */ virtual srs_error_t segment_close(); private: + virtual srs_error_t write_hls_key(); virtual srs_error_t refresh_m3u8(); virtual srs_error_t _refresh_m3u8(std::string m3u8_file); }; diff --git a/trunk/src/kernel/srs_kernel_ts.cpp b/trunk/src/kernel/srs_kernel_ts.cpp index 0a054bcec..354ee825b 100644 --- a/trunk/src/kernel/srs_kernel_ts.cpp +++ b/trunk/src/kernel/srs_kernel_ts.cpp @@ -34,15 +34,21 @@ #include using namespace std; +#ifdef SRS_AUTO_SSL +#include +#include +#endif + #include #include -#include #include #include #include #include #include +#define HLS_AES_ENCRYPT_BLOCK_LENGTH SRS_TS_PACKET_SIZE * 4 + // in ms, for HLS aac sync time. #define SRS_CONF_DEFAULT_AAC_SYNC 100 @@ -2610,64 +2616,94 @@ SrsVideoCodecId SrsTsContextWriter::video_codec() return vcodec; } -srs_error_t SrsEncFileWriter::write(void* buf, size_t count, ssize_t* pnwrite) +#ifdef SRS_AUTO_SSL +SrsEncFileWriter::SrsEncFileWriter() { + memset(iv,0,16); - srs_assert(count == SRS_TS_PACKET_SIZE); + buf = new char[HLS_AES_ENCRYPT_BLOCK_LENGTH]; + memset(buf, 0, HLS_AES_ENCRYPT_BLOCK_LENGTH); + + nb_buf = 0; + key = (unsigned char*)new AES_KEY(); +} + +SrsEncFileWriter::~SrsEncFileWriter() +{ + srs_freepa(buf); + + AES_KEY* k = (AES_KEY*)key; + srs_freep(k); +} + +srs_error_t SrsEncFileWriter::write(void* data, size_t count, ssize_t* pnwrite) +{ srs_error_t err = srs_success; + + srs_assert(count == SRS_TS_PACKET_SIZE); - if(buflength != HLS_AES_ENCRYPT_BLOCK_LENGTH) - { - memcpy(tmpbuf+buflength,(char*)buf,SRS_TS_PACKET_SIZE); - buflength += SRS_TS_PACKET_SIZE; - } - if(buflength == HLS_AES_ENCRYPT_BLOCK_LENGTH) - { - unsigned char encryptedbuf[HLS_AES_ENCRYPT_BLOCK_LENGTH]; - memset(encryptedbuf,0,HLS_AES_ENCRYPT_BLOCK_LENGTH); - AES_cbc_encrypt((unsigned char *)tmpbuf, (unsigned char *)encryptedbuf, HLS_AES_ENCRYPT_BLOCK_LENGTH, &key, iv, AES_ENCRYPT); - buflength = 0; - memset(tmpbuf,0,HLS_AES_ENCRYPT_BLOCK_LENGTH); - return SrsFileWriter::write(encryptedbuf,HLS_AES_ENCRYPT_BLOCK_LENGTH,pnwrite); - } - else - { - return err; + if (nb_buf < HLS_AES_ENCRYPT_BLOCK_LENGTH) { + memcpy(buf + nb_buf, (char*)data, SRS_TS_PACKET_SIZE); + nb_buf += SRS_TS_PACKET_SIZE; } - -}; + + if (nb_buf == HLS_AES_ENCRYPT_BLOCK_LENGTH) { + nb_buf = 0; + + char* cipher = new char[HLS_AES_ENCRYPT_BLOCK_LENGTH]; + SrsAutoFreeA(char, cipher); + + AES_KEY* k = (AES_KEY*)key; + AES_cbc_encrypt((unsigned char *)buf, (unsigned char *)cipher, HLS_AES_ENCRYPT_BLOCK_LENGTH, k, iv, AES_ENCRYPT); + + if ((err = SrsFileWriter::write(cipher, HLS_AES_ENCRYPT_BLOCK_LENGTH, pnwrite)) != srs_success) { + return srs_error_wrap(err, "write cipher"); + } + } + + return err; +} -srs_error_t SrsEncFileWriter::SetEncCfg(unsigned char* keyval,unsigned char *ivval) +srs_error_t SrsEncFileWriter::config_cipher(unsigned char* key, unsigned char* iv) { - srs_error_t err = srs_success; + + memcpy(this->iv, iv, 16); - if (AES_set_encrypt_key(keyval, 16*8, &key)) - { + AES_KEY* k = (AES_KEY*)this->key; + if (AES_set_encrypt_key(key, 16 * 8, k)) { return srs_error_new(ERROR_SYSTEM_FILE_WRITE, "set aes key failed"); - } - - memcpy(iv,ivval,16); + } + return err; } void SrsEncFileWriter::close() { - if(buflength > 0) - { - int addBytes = 16 - buflength % 16; - memset(tmpbuf + buflength, addBytes, addBytes); - unsigned char encryptedbuf[buflength+addBytes]; - memset(encryptedbuf,0,buflength+addBytes); - AES_cbc_encrypt((unsigned char *)tmpbuf, (unsigned char *)encryptedbuf, buflength+addBytes, &key, iv, AES_ENCRYPT); - SrsFileWriter::write(encryptedbuf,buflength+addBytes,NULL); + if(nb_buf > 0) { + int nb_padding = 16 - (nb_buf % 16); + if (nb_padding > 0) { + memset(buf + nb_buf, nb_padding, nb_padding); + } + + char* cipher = new char[nb_buf + nb_padding]; + SrsAutoFreeA(char, cipher); + + AES_KEY* k = (AES_KEY*)key; + AES_cbc_encrypt((unsigned char *)buf, (unsigned char *)cipher, nb_buf + nb_padding, k, iv, AES_ENCRYPT); + + srs_error_t err = srs_success; + if ((err = SrsFileWriter::write(cipher, nb_buf + nb_padding, NULL)) != srs_success) { + srs_warn("ignore err %s", srs_error_desc(err).c_str()); + srs_error_reset(err); + } - buflength = 0; - memset(tmpbuf,0,HLS_AES_ENCRYPT_BLOCK_LENGTH); + nb_buf = 0; } + SrsFileWriter::close(); } - +#endif SrsTsMessageCache::SrsTsMessageCache() { diff --git a/trunk/src/kernel/srs_kernel_ts.hpp b/trunk/src/kernel/srs_kernel_ts.hpp index 5fc16a7cc..6d1830826 100644 --- a/trunk/src/kernel/srs_kernel_ts.hpp +++ b/trunk/src/kernel/srs_kernel_ts.hpp @@ -31,13 +31,10 @@ #include #include #include -#include -#include #include #include - class SrsBuffer; class SrsTsMessageCache; class SrsTsContextWriter; @@ -1575,40 +1572,28 @@ public: virtual SrsVideoCodecId video_codec(); }; +#ifdef SRS_AUTO_SSL /* -* Used for HLS Encryption -*/ - - -#define HLS_AES_ENCRYPT_BLOCK_LENGTH 188*4 - + * Used for HLS Encryption + */ class SrsEncFileWriter: public SrsFileWriter { public: - SrsEncFileWriter() - { - memset(iv,0,16); - memset(tmpbuf,0,HLS_AES_ENCRYPT_BLOCK_LENGTH); - buflength = 0; - } - virtual ~SrsEncFileWriter(){} - - virtual srs_error_t write(void* buf, size_t count, ssize_t* pnwrite); - - srs_error_t SetEncCfg(unsigned char* key,unsigned char *iv); - + SrsEncFileWriter(); + virtual ~SrsEncFileWriter(); +public: + virtual srs_error_t write(void* data, size_t count, ssize_t* pnwrite); virtual void close(); - +public: + srs_error_t config_cipher(unsigned char* key, unsigned char* iv); private: - AES_KEY key; + unsigned char* key; unsigned char iv[16]; - private: - - char tmpbuf[HLS_AES_ENCRYPT_BLOCK_LENGTH]; - int buflength; - + char* buf; + int nb_buf; }; +#endif /** * TS messages cache, to group frames to TS message,