Merge recent doc changes for OEMCrypto

This is a cherry pick of recent changes to OEMCrypto and ODK. Most of
these are part of the document migration to doxygen.

See http://go/wvgerrit/106005 and its parents for code reviews.

Bug: 144715340
Bug: 148232693
Bug: 167580674
Change-Id: I658f99c8117b974faed97322d61fac0f382283af
This commit is contained in:
Fred Gylys-Colwell
2020-09-11 13:30:58 -07:00
parent 28b13ef65e
commit 20bb84ffee
75 changed files with 5717 additions and 4488 deletions

View File

@@ -23,6 +23,14 @@
#include "oemcrypto_rsa_key_shared.h"
#include "string_conversions.h"
namespace {
// Lower bits in SessionId are actual session id. The rest higher bits are
// session type.
const uint32_t kSessionIdTypeShift = 28;
const uint32_t kSessionIdMask = (1u << kSessionIdTypeShift) - 1u;
} // namespace
namespace wvoec_ref {
// Note: The class CryptoEngine is configured at compile time by compiling in
@@ -64,6 +72,12 @@ SessionId CryptoEngine::OpenSession() {
std::unique_lock<std::mutex> lock(session_table_lock_);
static OEMCrypto_SESSION unique_id = 1;
SessionId id = ++unique_id;
// Check if too many sessions have been opened.
if (SessionTypeBits(id) != 0) {
return 0;
}
// Apply session type to higher bits.
id = (kSessionTypeOEMCrypto << kSessionIdTypeShift) | (id & kSessionIdMask);
sessions_[id] = MakeSession(id);
return id;
}
@@ -251,4 +265,8 @@ OEMCryptoResult CryptoEngine::SetDestination(
return OEMCrypto_SUCCESS;
}
uint32_t CryptoEngine::SessionTypeBits(SessionId sid) {
return sid >> kSessionIdTypeShift;
}
} // namespace wvoec_ref

View File

