Bug 1257726 - Update to latest upstream version of nestegg. r=kinetik

Bring in updated nestegg library, the newly exposed encryption
functionality will be used to enable WebM EME.

MozReview-Commit-ID: Hv6hSFjlS5c

--HG--
extra : rebase_source : c759a702c205111d65aa2002564559210c662d5f
This commit is contained in:
Bryce Van Dyk 2016-05-04 11:14:29 +12:00
Родитель c6bd7cd3df
Коммит 85f8335784
3 изменённых файлов: 478 добавлений и 92 удалений

Просмотреть файл

@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
The nestegg git repository is: git://github.com/kinetiknz/nestegg.git
The git commit ID used was d493c8a7abd05c6911cd546fd6b5c82b366f5203.
The git commit ID used was 3bc788d4de8f11a1e6b625047f49b9d35dce824f.

Просмотреть файл

@ -89,6 +89,13 @@ extern "C" {
#define NESTEGG_LOG_ERROR 1000 /**< Error level log message. */
#define NESTEGG_LOG_CRITICAL 10000 /**< Critical level log message. */
#define NESTEGG_ENCODING_COMPRESSION 0 /**< Content encoding type is compression. */
#define NESTEGG_ENCODING_ENCRYPTION 1 /**< Content encoding type is encryption. */
#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE 0 /**< Packet does not have signal byte */
#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED 1 /**< Packet has signal byte and is unencrypted */
#define NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED 2 /**< Packet has signal byte and is encrypted */
#define NESTEGG_PACKET_HAS_KEYFRAME_FALSE 0 /**< Packet contains only keyframes. */
#define NESTEGG_PACKET_HAS_KEYFRAME_TRUE 1 /**< Packet does not contain any keyframes */
#define NESTEGG_PACKET_HAS_KEYFRAME_UNKNOWN 2 /**< Packet may or may not contain keyframes */
@ -288,6 +295,28 @@ int nestegg_track_video_params(nestegg * context, unsigned int track,
int nestegg_track_audio_params(nestegg * context, unsigned int track,
nestegg_audio_params * params);
/** Query the encoding status for @a track. If a track has multiple encodings
the first will be returned.
@param context Stream context initialized by #nestegg_init.
@param track Zero based track number.
@retval #NESTEGG_ENCODING_COMPRESSION The track is compressed, but not encrypted.
@retval #NESTEGG_ENCODING_ENCRYPTION The track is encrypted and compressed.
@retval -1 Error. */
int nestegg_track_encoding(nestegg * context, unsigned int track);
/** Query the ContentEncKeyId for @a track. Will return an error if the track
in not encrypted, or is not recognized.
@param context Stream context initialized by #nestegg_init.
@param track Zero based track number.
@param content_enc_key_id Storage for queried id. The content encryption key used.
Owned by nestegg and will be freed separately.
@param content_enc_key_id_length Length of the queried ContentEncKeyId in bytes.
@retval 0 Success.
@retval -1 Error. */
int nestegg_track_content_enc_key_id(nestegg * context, unsigned int track,
unsigned char const ** content_enc_key_id,
size_t * content_enc_key_id_length);
/** Query the default frame duration for @a track. For a video track, this
is typically the inverse of the video frame rate.
@param context Stream context initialized by #nestegg_init.
@ -387,6 +416,29 @@ int nestegg_packet_additional_data(nestegg_packet * packet, unsigned int id,
int nestegg_packet_discard_padding(nestegg_packet * packet,
int64_t * discard_padding);
/** Query if a packet is encrypted.
@param packet Packet initialized by #nestegg_read_packet.
@retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_FALSE No signal byte, encryption
information not read from packet.
@retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_UNENCRYPTED Encrypted bit not
set, encryption information not read from packet.
@retval #NESTEGG_PACKET_HAS_SIGNAL_BYTE_ENCRYPTED Encrypted bit set,
encryption infomation read from packet.
@retval -1 Error.*/
int nestegg_packet_encryption(nestegg_packet * packet);
/** Query the IV for an encrypted packet. Expects a packet from an encrypted
track, and will return error if given a packet that has no signal btye.
@param packet Packet initialized by #nestegg_read_packet.
@param iv Storage for queried iv.
@param length Length of returned iv, may be 0.
The data is owned by the #nestegg_packet packet.
@retval 0 Success.
@retval -1 Error.
*/
int nestegg_packet_iv(nestegg_packet * packet, unsigned char const ** iv,
size_t * length);
/** Returns reference_block given packet
@param packet Packet initialized by #nestegg_read_packet.
@param reference_block pointer to store reference block in.

Просмотреть файл

@ -12,97 +12,109 @@
#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 {
@ -114,36 +126,48 @@ enum ebml_type_enum {
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,
@ -223,6 +247,25 @@ struct audio {
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;
@ -239,6 +282,7 @@ struct track_entry {
struct ebml_type default_duration;
struct video video;
struct audio audio;
struct content_encodings content_encodings;
};
struct tracks {
@ -285,9 +329,16 @@ struct saved_state {
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;
};
@ -409,6 +460,29 @@ static struct ebml_element_desc ne_audio_elements[] = {
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),
@ -425,6 +499,7 @@ static struct ebml_element_desc ne_track_entry_elements[] = {
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
};
@ -1072,6 +1147,55 @@ ne_parse(nestegg * ctx, struct ebml_element_desc * top_level, int64_t max_offset
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)
{
@ -1224,10 +1348,11 @@ ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_pac
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;
@ -1324,6 +1449,16 @@ ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_pac
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);
@ -1357,15 +1492,64 @@ ne_read_block(nestegg * ctx, uint64_t block_id, uint64_t block_size, nestegg_pac
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);
@ -2301,6 +2485,108 @@ nestegg_track_audio_params(nestegg * ctx, unsigned int track,
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)
@ -2476,6 +2762,10 @@ nestegg_free_packet(nestegg_packet * pkt)
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);
}
@ -2596,6 +2886,50 @@ nestegg_packet_additional_data(nestegg_packet * pkt, unsigned int id,
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)
{