Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Source/ocdm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,12 @@ InstallCMakeConfig(
InstallPackageConfig(
TARGETS ${TARGET}
DESCRIPTION "OCDM library")

option(BUILD_OCDM_TESTS "Build OCDM tests" OFF)
if(BUILD_OCDM_TESTS)
enable_testing()
add_executable(ocdm_cenc_bounds_test test_ocdm_cenc_bounds.cpp)
target_include_directories(ocdm_cenc_bounds_test PRIVATE ${CMAKE_CURRENT_LIST_DIR})
set_target_properties(ocdm_cenc_bounds_test PROPERTIES CXX_STANDARD ${CXX_STD} CXX_STANDARD_REQUIRED YES)
add_test(NAME ocdm_cenc_bounds_test COMMAND ocdm_cenc_bounds_test)
endif()
42 changes: 42 additions & 0 deletions Source/ocdm/adapter/SubSampleParser.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include "../open_cdm.h"

#include <cstdint>
#include <limits>
#include <vector>

namespace Thunder {
namespace OCDM {

inline bool ParseSubSamples(const uint8_t data[], const uint32_t length, const uint32_t count, const uint32_t sampleLength, std::vector<SubSampleInfo>& entries, uint32_t& encryptedLength)
{
constexpr uint32_t entryLength = sizeof(uint16_t) + sizeof(uint32_t);
if ((count > std::numeric_limits<uint8_t>::max()) || (count > (std::numeric_limits<uint32_t>::max() / entryLength)) || (length != count * entryLength) || ((count != 0) && (data == nullptr))) {
return false;
}

entries.clear();
entries.reserve(count);
uint64_t sampleOffset = 0;
uint64_t encryptedOffset = 0;

for (uint32_t index = 0; index < count; ++index) {
const uint8_t* entry = data + (index * entryLength);
const uint16_t clear = static_cast<uint16_t>((static_cast<uint16_t>(entry[0]) << 8) | entry[1]);
const uint32_t encrypted = (static_cast<uint32_t>(entry[2]) << 24) | (static_cast<uint32_t>(entry[3]) << 16) | (static_cast<uint32_t>(entry[4]) << 8) | entry[5];
sampleOffset += static_cast<uint64_t>(clear) + encrypted;
encryptedOffset += encrypted;
if ((sampleOffset > sampleLength) || (encryptedOffset > std::numeric_limits<uint32_t>::max())) {
entries.clear();
return false;
}
entries.push_back({ clear, encrypted });
}

encryptedLength = static_cast<uint32_t>(encryptedOffset);
return true;
}

}
}
95 changes: 36 additions & 59 deletions Source/ocdm/adapter/gstreamer/open_cdm_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
*/

#include <gst/gst.h>
#include <gst/base/gstbytereader.h>

#include "Module.h"
#include "CapsParser.h"
#include "open_cdm_adapter.h"
#include "../SubSampleParser.h"

inline bool mappedBuffer(GstBuffer *buffer, bool writable, uint8_t **data, uint32_t *size)
{
Expand All @@ -43,6 +43,9 @@ OpenCDMError opencdm_gstreamer_session_decrypt(struct OpenCDMSession* session, G
GstBuffer* IV, GstBuffer* keyID, uint32_t initWithLast15)
{
OpenCDMError result (ERROR_INVALID_SESSION);
if (((subSampleCount == 0) != (subSampleBuffer == nullptr)) || (subSampleCount > UINT8_MAX)) {
return (ERROR_INVALID_DECRYPT_BUFFER);
}

if (session != nullptr) {
GstMapInfo dataMap;
Expand Down Expand Up @@ -109,49 +112,35 @@ OpenCDMError opencdm_gstreamer_session_decrypt(struct OpenCDMSession* session, G
}
uint8_t *mappedSubSample = reinterpret_cast<uint8_t* >(sampleMap.data);
uint32_t mappedSubSampleSize = static_cast<uint32_t >(sampleMap.size);
GstByteReader* reader = gst_byte_reader_new(mappedSubSample, mappedSubSampleSize);
uint16_t inClear = 0;
uint32_t inEncrypted = 0;
std::vector<SubSampleInfo> subSamples;
uint32_t totalEncrypted = 0;
for (unsigned int position = 0; position < subSampleCount; position++) {

gst_byte_reader_get_uint16_be(reader, &inClear);
gst_byte_reader_get_uint32_be(reader, &inEncrypted);
totalEncrypted += inEncrypted;
if (Thunder::OCDM::ParseSubSamples(mappedSubSample, mappedSubSampleSize, subSampleCount, mappedDataSize, subSamples, totalEncrypted) == false) {
gst_buffer_unmap(subSampleBuffer, &sampleMap);
if (keyID != nullptr) {
gst_buffer_unmap(keyID, &keyIDMap);
}
gst_buffer_unmap(IV, &ivMap);
gst_buffer_unmap(buffer, &dataMap);
return (ERROR_INVALID_DECRYPT_BUFFER);
}
gst_byte_reader_set_pos(reader, 0);

uint8_t* encryptedData = reinterpret_cast<uint8_t*>(malloc(totalEncrypted));
uint8_t* encryptedDataIter = encryptedData;

uint32_t index = 0;
for (unsigned int position = 0; position < subSampleCount; position++) {

gst_byte_reader_get_uint16_be(reader, &inClear);
gst_byte_reader_get_uint32_be(reader, &inEncrypted);

memcpy(encryptedDataIter, mappedData + index + inClear, inEncrypted);
index += inClear + inEncrypted;
encryptedDataIter += inEncrypted;
std::vector<uint8_t> encryptedData(totalEncrypted);
uint32_t sampleOffset = 0;
uint32_t encryptedOffset = 0;
for (const auto& entry : subSamples) {
memcpy(encryptedData.data() + encryptedOffset, mappedData + sampleOffset + entry.clear_bytes, entry.encrypted_bytes);
sampleOffset += entry.clear_bytes + entry.encrypted_bytes;
encryptedOffset += entry.encrypted_bytes;
}
gst_byte_reader_set_pos(reader, 0);


result = opencdm_session_decrypt(session, encryptedData, totalEncrypted, encScheme, pattern, mappedIV, mappedIVSize, mappedKeyID, mappedKeyIDSize, initWithLast15);
// Re-build sub-sample data.
index = 0;
unsigned total = 0;
for (uint32_t position = 0; position < subSampleCount; position++) {
gst_byte_reader_get_uint16_be(reader, &inClear);
gst_byte_reader_get_uint32_be(reader, &inEncrypted);

memcpy(mappedData + total + inClear, encryptedData + index, inEncrypted);
index += inEncrypted;
total += inClear + inEncrypted;
result = opencdm_session_decrypt(session, encryptedData.data(), totalEncrypted, encScheme, pattern, mappedIV, mappedIVSize, mappedKeyID, mappedKeyIDSize, initWithLast15);
sampleOffset = 0;
encryptedOffset = 0;
for (const auto& entry : subSamples) {
memcpy(mappedData + sampleOffset + entry.clear_bytes, encryptedData.data() + encryptedOffset, entry.encrypted_bytes);
sampleOffset += entry.clear_bytes + entry.encrypted_bytes;
encryptedOffset += entry.encrypted_bytes;
}

gst_byte_reader_free(reader);
free(encryptedData);
gst_buffer_unmap(subSampleBuffer, &sampleMap);
} else {
result = opencdm_session_decrypt(session, mappedData, mappedDataSize, encScheme, pattern, mappedIV, mappedIVSize, mappedKeyID, mappedKeyIDSize, initWithLast15);
Expand Down Expand Up @@ -206,12 +195,11 @@ OpenCDMError opencdm_gstreamer_session_decrypt_buffer(struct OpenCDMSession* ses
goto exit;
}
subSample = gst_value_get_buffer(value);
if (subSample != nullptr && mappedBuffer(subSample, false, &mappedSubSample, &mappedSubSampleSize) == false) {
if ((subSample == nullptr) || (subSampleCount > UINT8_MAX) || (mappedBuffer(subSample, false, &mappedSubSample, &mappedSubSampleSize) == false)) {
TRACE_L1("opencdm_gstreamer_session_decrypt_buffer: Invalid subsample buffer.");
result = ERROR_INVALID_DECRYPT_BUFFER;
goto exit;
}
ASSERT(mappedSubSampleSize==subSampleCount);
}

//Get IV
Expand All @@ -224,7 +212,7 @@ OpenCDMError opencdm_gstreamer_session_decrypt_buffer(struct OpenCDMSession* ses
GstBuffer* IV = gst_value_get_buffer(value);
uint8_t *mappedIV = nullptr; //Set the Encryption Scheme and Pattern to defaults.
uint32_t mappedIVSize = 0;
if (mappedBuffer(IV, false, &mappedIV, &mappedIVSize) == false) {
if ((IV == nullptr) || (mappedBuffer(IV, false, &mappedIV, &mappedIVSize) == false)) {
TRACE_L1("opencdm_gstreamer_session_decrypt_buffer: Invalid IV buffer.");
result = ERROR_INVALID_DECRYPT_BUFFER;
goto exit;
Expand All @@ -240,7 +228,7 @@ OpenCDMError opencdm_gstreamer_session_decrypt_buffer(struct OpenCDMSession* ses
GstBuffer* keyID = gst_value_get_buffer(value);
uint8_t *mappedKeyID = nullptr;
uint32_t mappedKeyIDSize = 0;
if (keyID != nullptr && mappedBuffer(keyID, false, &mappedKeyID, &mappedKeyIDSize) == false) {
if ((keyID == nullptr) || (mappedBuffer(keyID, false, &mappedKeyID, &mappedKeyIDSize) == false)) {
TRACE_L1("Invalid keyID buffer.");
result = ERROR_INVALID_DECRYPT_BUFFER;
goto exit;
Expand All @@ -258,18 +246,11 @@ OpenCDMError opencdm_gstreamer_session_decrypt_buffer(struct OpenCDMSession* ses
gst_structure_get_uint(protectionMeta->info, "crypt_byte_block", &pattern.encrypted_blocks);
gst_structure_get_uint(protectionMeta->info, "skip_byte_block", &pattern.clear_blocks);

//Create a SubSampleInfo Array with mapping
SubSampleInfo * subSampleInfoPtr = nullptr;
if (subSample != nullptr) {
GstByteReader* reader = gst_byte_reader_new(mappedSubSample, mappedSubSampleSize);
subSampleInfoPtr = reinterpret_cast<SubSampleInfo*>(malloc(subSampleCount * sizeof(SubSampleInfo)));
for (unsigned int position = 0; position < subSampleCount; position++) {

gst_byte_reader_get_uint16_be(reader, &subSampleInfoPtr[position].clear_bytes);
gst_byte_reader_get_uint32_be(reader, &subSampleInfoPtr[position].encrypted_bytes);
}
gst_byte_reader_set_pos(reader, 0);
gst_byte_reader_free(reader);
std::vector<SubSampleInfo> subSamples;
uint32_t totalEncrypted = mappedDataSize;
if ((subSampleCount > 0) && (Thunder::OCDM::ParseSubSamples(mappedSubSample, mappedSubSampleSize, subSampleCount, mappedDataSize, subSamples, totalEncrypted) == false)) {
result = ERROR_INVALID_DECRYPT_BUFFER;
goto exit;
}

//Get Stream Properties from GstCaps
Expand Down Expand Up @@ -307,7 +288,7 @@ OpenCDMError opencdm_gstreamer_session_decrypt_buffer(struct OpenCDMSession* ses
}

SampleInfo sampleInfo;
sampleInfo.subSample = subSampleInfoPtr;
sampleInfo.subSample = subSamples.empty() ? nullptr : subSamples.data();
sampleInfo.subSampleCount = subSampleCount;
sampleInfo.scheme = encScheme;
sampleInfo.pattern.clear_blocks = pattern.clear_blocks;
Expand All @@ -323,10 +304,6 @@ OpenCDMError opencdm_gstreamer_session_decrypt_buffer(struct OpenCDMSession* ses
&sampleInfo,
spPtr);

//Clean up
if(subSampleInfoPtr != nullptr) {
free(subSampleInfoPtr);
}
} else {
TRACE_L1("opencdm_gstreamer_session_decrypt_buffer: Missing Protection Metadata.");
result = ERROR_INVALID_DECRYPT_BUFFER;
Expand Down
Loading
Loading