X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fstream_filter%2Fhttplive.c;h=6748ad25ed4275755817a2f5a5d1af40ac27f45e;hb=eb5ab7ff522fd661a73c5f557f5595b35d2ace40;hp=7e8c558b53ae6a828602ef1d33dd3d23f1214950;hpb=d0590ad182d82c5c856b8b4555bce93d5ccc1fb6;p=vlc diff --git a/modules/stream_filter/httplive.c b/modules/stream_filter/httplive.c index 7e8c558b53..6748ad25ed 100644 --- a/modules/stream_filter/httplive.c +++ b/modules/stream_filter/httplive.c @@ -29,12 +29,12 @@ #endif #include -#include #include #include #include +#include #include #include @@ -70,7 +70,7 @@ typedef struct segment_s char *url; char *psz_key_path; /* url key path */ - uint8_t psz_AES_key[16]; /* AES-128 */ + uint8_t aes_key[16]; /* AES-128 */ bool b_key_loaded; vlc_mutex_t lock; @@ -165,45 +165,57 @@ static void segment_Free(segment_t *segment); /**************************************************************************** * ****************************************************************************/ -static const char *const ext[] = { - "#EXT-X-TARGETDURATION", - "#EXT-X-MEDIA-SEQUENCE", - "#EXT-X-KEY", - "#EXT-X-ALLOW-CACHE", - "#EXT-X-ENDLIST", - "#EXT-X-STREAM-INF", - "#EXT-X-DISCONTINUITY", - "#EXT-X-VERSION" -}; - static bool isHTTPLiveStreaming(stream_t *s) { - const uint8_t *peek, *peek_end; + const uint8_t *peek; - int64_t i_size = stream_Peek(s->p_source, &peek, 46); - if (i_size < 1) + int size = stream_Peek(s->p_source, &peek, 46); + if (size < 7) return false; - if (strncasecmp((const char*)peek, "#EXTM3U", 7) != 0) + if (memcmp(peek, "#EXTM3U", 7) != 0) return false; + peek += 7; + size -= 7; + /* Parse stream and search for * EXT-X-TARGETDURATION or EXT-X-STREAM-INF tag, see * http://tools.ietf.org/html/draft-pantos-http-live-streaming-04#page-8 */ - peek_end = peek + i_size; - while(peek <= peek_end) - { - if (*peek == '#') + while (size--) + { + static const char *const ext[] = { + "TARGETDURATION", + "MEDIA-SEQUENCE", + "KEY", + "ALLOW-CACHE", + "ENDLIST", + "STREAM-INF", + "DISCONTINUITY", + "VERSION" + }; + + if (*peek++ != '#') + continue; + + if (size < 6) + continue; + + if (memcmp(peek, "EXT-X-", 6)) + continue; + + peek += 6; + size -= 6; + + for (size_t i = 0; i < ARRAY_SIZE(ext); i++) { - for (unsigned int i = 0; i < ARRAY_SIZE(ext); i++) - { - char *p = strstr((const char*)peek, ext[i]); - if (p != NULL) - return true; - } + size_t len = strlen(ext[i]); + if (size < len) + continue; + if (!memcmp(peek, ext[i], len)) + return true; } - peek++; - }; + } return false; } @@ -490,33 +502,38 @@ static char *parse_Attributes(const char *line, const char *attr) return NULL; } -static int hex2int(char c) +static int string_to_IV(char *string_hexa, uint8_t iv[AES_BLOCK_SIZE]) { - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - return -1; -} - -static int string_to_IV(const char *string_hexa, uint8_t iv[AES_BLOCK_SIZE]) -{ - const char *p = string_hexa; - uint8_t *d = iv; - unsigned int c; - - if (*p++ != '0') + unsigned long long iv_hi, iv_lo; + char *end = NULL; + if (*string_hexa++ != '0') return VLC_EGENERIC; - if (*p++ != 'x') + if (*string_hexa != 'x' && *string_hexa != 'X') return VLC_EGENERIC; - while (*p && *(p+1)) - { - c = hex2int(*p++) << 4; - c |= hex2int(*p++); - *d++ = c; + string_hexa++; + + size_t len = strlen(string_hexa); + if (len <= 16) { + iv_hi = 0; + iv_lo = strtoull(string_hexa, &end, 16); + if (end) + return VLC_EGENERIC; + } else { + iv_lo = strtoull(&string_hexa[len-16], NULL, 16); + if (end) + return VLC_EGENERIC; + string_hexa[len-16] = '\0'; + iv_hi = strtoull(string_hexa, NULL, 16); + if (end) + return VLC_EGENERIC; + } + + for (int i = 8; i ; --i) { + iv[ i] = iv_hi & 0xff; + iv[8+i] = iv_lo & 0xff; + iv_hi >>= 8; + iv_lo >>= 8; } return VLC_SUCCESS; @@ -557,20 +574,23 @@ static int parse_SegmentInformation(hls_stream_t *hls, char *p_read, int *durati return VLC_EGENERIC; int value; + char *endptr; if (hls->version < 3) { - value = strtol(token, NULL, 10); - if (errno == ERANGE) - { - *duration = -1; - return VLC_EGENERIC; - } - *duration = value; + errno = 0; + value = strtol(token, &endptr, 10); + if (token == endptr || errno == ERANGE) + { + *duration = -1; + return VLC_EGENERIC; + } + *duration = value; } else { - double d = strtod(token, (char **) NULL); - if (errno == ERANGE) + errno = 0; + double d = strtof(token, &endptr); + if (token == endptr || errno == ERANGE) { *duration = -1; return VLC_EGENERIC; @@ -579,6 +599,7 @@ static int parse_SegmentInformation(hls_stream_t *hls, char *p_read, int *durati value = ((int)d) + 1; else value = ((int)d); + *duration = value; } /* Ignore the rest of the line */ @@ -778,7 +799,10 @@ static int parse_Key(stream_t *s, hls_stream_t *hls, char *p_read) */ if (string_to_IV(iv, hls->psz_AES_IV) == VLC_EGENERIC) + { + msg_Err(s, "IV invalid"); err = VLC_EGENERIC; + } else hls->b_iv_loaded = true; free(value); @@ -1071,9 +1095,6 @@ static int parse_M3U8(stream_t *s, vlc_array_t *streams, uint8_t *buffer, const static int hls_DownloadSegmentKey(stream_t *s, segment_t *seg) { - uint8_t aeskey[32]; /* AES-512 can use up to 32 bytes */ - ssize_t len; - stream_t *p_m3u8 = stream_UrlNew(s, seg->psz_key_path); if (p_m3u8 == NULL) { @@ -1081,18 +1102,14 @@ static int hls_DownloadSegmentKey(stream_t *s, segment_t *seg) return VLC_EGENERIC; } - len = stream_Read(p_m3u8, aeskey, sizeof(aeskey)); + int len = stream_Read(p_m3u8, seg->aes_key, sizeof(seg->aes_key)); + stream_Delete(p_m3u8); if (len != AES_BLOCK_SIZE) { - msg_Err(s, "The AES key loaded doesn't have the right size (%zd)", len); - stream_Delete(p_m3u8); + msg_Err(s, "The AES key loaded doesn't have the right size (%d)", len); return VLC_EGENERIC; } - memcpy(seg->psz_AES_key, aeskey, AES_BLOCK_SIZE); - - stream_Delete(p_m3u8); - return VLC_SUCCESS; } @@ -1117,7 +1134,7 @@ static int hls_ManageSegmentKeys(stream_t *s, hls_stream_t *hls) * try to copy it, and don't load the key */ if (prev_seg && prev_seg->b_key_loaded && strcmp(seg->psz_key_path, prev_seg->psz_key_path) == 0) { - memcpy(seg->psz_AES_key, prev_seg->psz_AES_key, AES_BLOCK_SIZE); + memcpy(seg->aes_key, prev_seg->aes_key, AES_BLOCK_SIZE); seg->b_key_loaded = true; continue; } @@ -1156,8 +1173,8 @@ static int hls_DecodeSegmentData(stream_t *s, hls_stream_t *hls, segment_t *segm } /* Set key */ - i_gcrypt_err = gcry_cipher_setkey(aes_ctx, segment->psz_AES_key, - sizeof(segment->psz_AES_key)); + i_gcrypt_err = gcry_cipher_setkey(aes_ctx, segment->aes_key, + sizeof(segment->aes_key)); if (i_gcrypt_err) { msg_Err(s, "gcry_cipher_setkey failed: %s", gpg_strerror(i_gcrypt_err)); @@ -1795,21 +1812,27 @@ static char *ReadLine(uint8_t *buffer, uint8_t **pos, const size_t len) while (p < end) { - if ((*p == '\n') || (*p == '\0')) + if ((*p == '\r') || (*p == '\n') || (*p == '\0')) break; p++; } - /* copy line excluding \n or \0 */ + /* copy line excluding \r \n or \0 */ line = strndup((char *)begin, p - begin); - if (*p == '\0') - *pos = end; - else + while ((*p == '\r') || (*p == '\n') || (*p == '\0')) { - /* next pass start after \n */ - p++; - *pos = p; + if (*p == '\0') + { + *pos = end; + break; + } + else + { + /* next pass start after \r and \n */ + p++; + *pos = p; + } } return line;