Refactor OEMCrypto mock and its unit tests

This is a copy of the Widevine CL:
https://widevine-internal-review.googlesource.com/#/c/9708/

This CL refactors some of code in oemcrypto/mock and oemcrypto/test in
preparation for adding usage table code.

Change-Id: I7e58c8ecd6d92b3e177cb915733212fcad645485
This commit is contained in:
Fred Gylys-Colwell
2014-04-10 17:34:51 -07:00
parent 026a04701e
commit e95eebf326
9 changed files with 1343 additions and 2285 deletions

View File

@@ -79,19 +79,13 @@ void SessionKeyTable::Remove(const KeyId key_id) {
}
}
bool SessionKeyTable::UpdateDuration(const KeyControlBlock& control) {
void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) {
for(KeyMap::iterator it = keys_.begin(); it != keys_.end(); ++it) {
if (!it->second->UpdateDuration(control)) {
return false;
}
it->second->UpdateDuration(control);
}
return true;
}
void SessionContext::Open() {
}
void SessionContext::Close() {
SessionContext::~SessionContext() {
}
// Internal utility function to derive key using CMAC-128
@@ -235,7 +229,7 @@ bool SessionContext::GenerateSignature(const uint8_t* message,
}
unsigned int md_len = *signature_length;
if (HMAC(EVP_sha256(), &mac_key_client_[0], SHA256_DIGEST_LENGTH,
if (HMAC(EVP_sha256(), &mac_key_client_[0], mac_key_client_.size(),
message, message_length, signature, &md_len)) {
*signature_length = md_len;
return true;
@@ -331,7 +325,7 @@ bool SessionContext::ValidateMessage(const uint8_t* given_message,
}
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
unsigned int md_len = SHA256_DIGEST_LENGTH;
if (!HMAC(EVP_sha256(), &mac_key_server_[0], SHA256_DIGEST_LENGTH,
if (!HMAC(EVP_sha256(), &mac_key_server_[0], mac_key_server_.size(),
given_message, message_length, computed_signature, &md_len)) {
LOGE("ValidateMessage: Could not compute signature.");
return false;
@@ -346,75 +340,14 @@ bool SessionContext::ValidateMessage(const uint8_t* given_message,
return true;
}
bool SessionContext::ParseKeyControl(
const std::vector<uint8_t>& key_control_string,
KeyControlBlock& key_control_block) {
key_control_block.Invalidate();
if (key_control_string.size() < wvcdm::KEY_CONTROL_SIZE) {
LOGD("ParseKeyControl: wrong size.");
return false;
}
if (!key_control_block.SetFromString(key_control_string)) {
LOGE("KCB: BAD Size or Structure");
return false;
}
LOGD("KCB:");
LOGD(" valid: %d", key_control_block.valid());
LOGD(" duration: %d", key_control_block.duration());
LOGD(" nonce: %08X", key_control_block.nonce());
LOGD(" magic: %08X", key_control_block.verification());
LOGD(" bits: %08X", key_control_block.control_bits());
switch(key_control_block.control_bits() & kControlReplayMask) {
case kControlNonceRequired:
LOGD(" bits kControlReplay kControlNonceRequired.");
break;
case kControlNonceOrEntry:
LOGD(" bits kControlReplay kControlNonceOrEntry.");
break;
default:
LOGD(" bits kControlReplay unset.");
break;
}
LOGD(" bits kControlKDCPVersion 0x%02x.",
(key_control_block.control_bits() & kControlHDCPVersionMask)
>> kControlHDCPVersionShift);
LOGD(" bit kControlAllowEncrypt %s.",
(key_control_block.control_bits() & kControlAllowEncrypt) ? "set" : "unset");
LOGD(" bit kControlAllowDecrypt %s.",
(key_control_block.control_bits() & kControlAllowDecrypt) ? "set" : "unset");
LOGD(" bit kControlAllowSign %s.",
(key_control_block.control_bits() & kControlAllowSign) ? "set" : "unset");
LOGD(" bit kControlAllowVerify %s.",
(key_control_block.control_bits() & kControlAllowVerify) ? "set" : "unset");
LOGD(" bit kControlObserveDataPath %s.",
(key_control_block.control_bits() & kControlObserveDataPath) ? "set" : "unset");
LOGD(" bit kControlObserveHDCP %s.",
(key_control_block.control_bits() & kControlObserveHDCP) ? "set" : "unset");
LOGD(" bit kControlObserveCGMS %s.",
(key_control_block.control_bits() & kControlObserveCGMS) ? "set" : "unset");
LOGD(" bit kControlDataPathSecure %s.",
(key_control_block.control_bits() & kControlDataPathSecure) ? "set" : "unset");
LOGD(" bit kControlNonceEnabled %s.",
(key_control_block.control_bits() & kControlNonceEnabled) ? "set" : "unset");
LOGD(" bit kControlHDCPRequired %s.",
(key_control_block.control_bits() & kControlHDCPRequired) ? "set" : "unset");
uint32_t cgms_bits = key_control_block.control_bits() & 0x3;
const char* cgms_values[4] = {"free", "BAD", "once", "never"};
LOGD(" CGMS = %s", cgms_values[cgms_bits]);
if (!key_control_block.Validate()) {
LOGE("KCB: BAD Signature");
return false;
}
if ((key_control_block.control_bits() & kControlNonceEnabled)
&& (!CheckNonce(key_control_block.nonce()))) {
bool SessionContext::CheckNonceOrPST(KeyControlBlock& key_control_block,
const std::vector<uint8_t>& pst) {
// TODO(fredgc): look at replay control bits, too.
if ((key_control_block.control_bits() & kControlNonceEnabled) &&
(!CheckNonce(key_control_block.nonce()))) {
LOGE("KCB: BAD Nonce");
return false;
}
return true;
}
@@ -427,19 +360,79 @@ uint32_t SessionContext::CurrentTimer() {
return now - timer_start_;
}
OEMCryptoResult SessionContext::LoadKeys(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length,
const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_keys, size_t num_keys,
const OEMCrypto_KeyObject* key_array, const uint8_t* pst,
size_t pst_length) {
// Validate message signature
if (!ValidateMessage(message, message_length, signature, signature_length)) {
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
StartTimer();
// Decrypt and install keys in key object
// Each key will have a key control block. They will all have the same nonce.
bool status = true;
std::vector<uint8_t> key_id;
std::vector<uint8_t> enc_key_data;
std::vector<uint8_t> key_data_iv;
std::vector<uint8_t> key_control;
std::vector<uint8_t> key_control_iv;
std::vector<uint8_t> pstv(pst, pst + pst_length);
for (unsigned int i = 0; i < num_keys; i++) {
key_id.assign(key_array[i].key_id,
key_array[i].key_id + key_array[i].key_id_length);
enc_key_data.assign(key_array[i].key_data,
key_array[i].key_data + key_array[i].key_data_length);
key_data_iv.assign(key_array[i].key_data_iv,
key_array[i].key_data_iv + wvcdm::KEY_IV_SIZE);
if (key_array[i].key_control == NULL) {
status = false;
break;
}
key_control.assign(key_array[i].key_control,
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
key_control_iv.assign(key_array[i].key_control_iv,
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
if (!InstallKey(key_id, enc_key_data, key_data_iv, key_control,
key_control_iv, pstv)) {
status = false;
break;
}
}
FlushNonces();
if (!status) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
// enc_mac_key can be NULL if license renewal is not supported
if (enc_mac_keys != NULL) {
// V2.1 license protocol: update mac keys after processing license response
const std::vector<uint8_t> enc_mac_keys_str = std::vector<uint8_t>(
enc_mac_keys, enc_mac_keys + 2 * wvcdm::MAC_KEY_SIZE);
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
if (!UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
return OEMCrypto_SUCCESS;
}
bool SessionContext::InstallKey(const KeyId& key_id,
const std::vector<uint8_t>& key_data,
const std::vector<uint8_t>& key_data_iv,
const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv) {
const std::vector<uint8_t>& key_control_iv,
const std::vector<uint8_t>& pst) {
// Decrypt encrypted key_data using derived encryption key and offered iv
std::vector<uint8_t> content_key;
std::vector<uint8_t> key_control_str;
KeyControlBlock key_control_block;
if (!ce_->DecryptMessage(this, encryption_key_, key_data_iv,
key_data, &content_key)) {
if (!DecryptMessage(encryption_key_, key_data_iv, key_data, &content_key)) {
LOGE("[Installkey(): Could not decrypt key data]");
return false;
}
@@ -456,27 +449,94 @@ bool SessionContext::InstallKey(const KeyId& key_id,
// Key control must be supplied by license server
if (key_control.empty()) {
LOGE("[Installkey(): WARNING: No Key Control]");
key_control_block.Invalidate();
return false;
} else {
if (key_control_iv.empty()) {
LOGE("[Installkey(): ERROR: No Key Control IV]");
return false;
}
if (!ce_->DecryptMessage(this, content_key, key_control_iv,
key_control, &key_control_str)) {
LOGE("[Installkey(): ERROR: Could not decrypt content key]");
return false;
}
}
if (key_control_iv.empty()) {
LOGE("[Installkey(): ERROR: No Key Control IV]");
return false;
}
if (!DecryptMessage(content_key, key_control_iv, key_control,
&key_control_str)) {
LOGE("[Installkey(): ERROR: Could not decrypt content key]");
return false;
}
if (!ParseKeyControl(key_control_str, key_control_block)) {
LOGE("Error parsing key control.");
KeyControlBlock key_control_block(key_control_str);
if (!key_control_block.valid()) {
LOGE("Error parsing key control.");
return false;
}
if (!CheckNonceOrPST(key_control_block, pst)) {
LOGE("Failed Nonce or PST check.");
return false;
}
Key key(content_key, key_control_block);
session_keys_.Insert(key_id, key);
return true;
}
bool SessionContext::RefreshKey(const KeyId& key_id,
const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv) {
if (key_id.empty()) {
// Key control is not encrypted if key id is NULL
KeyControlBlock key_control_block(key_control);
if (!key_control_block.valid()) {
LOGD("Parse key control error.");
return false;
}
if ((key_control_block.control_bits() & kControlNonceEnabled) &&
(!CheckNonce(key_control_block.nonce()))) {
LOGE("KCB: BAD Nonce");
return false;
}
// Apply duration to all keys in this session
session_keys_.UpdateDuration(key_control_block);
return true;
}
Key* content_key = session_keys_.Find(key_id);
if (NULL == content_key) {
LOGD("Error: no matching content key.");
return false;
}
if (key_control.empty()) {
LOGD("Error: no key_control.");
return false;
}
const std::vector<uint8_t> content_key_value = content_key->value();
// Decrypt encrypted key control block
std::vector<uint8_t> control;
if (key_control_iv.empty()) {
// TODO(fredg): get confirmation from server team this is valid.
LOGD("Key control block is NOT encrypted.");
control = key_control;
} else {
// TODO(fredg): get confirmation from server team this is valid, too.
LOGD("Key control block is encrypted.");
if (!DecryptMessage(content_key_value, key_control_iv, key_control,
&control)) {
LOGD("Error decrypting key control block.");
return false;
}
}
Key key(KEYTYPE_CONTENT, content_key, key_control_block);
session_keys_.Insert(key_id, key);
KeyControlBlock key_control_block(control);
if (!key_control_block.valid()) {
LOGD("Parse key control error.");
return false;
}
if ((key_control_block.control_bits() & kControlNonceEnabled) &&
(!CheckNonce(key_control_block.nonce()))) {
LOGE("KCB: BAD Nonce");
return false;
}
content_key->UpdateDuration(key_control_block);
return true;
}
@@ -720,7 +780,7 @@ OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
unsigned int md_len = *signature_length;
if (HMAC(EVP_sha256(), &key[0], SHA256_DIGEST_LENGTH,
if (HMAC(EVP_sha256(), &key[0], key.size(),
in_buffer, buffer_length, signature, &md_len)) {
*signature_length = md_len;
return OEMCrypto_SUCCESS;
@@ -765,7 +825,7 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
}
unsigned int md_len = signature_length;
uint8_t computed_signature[SHA256_DIGEST_LENGTH];
if (HMAC(EVP_sha256(), &key[0], SHA256_DIGEST_LENGTH,
if (HMAC(EVP_sha256(), &key[0], key.size(),
in_buffer, buffer_length, computed_signature, &md_len)) {
if (0 == memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH)) {
return OEMCrypto_SUCCESS;
@@ -778,71 +838,12 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
bool SessionContext::RefreshKey(const KeyId& key_id,
const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv) {
if (key_id.empty()) {
// Key control is not encrypted if key id is NULL
KeyControlBlock key_control_block(true);
if (!ParseKeyControl(key_control, key_control_block)) {
LOGD("Parse key control error.");
return false;
}
// Apply duration to all keys in this session
return session_keys_.UpdateDuration(key_control_block);
}
Key* content_key = session_keys_.Find(key_id);
if (NULL == content_key) {
LOGD("Error: no matching content key.");
return false;
}
if (key_control.empty()) {
LOGD("Error: no key_control.");
return false;
}
const std::vector<uint8_t> content_key_value = content_key->value();
// Decrypt encrypted key control block
std::vector<uint8_t> control;
if (key_control_iv.empty()) {
// TODO(fredg): get confirmation from server team this is valid.
LOGD("Key control block is NOT encrypted.");
control = key_control;
} else {
// TODO(fredg): get confirmation from server team this is valid, too.
LOGD("Key control block is encrypted.");
if (!ce_->DecryptMessage(this, content_key_value, key_control_iv,
key_control, &control)) {
LOGD("Error decrypting key control block.");
return false;
}
}
KeyControlBlock key_control_block(true);
if (!ParseKeyControl(control, key_control_block)) {
LOGD("Error parsing key control.");
return false;
}
if (!content_key->UpdateDuration(key_control_block)) {
LOGD("Error updating duration.");
return false;
}
return true;
}
bool SessionContext::UpdateMacKeys(const std::vector<uint8_t>& enc_mac_keys,
const std::vector<uint8_t>& iv) {
// Decrypt mac key from enc_mac_key using device_keya
std::vector<uint8_t> mac_keys;
if (!ce_->DecryptMessage(this, encryption_key_, iv,
enc_mac_keys, &mac_keys)) {
if (!DecryptMessage(encryption_key_, iv, enc_mac_keys, &mac_keys)) {
return false;
}
mac_key_server_ = std::vector<uint8_t>(mac_keys.begin(),
@@ -933,11 +934,10 @@ SessionContext* CryptoEngine::FindSession(SessionId sid) {
}
// Internal utility function to decrypt the message
bool CryptoEngine::DecryptMessage(SessionContext* session,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& message,
std::vector<uint8_t>* decrypted) {
bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& message,
std::vector<uint8_t>* decrypted) {
if (key.empty() || iv.empty() || message.empty() || !decrypted) {
LOGE("[DecryptMessage(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return false;
@@ -952,13 +952,10 @@ bool CryptoEngine::DecryptMessage(SessionContext* session,
return true;
}
OEMCryptoResult CryptoEngine::DecryptCTR(SessionContext* session,
const uint8_t* iv, size_t block_offset,
const uint8_t* cipher_data,
size_t cipher_data_length,
bool is_encrypted, uint8_t* clear_data,
BufferType buffer_type) {
OEMCryptoResult SessionContext::DecryptCTR(
const uint8_t* iv, size_t block_offset, const uint8_t* cipher_data,
size_t cipher_data_length, bool is_encrypted, uint8_t* clear_data,
BufferType buffer_type) {
// If the data is clear, we do not need a current key selected.
if (!is_encrypted && buffer_type != kBufferTypeDirect) {
memcpy(reinterpret_cast<uint8_t*>(clear_data),
@@ -967,39 +964,38 @@ OEMCryptoResult CryptoEngine::DecryptCTR(SessionContext* session,
}
// Check there is a content key
if (session->current_content_key() == NULL) {
if (current_content_key() == NULL) {
LOGE("[DecryptCTR(): OEMCrypto_ERROR_NO_CONTENT_KEY]");
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
const KeyControlBlock& control = session->current_content_key()->control();
const KeyControlBlock& control = current_content_key()->control();
if (control.control_bits() & kControlDataPathSecure) {
if (buffer_type == kBufferTypeClear) {
LOGE("[DecryptCTR(): Secure key with insecure buffer]");
return OEMCrypto_ERROR_DECRYPT_FAILED;
}
}
if (!local_display_) { // Only look at HDCP if the display is not local.
if (control.control_bits() & kControlHDCPRequired) {
uint8_t required_hdcp
= (control.control_bits() & kControlHDCPVersionMask)
>> kControlHDCPVersionShift;
// For reference implementation, we pretend we can handle the current
// HDCP version.
if (required_hdcp > current_hdcp_capability()
|| current_hdcp_capability() == 0) {
return OEMCrypto_ERROR_INSUFFICIENT_HDCP;
}
}
}
if (control.duration() > 0) {
if (control.duration() < session->CurrentTimer()) {
if (control.duration() < CurrentTimer()) {
LOGE("[DecryptCTR(): KEY_EXPIRED]");
return OEMCrypto_ERROR_KEY_EXPIRED;
}
}
const std::vector<uint8_t>& content_key = session->current_content_key()->value();
if (!ce_->local_display()) { // Only look at HDCP if the display is not
// local.
if (control.control_bits() & kControlHDCPRequired) {
uint8_t required_hdcp =
(control.control_bits() & kControlHDCPVersionMask) >>
kControlHDCPVersionShift;
// For reference implementation, we pretend we can handle the current
// HDCP version.
if (required_hdcp > ce_->current_hdcp_capability() ||
ce_->current_hdcp_capability() == 0) {
return OEMCrypto_ERROR_INSUFFICIENT_HDCP;
}
}
}
const std::vector<uint8_t>& content_key = current_content_key()->value();
// Set the AES key.
if (static_cast<int>(content_key.size()) != AES_BLOCK_SIZE) {

View File

@@ -50,7 +50,7 @@ class SessionKeyTable {
bool Insert(const KeyId key_id, const Key& key_data);
Key* Find(const KeyId key_id);
void Remove(const KeyId key_id);
bool UpdateDuration(const KeyControlBlock& control);
void UpdateDuration(const KeyControlBlock& control);
private:
KeyMap keys_;
@@ -87,12 +87,13 @@ class SessionContext {
public:
explicit SessionContext(CryptoEngine* ce, SessionId sid)
: valid_(true), ce_(ce), id_(sid), current_content_key_(NULL),
rsa_key_(NULL), allowed_schemes_(kSign_RSASSA_PSS) {}
~SessionContext() {}
void Open();
void Close();
: valid_(true),
ce_(ce),
id_(sid),
current_content_key_(NULL),
rsa_key_(NULL),
allowed_schemes_(kSign_RSASSA_PSS) {}
~SessionContext();
bool isValid() { return valid_; }
@@ -116,6 +117,11 @@ class SessionContext {
size_t message_length,
const uint8_t* signature,
size_t signature_length);
OEMCryptoResult DecryptCTR(const uint8_t* iv, size_t block_offset,
const uint8_t* cipher_data,
size_t cipher_data_length, bool is_encrypted,
uint8_t* clear_data, BufferType buffer_type);
OEMCryptoResult Generic_Encrypt(const uint8_t* in_buffer,
size_t buffer_length, const uint8_t* iv,
OEMCrypto_Algorithm algorithm,
@@ -133,11 +139,23 @@ class SessionContext {
size_t signature_length);
void StartTimer();
uint32_t CurrentTimer(); // (seconds).
OEMCryptoResult LoadKeys(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
const uint8_t* enc_mac_key_iv,
const uint8_t* enc_mac_keys,
size_t num_keys,
const OEMCrypto_KeyObject* key_array,
const uint8_t* pst,
size_t pst_length);
bool InstallKey(const KeyId& key_id,
const std::vector<uint8_t>& key_data,
const std::vector<uint8_t>& key_data_iv,
const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv);
const std::vector<uint8_t>& key_control_iv,
const std::vector<uint8_t>& pst);
bool DecryptRSAKey(const uint8_t* enc_rsa_key,
size_t enc_rsa_key_length,
const uint8_t* wrapped_rsa_key_iv,
@@ -152,8 +170,6 @@ class SessionContext {
size_t message_length,
const uint8_t* signature,
size_t signature_length);
bool ParseKeyControl(const std::vector<uint8_t>& key_control_string,
KeyControlBlock& key_control_block);
bool RefreshKey(const KeyId& key_id,
const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv);
@@ -166,14 +182,15 @@ class SessionContext {
}
const std::vector<uint8_t>& mac_key_server() { return mac_key_server_; }
void set_mac_key_client(const std::vector<uint8_t>& mac_key_client) {
mac_key_client_ = mac_key_client; }
mac_key_client_ = mac_key_client;
}
const std::vector<uint8_t>& mac_key_client() { return mac_key_client_; }
void set_encryption_key(const std::vector<uint8_t>& enc_key) {
encryption_key_ = enc_key;
}
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
const uint32_t allowed_schemes() { return allowed_schemes_; }
uint32_t allowed_schemes() const { return allowed_schemes_; }
void AddNonce(uint32_t nonce);
bool CheckNonce(uint32_t nonce);
@@ -183,6 +200,12 @@ class SessionContext {
bool DeriveKey(const std::vector<uint8_t>& key, const std::vector<uint8_t>& context,
int counter, std::vector<uint8_t>* out);
bool DecryptMessage(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& message,
std::vector<uint8_t>* decrypted);
bool CheckNonceOrPST(KeyControlBlock& key_control_block,
const std::vector<uint8_t>& pst);
bool valid_;
CryptoEngine* ce_;
@@ -237,25 +260,16 @@ class CryptoEngine {
current_session_ = current;
}
bool DecryptMessage(SessionContext* session,
const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv,
const std::vector<uint8_t>& message,
std::vector<uint8_t>* decrypted);
OEMCryptoResult DecryptCTR(SessionContext* session, const uint8_t* iv,
size_t block_offset, const uint8_t* cipher_data,
size_t cipher_data_length, bool is_encrypted,
uint8_t* clear_data, BufferType buffer_type);
const OEMCrypto_HDCP_Capability current_hdcp_capability() {
OEMCrypto_HDCP_Capability current_hdcp_capability() const {
return local_display_ ? 0xFF : current_hdcp_capability_;
}
const OEMCrypto_HDCP_Capability maximum_hdcp_capability() {
OEMCrypto_HDCP_Capability maximum_hdcp_capability() const {
return maximum_hdcp_capability_;
}
bool local_display() { return local_display_; }
private:
bool valid_;

View File

@@ -15,25 +15,15 @@
namespace wvoec_mock {
bool KeyControlBlock::Validate() {
valid_ = false;
if ((0x6b63746c != verification_) && // kctl.
(0x6b633039 != verification_)) { // kc09.
LOGE("KCB: BAD verification string: %08X (not %08X or %08X)",
verification_, 0x6b63746c, 0x6b633039);
return false;
}
#define FOURCC(c1, c2, c3, c4) \
(c1 << 24 | c2 << 16 | c3 << 8 | c4)
if (refresh_) {
if (control_bits_ & kControlObserveDataPath) {
LOGW("KCB: data_path_type set for refresh.");
}
if (control_bits_ & kControlObserveHDCP) {
LOGW("KCB: HDCP setting set for refresh.");
}
if (control_bits_ & kControlObserveCGMS) {
LOGW("KCB: CGMS setting set for refresh.");
}
bool KeyControlBlock::Validate() {
if ((FOURCC('k', 'c', 't', 'l') != verification_) && // original verification
(FOURCC('k', 'c', '0', '9') != verification_)) { // add in version 9 api.
LOGE("KCB: BAD verification string: %08X (not %08X or %08X)", verification_,
0x6b63746c, 0x6b633039);
return false;
}
valid_ = true;
return valid_;
@@ -50,11 +40,12 @@ uint32_t KeyControlBlock::ExtractField(const std::vector<uint8_t>& str, int idx)
return t;
}
bool KeyControlBlock::SetFromString(const std::vector<uint8_t>& key_control_string) {
KeyControlBlock::KeyControlBlock(
const std::vector<uint8_t>& key_control_string) {
if (key_control_string.size() < wvcdm::KEY_CONTROL_SIZE) {
LOGE("KCB: BAD Size: %d (not %d)",key_control_string.size(),
wvcdm::KEY_CONTROL_SIZE);
return false;
return;
}
verification_ = ExtractField(key_control_string, 0);
@@ -62,73 +53,56 @@ bool KeyControlBlock::SetFromString(const std::vector<uint8_t>& key_control_stri
nonce_ = ExtractField(key_control_string, 2);
control_bits_ = ExtractField(key_control_string, 3);
return Validate();
LOGD("KCB:");
LOGD(" valid: %d", valid());
LOGD(" duration: %d", duration());
LOGD(" nonce: %08X", nonce());
LOGD(" magic: %08X", verification());
LOGD(" bits: %08X", control_bits());
switch (control_bits() & kControlReplayMask) {
case kControlNonceRequired:
LOGD(" bits kControlReplay kControlNonceRequired.");
break;
case kControlNonceOrEntry:
LOGD(" bits kControlReplay kControlNonceOrEntry.");
break;
default:
LOGD(" bits kControlReplay unset.");
break;
}
LOGD(" bits kControlKDCPVersion 0x%02x.",
(control_bits() & kControlHDCPVersionMask) >> kControlHDCPVersionShift);
LOGD(" bit kControlAllowEncrypt %s.",
(control_bits() & kControlAllowEncrypt) ? "set" : "unset");
LOGD(" bit kControlAllowDecrypt %s.",
(control_bits() & kControlAllowDecrypt) ? "set" : "unset");
LOGD(" bit kControlAllowSign %s.",
(control_bits() & kControlAllowSign) ? "set" : "unset");
LOGD(" bit kControlAllowVerify %s.",
(control_bits() & kControlAllowVerify) ? "set" : "unset");
LOGD(" bit kControlObserveDataPath %s.",
(control_bits() & kControlObserveDataPath) ? "set" : "unset");
LOGD(" bit kControlObserveHDCP %s.",
(control_bits() & kControlObserveHDCP) ? "set" : "unset");
LOGD(" bit kControlObserveCGMS %s.",
(control_bits() & kControlObserveCGMS) ? "set" : "unset");
LOGD(" bit kControlDataPathSecure %s.",
(control_bits() & kControlDataPathSecure) ? "set" : "unset");
LOGD(" bit kControlNonceEnabled %s.",
(control_bits() & kControlNonceEnabled) ? "set" : "unset");
LOGD(" bit kControlHDCPRequired %s.",
(control_bits() & kControlHDCPRequired) ? "set" : "unset");
uint32_t cgms_bits = control_bits() & 0x3;
const char* cgms_values[4] = {"free", "BAD", "once", "never"};
LOGD(" CGMS = %s", cgms_values[cgms_bits]);
Validate();
}
Key::Key(KeyType ktype, const std::vector<uint8_t>& key_string,
const KeyControlBlock& control) :
valid_(true), type_(ktype),
value_(key_string), has_control_(true),
control_(control) {
}
bool Key::setValue(const char* key_string, size_t key_string_length) {
valid_ = false;
if (!key_string || key_string_length == 0) {
return false;
}
value_.assign(key_string, key_string + key_string_length);
if (isValidType() && has_control_) {
valid_ = true;
}
return valid_;
}
bool Key::setType(KeyType ktype) {
valid_ = false;
type_ = ktype;
if (value_.empty()) {
return false;
}
if (isValidType() && has_control_) {
valid_ = true;
}
return valid_;
}
bool Key::setControl(const KeyControlBlock& control) {
valid_ = false;
if (!control.valid()) {
return false;
}
control_ = control;
has_control_ = true;
if (isValidType() && !value_.empty()) {
valid_ = true;
}
return valid_;
}
bool Key::UpdateDuration(const KeyControlBlock& control) {
valid_ = false;
if (!control.valid() || !has_control_) {
LOGE("UpdateDuration: control block not valid.");
return false;
}
Key::Key(const std::vector<uint8_t>& key_string, const KeyControlBlock& control)
: value_(key_string), control_(control) {}
void Key::UpdateDuration(const KeyControlBlock& control) {
control_.set_duration(control.duration());
if (isValidType() && !value_.empty()) {
valid_ = true;
} else {
LOGE("UpdateDuration: value or type bad.");
}
return valid_;
}
}; // namespace wvoec_eng

View File

@@ -15,17 +15,6 @@
namespace wvoec_mock {
enum KeyType {
KEYTYPE_UNKNOWN,
KEYTYPE_PREPROV,
KEYTYPE_ROOT,
KEYTYPE_DEVICE,
KEYTYPE_CONTENT,
KEYTYPE_CONTENT_AUDIO,
KEYTYPE_CONTENT_VIDEO,
KEYTYPE_MAX
};
const uint32_t kControlObserveDataPath = (1<<31);
const uint32_t kControlObserveHDCP = (1<<30);
const uint32_t kControlObserveCGMS = (1<<29);
@@ -48,11 +37,9 @@ const uint32_t kControlCGMSCopyNever = (0x03);
class KeyControlBlock {
public:
KeyControlBlock() : valid_(false) {}
KeyControlBlock(bool refresh) : valid_(false), refresh_(refresh) {}
KeyControlBlock(const std::vector<uint8_t>& key_control_string);
~KeyControlBlock() {}
bool SetFromString(const std::vector<uint8_t>& key_control_string);
bool Validate();
void Invalidate() { valid_ = false; }
@@ -68,57 +55,25 @@ class KeyControlBlock {
uint32_t ExtractField(const std::vector<uint8_t>& str, int idx);
bool valid_;
bool refresh_;
uint32_t verification_;
uint32_t duration_;
uint32_t nonce_;
uint32_t control_bits_;
};
// AES-128 crypto key
// AES-128 crypto key, or HMAC signing key.
class Key {
public:
Key() : valid_(false), type_(KEYTYPE_UNKNOWN), has_control_(false) {}
Key(const Key& key) : valid_(key.valid_), type_(key.type_),
value_(key.value_),
has_control_(key.has_control_),
control_(key.control_) {}
Key(KeyType type, const std::vector<uint8_t>& key_string,
const KeyControlBlock& control);
Key(const Key& key) : value_(key.value_), control_(key.control_) {}
Key(const std::vector<uint8_t>& key_string, const KeyControlBlock& control);
virtual ~Key() {};
// Key is valid iff setValue(), setType(), and setControl() have been called
bool setValue(const char* key_string, size_t key_string_length);
bool setType(KeyType ktype);
bool setControl(const KeyControlBlock& control);
bool UpdateDuration(const KeyControlBlock& control);
KeyType keyType() { return type_; }
void UpdateDuration(const KeyControlBlock& control);
const std::vector<uint8_t>& value() const { return value_; }
const KeyControlBlock& control() const { return control_; }
bool isDeviceKey() { return (KEYTYPE_DEVICE == type_); }
bool isRootKey() { return (KEYTYPE_ROOT == type_); }
bool isPreprovKey() { return (KEYTYPE_PREPROV == type_); }
bool isContentKey() {
bool ctypes = (KEYTYPE_CONTENT == type_) ||
(KEYTYPE_CONTENT_AUDIO == type_) ||
(KEYTYPE_CONTENT_VIDEO == type_);
return ctypes;
}
bool isValidType() {
return ((KEYTYPE_UNKNOWN < type_) && (KEYTYPE_MAX > type_));
}
bool isValid() { return valid_; }
void clear() { value_.clear(); valid_ = false; }
private:
bool valid_;
KeyType type_;
std::vector<uint8_t> value_;
bool has_control_;
KeyControlBlock control_;
};

View File

@@ -74,7 +74,7 @@ KeyboxError WvKeybox::Validate() {
WidevineKeybox keybox;
memset(&keybox, 0, sizeof(keybox));
memcpy(keybox.device_id_, &device_id_[0], device_id_.size());
memcpy(keybox.device_key_, &device_key_.value()[0], sizeof(keybox.device_key_));
memcpy(keybox.device_key_, &device_key_[0], sizeof(keybox.device_key_));
memcpy(keybox.data_, key_data_, sizeof(keybox.data_));
memcpy(keybox.magic_, magic_, sizeof(keybox.magic_));
@@ -99,9 +99,8 @@ bool WvKeybox::InstallKeybox(const uint8_t* buffer, size_t keyBoxLength) {
= strnlen(reinterpret_cast<const char*>(keybox->device_id_), 32);
device_id_.assign(keybox->device_id_,
keybox->device_id_ + device_id_length);
device_key_.setValue(reinterpret_cast<const char*>(keybox->device_key_),
sizeof(keybox->device_key_));
device_key_.setType(KEYTYPE_DEVICE);
device_key_.assign(keybox->device_key_,
keybox->device_key_ + sizeof(keybox->device_key_));
memcpy(key_data_, keybox->data_, sizeof(keybox->data_));
memcpy(magic_, keybox->magic_, sizeof(keybox->magic_));
memcpy(crc_, keybox->crc_, sizeof(keybox->crc_));

View File

@@ -29,7 +29,7 @@ class WvKeybox {
KeyboxError Validate();
const std::vector<uint8_t>& device_id() { return device_id_; }
Key& device_key() { return device_key_; }
std::vector<uint8_t>& device_key() { return device_key_; }
const WvKeyboxKeyData& key_data() { return key_data_; }
size_t key_data_length() { return KEY_DATA_LENGTH; }
bool InstallKeybox(const uint8_t* keybox, size_t keyBoxLength);
@@ -40,7 +40,7 @@ class WvKeybox {
bool valid_;
std::vector<uint8_t> device_id_;
Key device_key_;
std::vector<uint8_t> device_key_;
WvKeyboxKeyData key_data_;
uint8_t magic_[4];
uint8_t crc_[4];

View File

@@ -199,7 +199,7 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(OEMCrypto_SESSION session,
enc_key_context + enc_key_context_length);
// Generate mac and encryption keys for current session context
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key(),
mac_ctx_str, enc_ctx_str)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -289,6 +289,7 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
dump_hex("signature", signature, signature_length);
dump_hex("enc_mac_key_iv", enc_mac_key_iv, wvcdm::KEY_IV_SIZE);
dump_hex("enc_mac_keys", enc_mac_keys, 2*wvcdm::MAC_KEY_SIZE);
dump_hex("pst", pst, pst_length);
for (size_t i = 0; i < num_keys; i++) {
printf("key_array[%zu].key_id_length=%zu;\n", i, key_array[i].key_id_length);
dump_array_part("key_array", i, "key_id",
@@ -347,60 +348,9 @@ OEMCryptoResult OEMCrypto_LoadKeys(OEMCrypto_SESSION session,
}
}
// Validate message signature
if (!session_ctx->ValidateMessage(message, message_length, signature, signature_length)) {
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
}
session_ctx->StartTimer();
// Decrypt and install keys in key object
// Each key will have a key control block. They will all have the same nonce.
bool status = true;
std::vector<uint8_t> key_id;
std::vector<uint8_t> enc_key_data;
std::vector<uint8_t> key_data_iv;
std::vector<uint8_t> key_control;
std::vector<uint8_t> key_control_iv;
for (unsigned int i = 0; i < num_keys; i++) {
key_id.assign(key_array[i].key_id,
key_array[i].key_id + key_array[i].key_id_length);
enc_key_data.assign(key_array[i].key_data,
key_array[i].key_data + key_array[i].key_data_length);
key_data_iv.assign(key_array[i].key_data_iv,
key_array[i].key_data_iv + wvcdm::KEY_IV_SIZE);
if (key_array[i].key_control == NULL) {
status = false;
break;
}
key_control.assign(key_array[i].key_control,
key_array[i].key_control + wvcdm::KEY_CONTROL_SIZE);
key_control_iv.assign(key_array[i].key_control_iv,
key_array[i].key_control_iv + wvcdm::KEY_IV_SIZE);
if (!session_ctx->InstallKey(key_id, enc_key_data, key_data_iv, key_control,
key_control_iv)) {
status = false;
break;
}
}
session_ctx->FlushNonces();
if (!status) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
// enc_mac_key can be NULL if license renewal is not supported
if (enc_mac_keys == NULL) return OEMCrypto_SUCCESS;
// V2.1 license protocol: update mac keys after processing license response
const std::vector<uint8_t> enc_mac_keys_str = std::vector<uint8_t>(
enc_mac_keys, enc_mac_keys + 2*wvcdm::MAC_KEY_SIZE);
const std::vector<uint8_t> enc_mac_key_iv_str = std::vector<uint8_t>(
enc_mac_key_iv, enc_mac_key_iv + wvcdm::KEY_IV_SIZE);
if (!session_ctx->UpdateMacKeys(enc_mac_keys_str, enc_mac_key_iv_str)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
return session_ctx->LoadKeys(
session, message, message_length, signature, signature_length,
enc_mac_key_iv, enc_mac_keys, num_keys, key_array, pst, pst_length);
}
extern "C"
@@ -582,9 +532,8 @@ OEMCryptoResult OEMCrypto_DecryptCTR(OEMCrypto_SESSION session,
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return crypto_engine->DecryptCTR(session_ctx, iv, block_offset, data_addr,
data_length, is_encrypted, destination,
buffer_type);
return session_ctx->DecryptCTR(iv, block_offset, data_addr, data_length,
is_encrypted, destination, buffer_type);
}
extern "C"
@@ -800,8 +749,8 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
wrapped->context + sizeof(wrapped->context));
// Generate mac and encryption keys for encrypting the signature.
if (result == OEMCrypto_SUCCESS) {
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
context, context)) {
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key(), context,
context)) {
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
@@ -820,7 +769,7 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
if (result == OEMCrypto_SUCCESS) {
unsigned int sig_length = sizeof(wrapped->signature);
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
SHA256_DIGEST_LENGTH, wrapped->context,
session_ctx->mac_key_server().size(), wrapped->context,
buffer_size - sizeof(wrapped->signature), wrapped->signature,
&sig_length)) {
result = OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -865,8 +814,8 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session,
const std::vector<uint8_t> context(wrapped->context,
wrapped->context + sizeof(wrapped->context));
// Generate mac and encryption keys for encrypting the signature.
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key().value(),
context, context)) {
if (!session_ctx->DeriveKeys(crypto_engine->keybox().device_key(), context,
context)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
// Decrypt RSA key.
@@ -1019,6 +968,10 @@ const char* OEMCrypto_SecurityLevel() {
extern "C"
OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability *current,
OEMCrypto_HDCP_Capability *maximum) {
if (trace_all_calls) {
printf("-- OEMCryptoResult OEMCrypto_GetHDCPCapability(%p, %p)\n",
current, maximum);
}
if (current == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (maximum == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
*current = crypto_engine->current_hdcp_capability();
@@ -1034,6 +987,12 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt(OEMCrypto_SESSION session,
OEMCrypto_Algorithm algorithm,
uint8_t* out_buffer) {
if (trace_all_calls) {
printf("-- OEMCryptoResult OEMCrypto_Generic_Encrypt( algorithm=%d\n",
algorithm);
dump_hex("in_buffer", in_buffer, buffer_length);
dump_hex("iv", iv, wvcdm::KEY_IV_SIZE);
}
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
LOGE("[OEMCrypto_Generic_Enrypt(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
@@ -1048,8 +1007,13 @@ OEMCryptoResult OEMCrypto_Generic_Encrypt(OEMCrypto_SESSION session,
LOGE("[OEMCrypto_Generic_Enrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return session_ctx->Generic_Encrypt(in_buffer, buffer_length, iv, algorithm,
out_buffer);
OEMCryptoResult sts =
session_ctx->Generic_Encrypt(in_buffer, buffer_length, iv, algorithm,
out_buffer);
if (trace_all_calls) {
dump_hex("out_buffer", out_buffer, buffer_length);
}
return sts;
}
extern "C"
@@ -1059,6 +1023,12 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt(OEMCrypto_SESSION session,
const uint8_t* iv,
OEMCrypto_Algorithm algorithm,
uint8_t* out_buffer) {
if (trace_all_calls) {
printf("-- OEMCryptoResult OEMCrypto_Generic_Decrypt( algorithm=%d\n",
algorithm);
dump_hex("in_buffer", in_buffer, buffer_length);
dump_hex("iv", iv, wvcdm::KEY_IV_SIZE);
}
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
LOGE("[OEMCrypto_Generic_Decrypt(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
@@ -1073,8 +1043,13 @@ OEMCryptoResult OEMCrypto_Generic_Decrypt(OEMCrypto_SESSION session,
LOGE("[OEMCrypto_Generic_Decrypt(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return session_ctx->Generic_Decrypt(in_buffer, buffer_length, iv, algorithm,
out_buffer);
OEMCryptoResult sts =
session_ctx->Generic_Decrypt(in_buffer, buffer_length, iv, algorithm,
out_buffer);
if (trace_all_calls) {
dump_hex("out_buffer", out_buffer, buffer_length);
}
return sts;
}
extern "C"
@@ -1084,6 +1059,11 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session,
OEMCrypto_Algorithm algorithm,
uint8_t* signature,
size_t* signature_length) {
if (trace_all_calls) {
printf("-- OEMCryptoResult OEMCrypto_Generic_Sign( algorithm=%d\n",
algorithm);
dump_hex("in_buffer", in_buffer, buffer_length);
}
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
LOGE("[OEMCrypto_Generic_Sign(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
@@ -1101,8 +1081,13 @@ OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session,
LOGE("[OEMCrypto_Generic_Sign(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
return session_ctx->Generic_Sign(in_buffer, buffer_length, algorithm,
signature, signature_length);
OEMCryptoResult sts =
session_ctx->Generic_Sign(in_buffer, buffer_length, algorithm,
signature, signature_length);
if (trace_all_calls) {
dump_hex("signature", signature, *signature_length);
}
return sts;
}
extern "C"
@@ -1112,6 +1097,12 @@ OEMCryptoResult OEMCrypto_Generic_Verify(OEMCrypto_SESSION session,
OEMCrypto_Algorithm algorithm,
const uint8_t* signature,
size_t signature_length) {
if (trace_all_calls) {
printf("-- OEMCryptoResult OEMCrypto_Generic_Verify( algorithm=%d\n",
algorithm);
dump_hex("in_buffer", in_buffer, buffer_length);
dump_hex("signature", signature, signature_length);
}
if (NO_ERROR != crypto_engine->ValidateKeybox()) {
LOGE("[OEMCrypto_Generic_Verify(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;