--- a/media/libnestegg/src/nestegg.c
+++ b/media/libnestegg/src/nestegg.c
@@ -7,148 +7,172 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "halloc.h"
#include "nestegg/nestegg.h"
/* EBML Elements */
-#define ID_EBML 0x1a45dfa3
-#define ID_EBML_VERSION 0x4286
-#define ID_EBML_READ_VERSION 0x42f7
-#define ID_EBML_MAX_ID_LENGTH 0x42f2
-#define ID_EBML_MAX_SIZE_LENGTH 0x42f3
-#define ID_DOCTYPE 0x4282
-#define ID_DOCTYPE_VERSION 0x4287
-#define ID_DOCTYPE_READ_VERSION 0x4285
+#define ID_EBML 0x1a45dfa3
+#define ID_EBML_VERSION 0x4286
+#define ID_EBML_READ_VERSION 0x42f7
+#define ID_EBML_MAX_ID_LENGTH 0x42f2
+#define ID_EBML_MAX_SIZE_LENGTH 0x42f3
+#define ID_DOCTYPE 0x4282
+#define ID_DOCTYPE_VERSION 0x4287
+#define ID_DOCTYPE_READ_VERSION 0x4285
/* Global Elements */
-#define ID_VOID 0xec
-#define ID_CRC32 0xbf
+#define ID_VOID 0xec
+#define ID_CRC32 0xbf
/* WebM Elements */
-#define ID_SEGMENT 0x18538067
+#define ID_SEGMENT 0x18538067
/* Seek Head Elements */
-#define ID_SEEK_HEAD 0x114d9b74
-#define ID_SEEK 0x4dbb
-#define ID_SEEK_ID 0x53ab
-#define ID_SEEK_POSITION 0x53ac
+#define ID_SEEK_HEAD 0x114d9b74
+#define ID_SEEK 0x4dbb
+#define ID_SEEK_ID 0x53ab
+#define ID_SEEK_POSITION 0x53ac
/* Info Elements */
-#define ID_INFO 0x1549a966
-#define ID_TIMECODE_SCALE 0x2ad7b1
-#define ID_DURATION 0x4489
+#define ID_INFO 0x1549a966
+#define ID_TIMECODE_SCALE 0x2ad7b1
+#define ID_DURATION 0x4489
/* Cluster Elements */
-#define ID_CLUSTER 0x1f43b675
-#define ID_TIMECODE 0xe7
-#define ID_BLOCK_GROUP 0xa0
-#define ID_SIMPLE_BLOCK 0xa3
+#define ID_CLUSTER 0x1f43b675
+#define ID_TIMECODE 0xe7
+#define ID_BLOCK_GROUP 0xa0
+#define ID_SIMPLE_BLOCK 0xa3
/* BlockGroup Elements */
-#define ID_BLOCK 0xa1
-#define ID_BLOCK_ADDITIONS 0x75a1
-#define ID_BLOCK_DURATION 0x9b
-#define ID_REFERENCE_BLOCK 0xfb
-#define ID_DISCARD_PADDING 0x75a2
+#define ID_BLOCK 0xa1
+#define ID_BLOCK_ADDITIONS 0x75a1
+#define ID_BLOCK_DURATION 0x9b
+#define ID_REFERENCE_BLOCK 0xfb
+#define ID_DISCARD_PADDING 0x75a2
/* BlockAdditions Elements */
-#define ID_BLOCK_MORE 0xa6
+#define ID_BLOCK_MORE 0xa6
/* BlockMore Elements */
-#define ID_BLOCK_ADD_ID 0xee
-#define ID_BLOCK_ADDITIONAL 0xa5
+#define ID_BLOCK_ADD_ID 0xee
+#define ID_BLOCK_ADDITIONAL 0xa5
/* Tracks Elements */
-#define ID_TRACKS 0x1654ae6b
-#define ID_TRACK_ENTRY 0xae
-#define ID_TRACK_NUMBER 0xd7
-#define ID_TRACK_UID 0x73c5
-#define ID_TRACK_TYPE 0x83
-#define ID_FLAG_ENABLED 0xb9
-#define ID_FLAG_DEFAULT 0x88
-#define ID_FLAG_LACING 0x9c
-#define ID_TRACK_TIMECODE_SCALE 0x23314f
-#define ID_LANGUAGE 0x22b59c
-#define ID_CODEC_ID 0x86
-#define ID_CODEC_PRIVATE 0x63a2
-#define ID_CODEC_DELAY 0x56aa
-#define ID_SEEK_PREROLL 0x56bb
-#define ID_DEFAULT_DURATION 0x23e383
+#define ID_TRACKS 0x1654ae6b
+#define ID_TRACK_ENTRY 0xae
+#define ID_TRACK_NUMBER 0xd7
+#define ID_TRACK_UID 0x73c5
+#define ID_TRACK_TYPE 0x83
+#define ID_FLAG_ENABLED 0xb9
+#define ID_FLAG_DEFAULT 0x88
+#define ID_FLAG_LACING 0x9c
+#define ID_TRACK_TIMECODE_SCALE 0x23314f
+#define ID_LANGUAGE 0x22b59c
+#define ID_CODEC_ID 0x86
+#define ID_CODEC_PRIVATE 0x63a2
+#define ID_CODEC_DELAY 0x56aa
+#define ID_SEEK_PREROLL 0x56bb
+#define ID_DEFAULT_DURATION 0x23e383
/* Video Elements */
-#define ID_VIDEO 0xe0
-#define ID_STEREO_MODE 0x53b8
-#define ID_ALPHA_MODE 0x53c0
-#define ID_PIXEL_WIDTH 0xb0
-#define ID_PIXEL_HEIGHT 0xba
-#define ID_PIXEL_CROP_BOTTOM 0x54aa
-#define ID_PIXEL_CROP_TOP 0x54bb
-#define ID_PIXEL_CROP_LEFT 0x54cc
-#define ID_PIXEL_CROP_RIGHT 0x54dd
-#define ID_DISPLAY_WIDTH 0x54b0
-#define ID_DISPLAY_HEIGHT 0x54ba
+#define ID_VIDEO 0xe0
+#define ID_STEREO_MODE 0x53b8
+#define ID_ALPHA_MODE 0x53c0
+#define ID_PIXEL_WIDTH 0xb0
+#define ID_PIXEL_HEIGHT 0xba
+#define ID_PIXEL_CROP_BOTTOM 0x54aa
+#define ID_PIXEL_CROP_TOP 0x54bb
+#define ID_PIXEL_CROP_LEFT 0x54cc
+#define ID_PIXEL_CROP_RIGHT 0x54dd
+#define ID_DISPLAY_WIDTH 0x54b0
+#define ID_DISPLAY_HEIGHT 0x54ba
/* Audio Elements */
-#define ID_AUDIO 0xe1
-#define ID_SAMPLING_FREQUENCY 0xb5
-#define ID_CHANNELS 0x9f
-#define ID_BIT_DEPTH 0x6264
+#define ID_AUDIO 0xe1
+#define ID_SAMPLING_FREQUENCY 0xb5
+#define ID_CHANNELS 0x9f
+#define ID_BIT_DEPTH 0x6264
/* Cues Elements */
-#define ID_CUES 0x1c53bb6b
-#define ID_CUE_POINT 0xbb
-#define ID_CUE_TIME 0xb3
-#define ID_CUE_TRACK_POSITIONS 0xb7
-#define ID_CUE_TRACK 0xf7
-#define ID_CUE_CLUSTER_POSITION 0xf1
-#define ID_CUE_BLOCK_NUMBER 0x5378
+#define ID_CUES 0x1c53bb6b
+#define ID_CUE_POINT 0xbb
+#define ID_CUE_TIME 0xb3
+#define ID_CUE_TRACK_POSITIONS 0xb7
+#define ID_CUE_TRACK 0xf7
+#define ID_CUE_CLUSTER_POSITION 0xf1
+#define ID_CUE_BLOCK_NUMBER 0x5378
+
+/* Encoding Elements */
+#define ID_CONTENT_ENCODINGS 0x6d80
+#define ID_CONTENT_ENCODING 0x6240
+#define ID_CONTENT_ENCODING_TYPE 0x5033
+
+/* Encryption Elements */
+#define ID_CONTENT_ENCRYPTION 0x5035
+#define ID_CONTENT_ENC_ALGO 0x47e1
+#define ID_CONTENT_ENC_KEY_ID 0x47e2
+#define ID_CONTENT_ENC_AES_SETTINGS 0x47e7
+#define ID_AES_SETTINGS_CIPHER_MODE 0x47e8
/* EBML Types */
enum ebml_type_enum {
TYPE_UNKNOWN,
TYPE_MASTER,
TYPE_UINT,
TYPE_FLOAT,
TYPE_STRING,
TYPE_BINARY
};
-#define LIMIT_STRING (1 << 20)
-#define LIMIT_BINARY (1 << 24)
-#define LIMIT_BLOCK (1 << 30)
-#define LIMIT_FRAME (1 << 28)
+#define LIMIT_STRING (1 << 20)
+#define LIMIT_BINARY (1 << 24)
+#define LIMIT_BLOCK (1 << 30)
+#define LIMIT_FRAME (1 << 28)
/* Field Flags */
-#define DESC_FLAG_NONE 0
-#define DESC_FLAG_MULTI (1 << 0)
-#define DESC_FLAG_SUSPEND (1 << 1)
-#define DESC_FLAG_OFFSET (1 << 2)
+#define DESC_FLAG_NONE 0
+#define DESC_FLAG_MULTI (1 << 0)
+#define DESC_FLAG_SUSPEND (1 << 1)
+#define DESC_FLAG_OFFSET (1 << 2)
/* Block Header Flags */
#define SIMPLE_BLOCK_FLAGS_KEYFRAME (1 << 7)
#define BLOCK_FLAGS_LACING 6
/* Lacing Constants */
-#define LACING_NONE 0
-#define LACING_XIPH 1
-#define LACING_FIXED 2
-#define LACING_EBML 3
+#define LACING_NONE 0
+#define LACING_XIPH 1
+#define LACING_FIXED 2
+#define LACING_EBML 3
/* Track Types */
-#define TRACK_TYPE_VIDEO 1
-#define TRACK_TYPE_AUDIO 2
+#define TRACK_TYPE_VIDEO 1
+#define TRACK_TYPE_AUDIO 2
/* Track IDs */
-#define TRACK_ID_VP8 "V_VP8"
-#define TRACK_ID_VP9 "V_VP9"
-#define TRACK_ID_VORBIS "A_VORBIS"
-#define TRACK_ID_OPUS "A_OPUS"
+#define TRACK_ID_VP8 "V_VP8"
+#define TRACK_ID_VP9 "V_VP9"
+#define TRACK_ID_VORBIS "A_VORBIS"
+#define TRACK_ID_OPUS "A_OPUS"
+
+/* Track Encryption */
+#define CONTENT_ENC_ALGO_AES 5
+#define AES_SETTINGS_CIPHER_CTR 1
+
+/* Packet Encryption */
+#define SIGNAL_BYTE_SIZE 1
+#define IV_SIZE 8
+
+/* Signal Byte */
+#define PACKET_ENCRYPTED 1
+#define ENCRYPTED_BIT_MASK (1 << 0)
enum vint_mask {
MASK_NONE,
MASK_FIRST_BIT
};
struct ebml_binary {
unsigned char * data;
@@ -218,32 +242,52 @@ struct video {
};
struct audio {
struct ebml_type sampling_frequency;
struct ebml_type channels;
struct ebml_type bit_depth;
};
+struct content_enc_aes_settings {
+ struct ebml_type aes_settings_cipher_mode;
+};
+
+struct content_encryption {
+ struct ebml_type content_enc_algo;
+ struct ebml_type content_enc_key_id;
+ struct ebml_list content_enc_aes_settings;
+};
+
+struct content_encoding {
+ struct ebml_type content_encoding_type;
+ struct ebml_list content_encryption;
+};
+
+struct content_encodings {
+ struct ebml_list content_encoding;
+};
+
struct track_entry {
struct ebml_type number;
struct ebml_type uid;
struct ebml_type type;
struct ebml_type flag_enabled;
struct ebml_type flag_default;
struct ebml_type flag_lacing;
struct ebml_type track_timecode_scale;
struct ebml_type language;
struct ebml_type codec_id;
struct ebml_type codec_private;
struct ebml_type codec_delay;
struct ebml_type seek_preroll;
struct ebml_type default_duration;
struct video video;
struct audio audio;
+ struct content_encodings content_encodings;
};
struct tracks {
struct ebml_list track_entry;
};
struct cue_track_positions {
struct ebml_type track;
@@ -280,19 +324,26 @@ struct list_node {
struct saved_state {
int64_t stream_offset;
uint64_t last_id;
uint64_t last_size;
int last_valid;
};
+struct frame_encryption {
+ unsigned char * iv;
+ size_t length;
+ uint8_t signal_byte;
+};
+
struct frame {
unsigned char * data;
size_t length;
+ struct frame_encryption * frame_encryption;
struct frame * next;
};
struct block_additional {
unsigned int id;
unsigned char * data;
size_t length;
struct block_additional * next;
@@ -404,32 +455,56 @@ static struct ebml_element_desc ne_video
static struct ebml_element_desc ne_audio_elements[] = {
E_FIELD(ID_SAMPLING_FREQUENCY, TYPE_FLOAT, struct audio, sampling_frequency),
E_FIELD(ID_CHANNELS, TYPE_UINT, struct audio, channels),
E_FIELD(ID_BIT_DEPTH, TYPE_UINT, struct audio, bit_depth),
E_LAST
};
+static struct ebml_element_desc ne_content_enc_aes_settings_elements[] = {
+ E_FIELD(ID_AES_SETTINGS_CIPHER_MODE, TYPE_UINT, struct content_enc_aes_settings, aes_settings_cipher_mode),
+ E_LAST
+};
+
+static struct ebml_element_desc ne_content_encryption_elements[] = {
+ E_FIELD(ID_CONTENT_ENC_ALGO, TYPE_UINT, struct content_encryption, content_enc_algo),
+ E_FIELD(ID_CONTENT_ENC_KEY_ID, TYPE_BINARY, struct content_encryption, content_enc_key_id),
+ E_MASTER(ID_CONTENT_ENC_AES_SETTINGS, TYPE_MASTER, struct content_encryption, content_enc_aes_settings),
+ E_LAST
+};
+
+static struct ebml_element_desc ne_content_encoding_elements[] = {
+ E_FIELD(ID_CONTENT_ENCODING_TYPE, TYPE_UINT, struct content_encoding, content_encoding_type),
+ E_MASTER(ID_CONTENT_ENCRYPTION, TYPE_MASTER, struct content_encoding, content_encryption),
+ E_LAST
+};
+
+static struct ebml_element_desc ne_content_encodings_elements[] = {
+ E_MASTER(ID_CONTENT_ENCODING, TYPE_MASTER, struct content_encodings, content_encoding),
+ E_LAST
+};
+
static struct ebml_element_desc ne_track_entry_elements[] = {
E_FIELD(ID_TRACK_NUMBER, TYPE_UINT, struct track_entry, number),
E_FIELD(ID_TRACK_UID, TYPE_UINT, struct track_entry, uid),
E_FIELD(ID_TRACK_TYPE, TYPE_UINT, struct track_entry, type),
E_FIELD(ID_FLAG_ENABLED, TYPE_UINT, struct track_entry, flag_enabled),
E_FIELD(ID_FLAG_DEFAULT, TYPE_UINT, struct track_entry, flag_default),
E_FIELD(ID_FLAG_LACING, TYPE_UINT, struct track_entry, flag_lacing),
E_FIELD(ID_TRACK_TIMECODE_SCALE, TYPE_FLOAT, struct track_entry, track_timecode_scale),
E_FIELD(ID_LANGUAGE, TYPE_STRING, struct track_entry, language),
E_FIELD(ID_CODEC_ID, TYPE_STRING, struct track_entry, codec_id),
E_FIELD(ID_CODEC_PRIVATE, TYPE_BINARY, struct track_entry, codec_private),
E_FIELD(ID_CODEC_DELAY, TYPE_UINT, struct track_entry, codec_delay),
E_FIELD(ID_SEEK_PREROLL, TYPE_UINT, struct track_entry, seek_preroll),
E_FIELD(ID_DEFAULT_DURATION, TYPE_UINT, struct track_entry, default_duration),
E_SINGLE_MASTER(ID_VIDEO, TYPE_MASTER, struct track_entry, video),
E_SINGLE_MASTER(ID_AUDIO, TYPE_MASTER, struct track_entry, audio),
+ E_SINGLE_MASTER(ID_CONTENT_ENCODINGS, TYPE_MASTER, struct track_entry, content_encodings),
E_LAST
};
static struct ebml_element_desc ne_tracks_elements[] = {
E_MASTER(ID_TRACK_ENTRY, TYPE_MASTER, struct tracks, track_entry),
E_LAST
};
@@ -1068,16 +1143,65 @@ ne_parse(nestegg * ctx, struct ebml_elem
if (r != 1)
while (ctx->ancestor)
ne_ctx_pop(ctx);
return r;
}
static int
+ne_read_block_encryption(nestegg * ctx, struct track_entry const * entry,
+ uint64_t * encoding_type, uint64_t * encryption_algo,
+ uint64_t * encryption_mode)
+{
+ struct content_encoding * encoding;
+ struct content_encryption * encryption;
+ struct content_enc_aes_settings * aes_settings;
+
+ *encoding_type = 0;
+ if (entry->content_encodings.content_encoding.head) {
+ encoding = entry->content_encodings.content_encoding.head->data;
+ if (ne_get_uint(encoding->content_encoding_type, encoding_type) != 0)
+ return -1;
+
+ if (*encoding_type == NESTEGG_ENCODING_ENCRYPTION) {
+ /* Metadata states content is encrypted */
+ if (!encoding->content_encryption.head)
+ return -1;
+
+ encryption = encoding->content_encryption.head->data;
+ if (ne_get_uint(encryption->content_enc_algo, encryption_algo) != 0) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncAlgo element found");
+ return -1;
+ }
+
+ if (*encryption_algo != CONTENT_ENC_ALGO_AES) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed ContentEncAlgo used");
+ return -1;
+ }
+
+ if (!encryption->content_enc_aes_settings.head) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncAESSettings element found");
+ return -1;
+ }
+
+ aes_settings = encryption->content_enc_aes_settings.head->data;
+ *encryption_mode = AES_SETTINGS_CIPHER_CTR;
+ ne_get_uint(aes_settings->aes_settings_cipher_mode, encryption_mode);
+
+ if (*encryption_mode != AES_SETTINGS_CIPHER_CTR) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed AESSettingsCipherMode used");
+ return -1;
+ }
+ }
+ }
+ return 1;
+}
+
+static int
ne_read_xiph_lace_value(nestegg_io * io, uint64_t * value, size_t * consumed)
{
int r;
uint64_t lace;
r = ne_read_uint(io, &lace, 1);
if (r != 1)
return r;
@@ -1219,20 +1343,21 @@ static int
ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_packet ** data)
{
int r;
int64_t timecode, abs_timecode;
nestegg_packet * pkt;
struct frame * f, * last;
struct track_entry * entry;
double track_scale;
- uint64_t track_number, length, frame_sizes[256], cluster_tc, flags, frames, tc_scale, total;
+ uint64_t track_number, length, frame_sizes[256], cluster_tc, flags, frames, tc_scale, total,
+ encoding_type, encryption_algo, encryption_mode;
unsigned int i, lacing, track;
- uint8_t keyframe = NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN;
- size_t consumed = 0;
+ uint8_t signal_byte, keyframe = NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN;
+ size_t consumed = 0, data_size, encryption_size;
*data = NULL;
if (block_size > LIMIT_BLOCK)
return -1;
r = ne_read_vint(ctx->io, &track_number, &length);
if (r != 1)
@@ -1319,16 +1444,26 @@ ne_read_block(nestegg * ctx, uint64_t bl
if (ne_map_track_number_to_index(ctx, track_number, &track) != 0)
return -1;
entry = ne_find_track_entry(ctx, track);
if (!entry)
return -1;
+ r = ne_read_block_encryption(ctx, entry, &encoding_type, &encryption_algo, &encryption_mode);
+ if (r != 1)
+ return r;
+
+ /* Encryption does not support lacing */
+ if (lacing != LACING_NONE && encoding_type == NESTEGG_ENCODING_ENCRYPTION) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "Encrypted blocks may not also be laced");
+ return -1;
+ }
+
track_scale = 1.0;
tc_scale = ne_get_timecode_scale(ctx);
if (!ctx->read_cluster_timecode)
return -1;
cluster_tc = ctx->cluster_timecode;
@@ -1352,25 +1487,74 @@ ne_read_block(nestegg * ctx, uint64_t bl
nestegg_free_packet(pkt);
return -1;
}
f = ne_alloc(sizeof(*f));
if (!f) {
nestegg_free_packet(pkt);
return -1;
}
- f->data = ne_alloc(frame_sizes[i]);
+ /* Parse encryption */
+ if (encoding_type == NESTEGG_ENCODING_ENCRYPTION) {
+ r = ne_io_read(ctx->io, &signal_byte, SIGNAL_BYTE_SIZE);
+ if (r != 1) {
+ free(f);
+ nestegg_free_packet(pkt);
+ return r;
+ }
+ f->frame_encryption = ne_alloc(sizeof(*f->frame_encryption));
+ if (!f->frame_encryption) {
+ free(f);
+ nestegg_free_packet(pkt);
+ return -1;
+ }
+ f->frame_encryption->signal_byte = signal_byte;
+ if ((signal_byte & ENCRYPTED_BIT_MASK) == PACKET_ENCRYPTED) {
+ f->frame_encryption->iv = ne_alloc(IV_SIZE);
+ if (!f->frame_encryption->iv) {
+ free(f->frame_encryption);
+ free(f);
+ nestegg_free_packet(pkt);
+ return -1;
+ }
+ r = ne_io_read(ctx->io, f->frame_encryption->iv, IV_SIZE);
+ if (r != 1) {
+ free(f->frame_encryption);
+ free(f);
+ nestegg_free_packet(pkt);
+ return r;
+ }
+ f->frame_encryption->length = IV_SIZE;
+ encryption_size = SIGNAL_BYTE_SIZE + IV_SIZE;
+ } else {
+ f->frame_encryption->iv = NULL;
+ f->frame_encryption->length = 0;
+ encryption_size = SIGNAL_BYTE_SIZE;
+ }
+ } else {
+ f->frame_encryption = NULL;
+ encryption_size = 0;
+ }
+ data_size = frame_sizes[i] - encryption_size;
+ /* Encryption parsed */
+ f->data = ne_alloc(data_size);
if (!f->data) {
+ if (f->frame_encryption)
+ free(f->frame_encryption->iv);
+ free(f->frame_encryption);
free(f);
nestegg_free_packet(pkt);
return -1;
}
- f->length = frame_sizes[i];
- r = ne_io_read(ctx->io, f->data, frame_sizes[i]);
+ f->length = data_size;
+ r = ne_io_read(ctx->io, f->data, data_size);
if (r != 1) {
+ if (f->frame_encryption)
+ free(f->frame_encryption->iv);
+ free(f->frame_encryption);
free(f->data);
free(f);
nestegg_free_packet(pkt);
return r;
}
if (!last)
pkt->frame = f;
@@ -2297,16 +2481,118 @@ nestegg_track_audio_params(nestegg * ctx
value = 0;
ne_get_uint(entry->seek_preroll, &value);
params->seek_preroll = value;
return 0;
}
int
+nestegg_track_encoding(nestegg * ctx, unsigned int track)
+{
+ struct track_entry * entry;
+ struct content_encoding * encoding;
+ uint64_t encoding_value;
+
+ entry = ne_find_track_entry(ctx, track);
+ if (!entry) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "No track entry found");
+ return -1;
+ }
+
+ if (!entry->content_encodings.content_encoding.head) {
+ /* Default encoding is compression */
+ return NESTEGG_ENCODING_COMPRESSION;
+ }
+
+ encoding = entry->content_encodings.content_encoding.head->data;
+
+ encoding_value = NESTEGG_ENCODING_COMPRESSION;
+ ne_get_uint(encoding->content_encoding_type, &encoding_value);
+ if (encoding_value != NESTEGG_ENCODING_COMPRESSION && encoding_value != NESTEGG_ENCODING_ENCRYPTION) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "Invalid ContentEncoding element found");
+ return -1;
+ }
+
+ return encoding_value;
+}
+
+int
+nestegg_track_content_enc_key_id(nestegg * ctx, unsigned int track, unsigned char const ** content_enc_key_id,
+ size_t * content_enc_key_id_length)
+{
+ struct track_entry * entry;
+ struct content_encoding * encoding;
+ struct content_encryption * encryption;
+ struct content_enc_aes_settings * aes_settings;
+ struct nestegg_encryption_params;
+ uint64_t value;
+ struct ebml_binary enc_key_id;
+
+ entry = ne_find_track_entry(ctx, track);
+ if (!entry) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "No track entry found");
+ return -1;
+ }
+
+ if (!entry->content_encodings.content_encoding.head) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncoding element found");
+ return -1;
+ }
+
+ encoding = entry->content_encodings.content_encoding.head->data;
+
+ value = 0;
+ ne_get_uint(encoding->content_encoding_type, &value);
+ if (value != NESTEGG_ENCODING_ENCRYPTION) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed ContentEncodingType found");
+ return -1;
+ }
+
+ if (!encoding->content_encryption.head) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncryption element found");
+ return -1;
+ }
+
+ encryption = encoding->content_encryption.head->data;
+
+ value = 0;
+ ne_get_uint(encryption->content_enc_algo, &value);
+
+ if (value != CONTENT_ENC_ALGO_AES) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed ContentEncAlgo found");
+ return -1;
+ }
+
+ if (!encryption->content_enc_aes_settings.head) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "No ContentEncAesSettings element found");
+ return -1;
+ }
+
+ aes_settings = encryption->content_enc_aes_settings.head->data;
+ value = AES_SETTINGS_CIPHER_CTR;
+ ne_get_uint(aes_settings->aes_settings_cipher_mode, &value);
+
+ if (value != AES_SETTINGS_CIPHER_CTR) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "Disallowed AESSettingCipherMode used");
+ return -1;
+ }
+
+ if (ne_get_binary(encryption->content_enc_key_id, &enc_key_id) != 0) {
+ ctx->log(ctx, NESTEGG_LOG_ERROR, "Could not retrieve track ContentEncKeyId");
+ return -1;
+ }
+
+ *content_enc_key_id = enc_key_id.data;
+ *content_enc_key_id_length = enc_key_id.length;
+
+ return 0;
+}
+
+int
nestegg_track_default_duration(nestegg * ctx, unsigned int track,
uint64_t * duration)
{
struct track_entry * entry;
uint64_t value;
entry = ne_find_track_entry(ctx, track);
if (!entry)
@@ -2471,16 +2757,20 @@ void
nestegg_free_packet(nestegg_packet * pkt)
{
struct frame * frame;
struct block_additional * block_additional;
while (pkt->frame) {
frame = pkt->frame;
pkt->frame = frame->next;
+ if (frame->frame_encryption) {
+ free(frame->frame_encryption->iv);
+ }
+ free(frame->frame_encryption);
free(frame->data);
free(frame);
}
while (pkt->block_additional) {
block_additional = pkt->block_additional;
pkt->block_additional = block_additional->next;
free(block_additional->data);
@@ -2592,16 +2882,60 @@ nestegg_packet_additional_data(nestegg_p
}
a = a->next;
}
return -1;
}
int
+nestegg_packet_encryption(nestegg_packet * pkt)
+{
+ struct frame * f = pkt->frame;
+ unsigned char encrypted_bit;
+
+ if (!f->frame_encryption)
+ return NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE;
+
+ /* Should never have parsed blocks with both encryption and lacing */
+ assert(f->next == NULL);
+
+ encrypted_bit = f->frame_encryption->signal_byte & ENCRYPTED_BIT_MASK;
+
+ if (encrypted_bit != PACKET_ENCRYPTED)
+ return NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED;
+
+ return NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED;
+}
+
+int
+nestegg_packet_iv(nestegg_packet * pkt, unsigned char const ** iv, size_t * length)
+{
+ struct frame * f = pkt->frame;
+ unsigned char encrypted_bit;
+
+ *iv = NULL;
+ *length = 0;
+ if (!f->frame_encryption)
+ return -1;
+
+ /* Should never have parsed blocks with both encryption and lacing */
+ assert(f->next == NULL);
+
+ encrypted_bit = f->frame_encryption->signal_byte & ENCRYPTED_BIT_MASK;
+
+ if (encrypted_bit != PACKET_ENCRYPTED)
+ return 0;
+
+ *iv = f->frame_encryption->iv;
+ *length = f->frame_encryption->length;
+ return 0;
+}
+
+int
nestegg_has_cues(nestegg * ctx)
{
return ctx->segment.cues.cue_point.head ||
ne_find_seek_for_id(ctx->segment.seek_head.head, ID_CUES);
}
int
nestegg_sniff(unsigned char const * buffer, size_t length)