@@ -22,8 +22,8 @@
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "oemcrypto_session.h"
#include "oemcrypto_usage_table_ref.h"
#include "oemcrypto_types.h"
#include "oemcrypto_usage_table_ref.h"
namespace wvoec_ref {
@@ -41,10 +41,16 @@ typedef struct {
uint8_t padding[16 - (2 * sizeof(time_t)) % 16];
} TimeInfo;
// Session types are higher (32 - kSessionIdTypeShift) bits in SessionId.
typedef enum SessionType {
kSessionTypeOEMCrypto = 0,
kSessionTypeEntitledKey = 1,
} SessionType;
class CryptoEngine {
public:
static const uint32_t kApiVersion = 16;
static const uint32_t kMinorApiVersion = 0;
static const uint32_t kMinorApiVersion = 3;
static const int64_t kTimeInfoUpdateWindowInSeconds = 300;
// This is like a factory method, except we choose which version to use at
@@ -83,9 +89,7 @@ class CryptoEngine {
size_t DeviceRootTokenLength() { return root_of_trust_.DeviceTokenLength(); }
const uint8_t* DeviceRootToken() {
return root_of_trust_.DeviceToken();
}
const uint8_t* DeviceRootToken() { return root_of_trust_.DeviceToken(); }
virtual void Terminate();
@@ -116,9 +120,7 @@ class CryptoEngine {
virtual OEMCrypto_HDCP_Capability config_maximum_hdcp_capability();
// Return true if there might be analog video output enabled.
virtual bool analog_display_active() {
return !config_local_display_only();
}
virtual bool analog_display_active() { return !config_local_display_only(); }
// Return true if there is an analog display, and CGMS A is turned on.
virtual bool cgms_a_active() { return false; }
@@ -222,6 +224,9 @@ class CryptoEngine {
return OEMCrypto_SUCCESS;
}
// Get the session type bits from |sid|.
static uint32_t SessionTypeBits(SessionId sid);
protected:
// System clock, measuring time in seconds, including anti-rollback offset.
int64_t MonotonicTime();

View File

@@ -39,6 +39,9 @@
namespace {
const uint8_t kBakedInCertificateMagicBytes[] = {0xDE, 0xAD, 0xBE, 0xEF};
// Maximum context key length used for performance reasons, not mandated by
// specification.
const size_t kMaxContextKeyLength = 1024 * 1024;
// Return uint32 referenced through a potentially unaligned pointer.
// If the pointer is nullptr, return 0.
@@ -109,6 +112,10 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_OpenSession(
return OEMCrypto_ERROR_TOO_MANY_SESSIONS;
}
SessionId sid = crypto_engine->OpenSession();
if (sid == 0) {
LOGE("OEMCrypto_OpenSession: invalid session id returned.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
*session = (OEMCrypto_SESSION)sid;
return OEMCrypto_SUCCESS;
}
@@ -141,6 +148,11 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
if (mac_key_context_length > kMaxContextKeyLength ||
enc_key_context_length > kMaxContextKeyLength) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
@@ -723,8 +735,10 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer,
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
crypto_engine->UseTestKeybox(buffer, length);
return OEMCrypto_SUCCESS;
if (crypto_engine->UseTestKeybox(buffer, length)) {
return OEMCrypto_SUCCESS;
}
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) {
@@ -887,17 +901,6 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// For the reference implementation, the wrapped key and the encrypted
// key are the same size -- just encrypted with different keys.
// We add 32 bytes for a context, 32 for iv, and 32 bytes for a signature.
// Important: This layout must match OEMCrypto_LoadDRMPrivateKey below.
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
if (wrapped_rsa_key == nullptr || *wrapped_rsa_key_length < buffer_size) {
*wrapped_rsa_key_length = buffer_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*wrapped_rsa_key_length = buffer_size; // Tell caller how much space we used.
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
@@ -933,13 +936,7 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
enc_rsa_key_iv, &pkcs8_rsa_key[0])) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
if (padding > 16) {
// Do not return an error at this point, to avoid a padding oracle attack.
padding = 0;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) {
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Failed to LoadRSAKey.");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
@@ -970,6 +967,7 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
LOGE("[_RewrapDeviceRSAKey30(): EncrypteRSAKey failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
// The wrapped keybox must be signed with the same key we verify with. I'll
// pick the server key, so I don't have to modify LoadRSAKey.
unsigned int sig_length = sizeof(wrapped->signature);
@@ -1004,17 +1002,6 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// For the reference implementation, the wrapped key and the encrypted
// key are the same size -- just encrypted with different keys.
// We add 32 bytes for a context, 32 for iv, and 32 bytes for a signature.
// Important: This layout must match OEMCrypto_LoadDRMPrivateKey below.
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
if (wrapped_rsa_key == nullptr || *wrapped_rsa_key_length < buffer_size) {
*wrapped_rsa_key_length = buffer_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
*wrapped_rsa_key_length = buffer_size; // Tell caller how much space we used.
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
@@ -1051,14 +1038,7 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
enc_rsa_key_iv, &pkcs8_rsa_key[0])) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
if (padding > 16) {
// Do not return an error at this point, to avoid a padding oracle attack.
padding = 0;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) {
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
@@ -1084,6 +1064,7 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
wrapped->iv, wrapped->enc_rsa_key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
// The wrapped keybox must be signed with the same key we verify with. I'll
// pick the server key, so I don't have to modify LoadRSAKey.
unsigned int sig_length = sizeof(wrapped->signature);
@@ -1302,6 +1283,12 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
if (mac_key_context_length > kMaxContextKeyLength ||
enc_key_context_length > kMaxContextKeyLength ||
enc_session_key_length > kMaxContextKeyLength) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {

View File

@@ -86,8 +86,7 @@ class ContentKeysContext : public SessionContextKeys {
OEMCrypto_LicenseType type() override { return OEMCrypto_ContentLicense; }
bool SetContentKey(const KeyId& entitlement_id,
const KeyId& content_key_id,
bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id,
const std::vector<uint8_t>& content_key) override;
EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) override;
@@ -139,8 +138,7 @@ class EntitlementKeysContext : public SessionContextKeys {
Key* FirstKey() override;
void Remove(const KeyId& key_id) override;
void UpdateDuration(const KeyControlBlock& control) override;
bool SetContentKey(const KeyId& entitlement_id,
const KeyId& content_key_id,
bool SetContentKey(const KeyId& entitlement_id, const KeyId& content_key_id,
const std::vector<uint8_t>& content_key) override;
EntitlementKey* GetEntitlementKey(const KeyId& entitlement_id) override;
@@ -210,8 +208,7 @@ SessionContext::SessionContext(CryptoEngine* ce, SessionId sid,
CryptoEngine::kApiVersion, sid);
}
SessionContext::~SessionContext() {
}
SessionContext::~SessionContext() {}
// Internal utility function to derive key using CMAC-128
bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
@@ -366,8 +363,10 @@ OEMCryptoResult SessionContext::PrepAndSignLicenseRequest(
const size_t message_body_length = message_length - *core_message_length;
result = GenerateCertSignature(message_body, message_body_length, signature,
signature_length);
if (result == OEMCrypto_SUCCESS) state_request_signed_ = true;
ODK_InitializeClockValues(&clock_values_, ce_->SystemTime());
if (result == OEMCrypto_SUCCESS) {
state_request_signed_ = true;
result = ODK_InitializeClockValues(&clock_values_, ce_->SystemTime());
}
return result;
}
@@ -677,11 +676,13 @@ OEMCryptoResult SessionContext::CheckStatusOffline(uint32_t nonce,
OEMCryptoResult SessionContext::CheckNonceOrEntry(
const KeyControlBlock& key_control_block) {
switch (key_control_block.control_bits() & wvoec::kControlReplayMask) {
case wvoec::kControlNonceRequired: // Online license. Nonce always required.
case wvoec::kControlNonceRequired: // Online license. Nonce always
// required.
return CheckStatusOnline(key_control_block.nonce(),
key_control_block.control_bits());
break;
case wvoec::kControlNonceOrEntry: // Offline license. Nonce required on first use.
case wvoec::kControlNonceOrEntry: // Offline license. Nonce required on
// first use.
return CheckStatusOffline(key_control_block.nonce(),
key_control_block.control_bits());
break;
@@ -844,9 +845,8 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature(
message + key_array[i].key_control_iv.offset,
message + key_array[i].key_control_iv.offset + wvoec::KEY_IV_SIZE);
OEMCryptoResult result =
InstallKey(key_id, enc_key_data, key_data_iv, key_control,
key_control_iv);
OEMCryptoResult result = InstallKey(key_id, enc_key_data, key_data_iv,
key_control, key_control_iv);
if (result != OEMCrypto_SUCCESS) {
status = result;
break;
@@ -868,7 +868,12 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature(
LOGE("Failed to update mac keys.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
} else {
// If the mac keys are not updated, we will not need them again.
mac_key_server_.resize(0);
mac_key_client_.resize(0);
}
if (usage_entry_) {
OEMCryptoResult result = OEMCrypto_SUCCESS;
switch (usage_entry_status_) {
@@ -1122,6 +1127,10 @@ bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key,
size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv,
uint8_t* pkcs8_rsa_key) {
if (enc_rsa_key_length % AES_BLOCK_SIZE != 0) {
LOGE("[DecryptRSAKey(): bad buffer size]");
return false;
}
// Decrypt rsa key with keybox.
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE);
@@ -1136,6 +1145,10 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv,
uint8_t* enc_rsa_key) {
if (enc_rsa_key_length % AES_BLOCK_SIZE != 0) {
LOGE("[EncryptRSAKey(): bad buffer size]");
return false;
}
// Encrypt rsa key with keybox.
uint8_t iv_buffer[wvoec::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE);
@@ -1227,7 +1240,7 @@ OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string,
LOGE("[%s(): CGMS required, but buffer is clear", log_string.c_str());
return OEMCrypto_ERROR_ANALOG_OUTPUT;
}
if ( ce_->analog_display_active() && !ce_->cgms_a_active()) {
if (ce_->analog_display_active() && !ce_->cgms_a_active()) {
LOGE("[%s(): control bit says CGMS required", log_string.c_str());
return OEMCrypto_ERROR_ANALOG_OUTPUT;
}
@@ -1252,8 +1265,9 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
LOGE("[Generic_Encrypt(): CONTENT_KEY has wrong size: %zu", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Encrypt", wvoec::kControlAllowEncrypt,
OEMCrypto_BufferType_Clear);
OEMCryptoResult result =
CheckKeyUse("Generic_Encrypt", wvoec::kControlAllowEncrypt,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
LOGE("[Generic_Encrypt(): algorithm bad");
@@ -1292,8 +1306,9 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
LOGE("[Generic_Decrypt(): CONTENT_KEY has wrong size");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Decrypt", wvoec::kControlAllowDecrypt,
OEMCrypto_BufferType_Clear);
OEMCryptoResult result =
CheckKeyUse("Generic_Decrypt", wvoec::kControlAllowDecrypt,
OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
@@ -1373,8 +1388,8 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
LOGE("[Generic_Verify(): CONTENT_KEY has wrong size: %zu", key.size());
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
OEMCryptoResult result = CheckKeyUse("Generic_Verify", wvoec::kControlAllowVerify,
OEMCrypto_BufferType_Clear);
OEMCryptoResult result = CheckKeyUse(
"Generic_Verify", wvoec::kControlAllowVerify, OEMCrypto_BufferType_Clear);
if (result != OEMCrypto_SUCCESS) return result;
if (algorithm != OEMCrypto_HMAC_SHA256) {
LOGE("[Generic_Verify(): bad algorithm");
@@ -1523,6 +1538,11 @@ bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
LOGE("[DecryptMessage(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return false;
}
if (message.size() % AES_BLOCK_SIZE != 0) {
LOGE("[DecryptMessage(): bad buffer size]");
return false;
}
decrypted->resize(message.size());
uint8_t iv_buffer[16];
memcpy(iv_buffer, &iv[0], 16);
@@ -1714,7 +1734,7 @@ OEMCryptoResult SessionContext::PatternDecryptCBC(
const bool skip_block = (pattern_offset >= pattern->encrypt);
pattern_offset = (pattern_offset + 1) % pattern_length;
if (skip_block || (size < AES_BLOCK_SIZE)) {
// If we are decrypting in-place, then this byte is already correct and
// If we are decrypting in-place, then this block is already correct and
// can be skipped.
if (clear_data != cipher_data) {
memcpy(&clear_data[l], &cipher_data[l], size);

View File

@@ -121,7 +121,8 @@ OEMCryptoResult UsageTableEntry::ReportUsage(const std::vector<uint8_t>& pst,
return OEMCrypto_ERROR_WRONG_PST;
}
if (CRYPTO_memcmp(&pst[0], data_.pst, data_.pst_length)) {
LOGE("ReportUsage: wrong pst %s, should be %s.", wvcdm::b2a_hex(pst).c_str(),
LOGE("ReportUsage: wrong pst %s, should be %s.",
wvcdm::b2a_hex(pst).c_str(),
wvcdm::HexEncode(data_.pst, data_.pst_length).c_str());
return OEMCrypto_ERROR_WRONG_PST;
}
@@ -283,7 +284,7 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index,
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
clear->verification,
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kEntryVerification),
kMagicLength)
kMagicLength)
.c_str(),
reinterpret_cast<const uint8_t*>(kEntryVerification));
return OEMCrypto_ERROR_BAD_MAGIC;
@@ -378,7 +379,7 @@ OEMCryptoResult UsageTable::LoadUsageEntry(
uint32_t index, const std::vector<uint8_t>& buffer,
ODK_ClockValues* clock_values) {
if (!header_loaded_) {
LOGE("CreateNewUsageEntry: Header not loaded.");
LOGE("LoadUsageEntry: Header not loaded.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -557,7 +558,7 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader(
wvcdm::HexEncode(clear->verification, kMagicLength).c_str(),
clear->verification,
wvcdm::HexEncode(reinterpret_cast<const uint8_t*>(kHeaderVerification),
kMagicLength)
kMagicLength)
.c_str(),
reinterpret_cast<const uint8_t*>(kHeaderVerification));
return OEMCrypto_ERROR_BAD_MAGIC;