Sync oemcrypto reference code

This is a merge from the Widevine repo of
http://go/wvgerrit/117311
Update backwards compatibility builds

http://go/wvgerrit/117423
Restrict maximum size of key id
To protect from out-of-memory found by fuzz testing.

http://go/wvgerrit/117683
Generation number should wrap

The master generation number should wrap around on overflow. This
means that we cannot use less than to check for a skew of 1.

http://go/wvgerrit/119232
Replace 0 with nullptr

Bug: 176234903
Bug: 184866351
Bug: 161243686
Test: ran unit tests (CL affects test code only)
Merged-In: Ie787bcf9c66a7605700c3dc29a8aa16406926ce3
Change-Id: I2b02a36a70a0920f31ffc00de102a23516d4b20e
This commit is contained in:
Fred Gylys-Colwell
2021-06-21 23:10:45 +00:00
parent 52d3c9f7c1
commit 830a7acc48
9 changed files with 30 additions and 95 deletions

View File

@@ -50,7 +50,7 @@ typedef enum SessionType {
class CryptoEngine {
public:
static const uint32_t kApiVersion = 16;
static const uint32_t kMinorApiVersion = 3;
static const uint32_t kMinorApiVersion = 4;
static const int64_t kTimeInfoUpdateWindowInSeconds = 300;
// This is like a factory method, except we choose which version to use at

View File

@@ -554,9 +554,12 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl(
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint32_t* block = reinterpret_cast<uint32_t*>(key_control_block);
if ((key_control_block_length == nullptr) ||
(*key_control_block_length < wvoec::KEY_CONTROL_SIZE)) {
if (key_control_block_length == nullptr) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (*key_control_block_length < wvoec::KEY_CONTROL_SIZE) {
LOGE("[OEMCrypto_QueryKeyControl(): OEMCrypto_ERROR_SHORT_BUFFER]");
*key_control_block_length = wvoec::KEY_CONTROL_SIZE;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*key_control_block_length = wvoec::KEY_CONTROL_SIZE;
@@ -572,6 +575,9 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl(
LOGE("[OEMCrypto_QueryKeyControl(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (key_id_length > wvoec::KEY_ID_SIZE || key_id_length == 0) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const std::vector<uint8_t> key_id_str =
std::vector<uint8_t>(key_id, key_id + key_id_length);
if (!session_ctx->QueryKeyControlBlock(key_id_str, block)) {
@@ -596,7 +602,9 @@ OEMCrypto_SelectKey(const OEMCrypto_SESSION session, const uint8_t* key_id,
LOGE("[OEMCrypto_SelectKey(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (key_id_length > wvoec::KEY_ID_SIZE || key_id_length == 0) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
const std::vector<uint8_t> key_id_str =
std::vector<uint8_t>(key_id, key_id + key_id_length);
return session_ctx->SelectContentKey(key_id_str, cipher_mode);
@@ -1272,7 +1280,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature(
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (signature_length == 0) {
if (signature_length == nullptr) {
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
@@ -1289,8 +1297,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature(
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (message == nullptr || message_length == 0 || signature == nullptr ||
signature_length == 0) {
if (message == nullptr || message_length == 0 || signature == nullptr) {
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}

View File

@@ -1,5 +1,5 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs

View File

@@ -1,5 +1,5 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Reference implementation of OEMCrypto APIs

View File

@@ -227,7 +227,7 @@ bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
return false;
}
if (!CMAC_Init(cmac_ctx, &key[0], key.size(), cipher, 0)) {
if (!CMAC_Init(cmac_ctx, &key[0], key.size(), cipher, nullptr)) {
LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]");
CMAC_CTX_free(cmac_ctx);
return false;
@@ -521,7 +521,7 @@ OEMCryptoResult SessionContext::GenerateCertSignature(
size_t* signature_length) {
// TODO(b/67735947): Add ECC cert support.
if (message == nullptr || message_length == 0 || signature == nullptr ||
signature_length == 0) {
signature_length == nullptr) {
LOGE("OEMCrypto_ERROR_INVALID_CONTEXT");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
@@ -571,7 +571,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
const uint8_t* message, size_t message_length, uint8_t* signature,
size_t* signature_length, RSA_Padding_Scheme padding_scheme) {
if (message == nullptr || message_length == 0 || signature == nullptr ||
signature_length == 0) {
signature_length == nullptr) {
LOGE("OEMCrypto_ERROR_INVALID_CONTEXT");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}

View File

@@ -407,11 +407,12 @@ OEMCryptoResult UsageTable::LoadUsageEntry(
if (new_entry->generation_number() != generation_numbers_[index]) {
LOGE("Generation SKEW: %ld -> %ld", new_entry->generation_number(),
generation_numbers_[index]);
if ((new_entry->generation_number() + 1 < generation_numbers_[index]) ||
(new_entry->generation_number() - 1 > generation_numbers_[index])) {
if ((new_entry->generation_number() + 1 == generation_numbers_[index]) ||
(new_entry->generation_number() - 1 == generation_numbers_[index])) {
status = OEMCrypto_WARNING_GENERATION_SKEW;
} else {
return OEMCrypto_ERROR_GENERATION_SKEW;
}
status = OEMCrypto_WARNING_GENERATION_SKEW;
}
sessions_[index] = session;
*entry = std::move(new_entry);
@@ -583,11 +584,12 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader(
if (clear->master_generation != master_generation_number_) {
LOGE("Generation SKEW: %ld -> %ld", clear->master_generation,
master_generation_number_);
if ((clear->master_generation + 1 < master_generation_number_) ||
(clear->master_generation - 1 > master_generation_number_)) {
if ((clear->master_generation + 1 == master_generation_number_) ||
(clear->master_generation - 1 == master_generation_number_)) {
status = OEMCrypto_WARNING_GENERATION_SKEW;
} else {
return OEMCrypto_ERROR_GENERATION_SKEW;
}
status = OEMCrypto_WARNING_GENERATION_SKEW;
}
int64_t* stored_generations =
reinterpret_cast<int64_t*>(&clear_buffer[0] + sizeof(SignedHeaderBlock));
@@ -615,7 +617,7 @@ OEMCryptoResult UsageTable::MoveEntry(UsageTableEntry* entry,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
sessions_[new_index] = sessions_[entry->index()];
sessions_[entry->index()] = 0;
sessions_[entry->index()] = nullptr;
entry->set_index(new_index);
generation_numbers_[new_index] = master_generation_number_;

View File

@@ -107,7 +107,7 @@ class UsageTable {
OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_table_size,
uint8_t* header_buffer,
size_t* header_buffer_length);
void ReleaseEntry(uint32_t index) { sessions_[index] = 0; }
void ReleaseEntry(uint32_t index) { sessions_[index] = nullptr; }
void IncrementGeneration();
static size_t SignedHeaderSize(size_t count);

View File

@@ -2,7 +2,7 @@
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// Compute CRC32/MPEG2 Checksum. Needed for verification of WV Keybox.
// Compute CRC32 Checksum. Needed for verification of WV Keybox.
//
#include "platform.h"
#include "wvcrc32.h"

View File

@@ -1,74 +0,0 @@
// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include <gtest/gtest.h>
#include "wvcrc32.h"
namespace wvoec_ref {
uint32_t ComputeCrc32(const std::string& s) {
return wvcrc32(reinterpret_cast<const uint8_t*>(s.data()), s.size());
}
uint32_t ComputeCrc32Cont(const std::string& s, uint32_t prev_crc) {
return wvcrc32Cont(reinterpret_cast<const uint8_t*>(s.data()), s.size(),
prev_crc);
}
TEST(OEMCryptoWvCrc32Test, BasicTest) {
EXPECT_EQ(0xF88AC628, ComputeCrc32("abcdefg"));
EXPECT_EQ(0xDF520F72, ComputeCrc32("Widevine"));
EXPECT_EQ(0x0376E6E7, ComputeCrc32("123456789"));
EXPECT_EQ(0xBA62119E,
ComputeCrc32("The quick brown fox jumps over the lazy dog"));
}
TEST(OEMCryptoWvCrc32Test, StreamTest) {
const std::vector<std::string> parts = {"The ", "quick", " brown ",
"fox", " jumps ", "over",
" the ", "lazy", " dog"};
uint32_t crc = wvcrc32Init();
for (const auto& part : parts) {
crc = ComputeCrc32Cont(part, crc);
}
EXPECT_EQ(0xBA62119E, crc);
}
TEST(OEMCryptoWvCrc32Test, Keybox) {
// clang-format off
const uint8_t kKeyboxData[128] = {
// deviceID = WidevineCRCTestKeyBox
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65,
0x43, 0x52, 0x43, 0x54, 0x65, 0x73, 0x74, 0x4b,
0x65, 0x79, 0x62, 0x6f, 0x78, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// key = random
0x8a, 0x7c, 0xda, 0x3e, 0x09, 0xd9, 0x8e, 0xd5,
0x47, 0x47, 0x00, 0x84, 0x5a, 0x1f, 0x52, 0xd4,
// data = random
0x98, 0xa5, 0x00, 0x19, 0x8b, 0xfe, 0x54, 0xfd,
0xca, 0x4d, 0x26, 0xa3, 0xfa, 0xaa, 0x3b, 0x6c,
0x35, 0xfe, 0x03, 0x7c, 0xbf, 0x35, 0xba, 0xce,
0x31, 0xb5, 0x1e, 0x3c, 0x49, 0xd6, 0x3f, 0x9c,
0x3a, 0xde, 0x9b, 0x58, 0xcc, 0x54, 0x8d, 0xc0,
0x4b, 0x04, 0xcc, 0xee, 0xae, 0x4d, 0x9f, 0x90,
0xd3, 0xf3, 0xfe, 0x23, 0x26, 0x13, 0x56, 0x80,
0xe4, 0x3b, 0x79, 0x22, 0x69, 0x5d, 0xd6, 0xb7,
0xa0, 0x0e, 0x7e, 0x07, 0xcd, 0x1a, 0x15, 0xca,
// magic
'k', 'b', 'o', 'x',
// crc
0x09, 0x7b, 0x7e, 0xcc
};
// clang-format on
const uint32_t crc_computed = wvcrc32n(kKeyboxData, 124);
uint32_t crc_current;
memcpy(&crc_current, &kKeyboxData[124], 4);
EXPECT_EQ(crc_computed, crc_current);
}
} // namespace wvoec_ref