Source release v3.5.0

This commit is contained in:
Gene Morgan
2017-11-28 17:42:16 -08:00
parent 501c22890d
commit 31381a1311
155 changed files with 16680 additions and 3816 deletions

View File

@@ -23,8 +23,8 @@
#include "OEMCryptoCENC.h"
#include "log.h"
#include "oec_device_features.h"
#include "oec_test_data.h"
#include "oemcrypto_key_mock.h"
#include "test_rsa_key.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
@@ -35,18 +35,31 @@ using namespace std;
// GTest requires PrintTo to be in the same namespace as the thing it prints,
// which is std::vector in this case.
namespace std {
void PrintTo(const vector<uint8_t>& value, ostream* os) {
*os << wvcdm::b2a_hex(value);
}
} // namespace std
void PrintTo(const PatternTestVariant& param, ostream* os) {
*os << ((param.mode == OEMCrypto_CipherMode_CTR) ? "CTR mode" : "CBC mode")
<< ", encrypt=" << param.pattern.encrypt
<< ", skip=" << param.pattern.skip;
namespace {
int GetRandBytes(unsigned char* buf, int num) {
// returns 1 on success, -1 if not supported, or 0 if other failure.
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
return RAND_pseudo_bytes(buf, num);
#else
return RAND_bytes(buf, num);
#endif
}
} // namespace std
#ifdef OPENSSL_IS_BORINGSSL
void DeleteX509Stack(STACK_OF(X509)* stack) {
sk_X509_pop_free(stack, X509_free);
}
typedef size_t X509Count;
#else
typedef int X509Count;
#endif
} // namespace
namespace wvoec {
@@ -82,7 +95,7 @@ class openssl_ptr {
T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
T* get() const { return ptr_; }
bool NotNull() { return ptr_; }
bool NotNull() const { return ptr_; }
private:
T* ptr_;
@@ -181,8 +194,10 @@ void Session::GenerateDerivedKeysFromKeybox() {
// with test keybox "installed".
mac_key_server_ = wvcdm::a2b_hex(
"3CFD60254786AF350B353B4FBB700AB382558400356866BA16C256BCD8C502BF");
mac_key_client_ = wvcdm::a2b_hex(
"A9DE7B3E4E199ED8D1FBC29CD6B4C772CC4538C8B0D3E208B3E76F2EC0FD6F47");
enc_key_ = wvcdm::a2b_hex("D0BFC35DA9E33436E81C4229E78CB9F4");
}
@@ -191,7 +206,7 @@ void Session::GenerateDerivedKeysFromSessionKey() {
GenerateNonce();
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
PreparePublicKey();
if (public_rsa_ == NULL) PreparePublicKey();
ASSERT_TRUE(GenerateRSASessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
@@ -222,22 +237,23 @@ void Session::LoadTestKeys(const std::string& pst, bool new_mac_keys) {
&signature_[0], signature_.size(),
encrypted_license().mac_key_iv,
encrypted_license().mac_keys, num_keys_,
key_array_, pst_ptr, pst.length()));
key_array_, pst_ptr, pst.length(), NULL));
// Update new generated keys.
memcpy(&mac_key_server_[0], license_.mac_keys, wvcdm::MAC_KEY_SIZE);
memcpy(&mac_key_client_[0], license_.mac_keys + wvcdm::MAC_KEY_SIZE,
wvcdm::MAC_KEY_SIZE);
} else {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_,
&signature_[0], signature_.size(), NULL, NULL,
num_keys_, key_array_, pst_ptr, pst.length()));
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_LoadKeys(session_id(), message_ptr(), message_size_,
&signature_[0], signature_.size(), NULL, NULL,
num_keys_, key_array_, pst_ptr, pst.length(), NULL));
}
VerifyTestKeys();
}
void Session::VerifyTestKeys() {
for (int i = 0; i < num_keys_; i++) {
for (unsigned int i = 0; i < num_keys_; i++) {
KeyControlBlock block;
size_t size = sizeof(block);
OEMCryptoResult sts = OEMCrypto_QueryKeyControl(
@@ -262,6 +278,7 @@ void Session::RefreshTestKeys(const size_t key_count, uint32_t control_bits,
uint32_t nonce, OEMCryptoResult expected_result) {
// Note: we store the message in encrypted_license_, but the refresh key
// message is not actually encrypted. It is, however, signed.
// FillRefreshMessage fills the message with a duration of kLongDuration.
FillRefreshMessage(key_count, control_bits, nonce);
ServerSignBuffer(reinterpret_cast<const uint8_t*>(&padded_message_),
message_size_, &signature_);
@@ -273,9 +290,14 @@ void Session::RefreshTestKeys(const size_t key_count, uint32_t control_bits,
ASSERT_EQ(expected_result, sts);
ASSERT_NO_FATAL_FAILURE(TestDecryptCTR());
sleep(kShortSleep); // Should still be valid key.
// This should still be valid key, even if the refresh failed, because this
// is before the original license duration.
sleep(kShortSleep);
ASSERT_NO_FATAL_FAILURE(TestDecryptCTR(false));
sleep(kShortSleep + kLongSleep); // Should be after first expiration.
// This should be after duration of the original license, but before the
// expiration of the refresh message. This should succeed if and only if the
// refresh succeeded.
sleep(kShortSleep + kLongSleep);
if (expected_result == OEMCrypto_SUCCESS) {
ASSERT_NO_FATAL_FAILURE(TestDecryptCTR(false, OEMCrypto_SUCCESS));
} else {
@@ -294,21 +316,24 @@ void Session::SetKeyId(int index, const string& key_id) {
void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
uint32_t nonce, const std::string& pst) {
EXPECT_EQ(
1, RAND_pseudo_bytes(license_.mac_key_iv, sizeof(license_.mac_key_iv)));
EXPECT_EQ(1, RAND_pseudo_bytes(license_.mac_keys, sizeof(license_.mac_keys)));
for (int i = 0; i < num_keys_; i++) {
1, GetRandBytes(license_.mac_key_iv, sizeof(license_.mac_key_iv)));
EXPECT_EQ(1, GetRandBytes(license_.mac_keys, sizeof(license_.mac_keys)));
for (unsigned int i = 0; i < num_keys_; i++) {
memset(license_.keys[i].key_id, 0, kTestKeyIdMaxLength);
license_.keys[i].key_id_length = kDefaultKeyIdLength;
memset(license_.keys[i].key_id, i, license_.keys[i].key_id_length);
EXPECT_EQ(1, RAND_pseudo_bytes(license_.keys[i].key_data,
EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_data,
sizeof(license_.keys[i].key_data)));
license_.keys[i].key_data_length = wvcdm::KEY_SIZE;
EXPECT_EQ(1, RAND_pseudo_bytes(license_.keys[i].key_iv,
EXPECT_EQ(1, GetRandBytes(license_.keys[i].key_iv,
sizeof(license_.keys[i].key_iv)));
EXPECT_EQ(1, RAND_pseudo_bytes(license_.keys[i].control_iv,
EXPECT_EQ(1, GetRandBytes(license_.keys[i].control_iv,
sizeof(license_.keys[i].control_iv)));
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
if (global_features.api_version == 12) {
if (global_features.api_version == 13) {
// For version 13, we require OEMCrypto to handle kc13 for all licenses.
memcpy(license_.keys[i].control.verification, "kc13", 4);
} else if (global_features.api_version == 12) {
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
memcpy(license_.keys[i].control.verification, "kc12", 4);
} else if (control & wvoec_mock::kControlSecurityPatchLevelMask) {
// For versions before 12, we require the special key control block only
@@ -328,6 +353,7 @@ void Session::FillSimpleMessage(uint32_t duration, uint32_t control,
license_.keys[i].cipher_mode = OEMCrypto_CipherMode_CTR;
}
memcpy(license_.pst, pst.c_str(), min(sizeof(license_.pst), pst.length()));
pst_ = pst;
}
void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits,
@@ -336,7 +362,10 @@ void Session::FillRefreshMessage(size_t key_count, uint32_t control_bits,
encrypted_license().keys[i].key_id_length = license_.keys[i].key_id_length;
memcpy(encrypted_license().keys[i].key_id, license_.keys[i].key_id,
encrypted_license().keys[i].key_id_length);
if (global_features.api_version == 12) {
if (global_features.api_version == 13) {
// For version 13, we require OEMCrypto to handle kc13 for all licenses.
memcpy(encrypted_license().keys[i].control.verification, "kc13", 4);
} else if (global_features.api_version == 12) {
// For version 12, we require OEMCrypto to handle kc12 for all licenses.
memcpy(encrypted_license().keys[i].control.verification, "kc12", 4);
} else {
@@ -360,7 +389,7 @@ void Session::EncryptAndSign() {
AES_cbc_encrypt(&license_.mac_keys[0], &encrypted_license().mac_keys[0],
2 * wvcdm::MAC_KEY_SIZE, &aes_key, iv_buffer, AES_ENCRYPT);
for (int i = 0; i < num_keys_; i++) {
for (unsigned int i = 0; i < num_keys_; i++) {
memcpy(iv_buffer, &license_.keys[i].control_iv[0], wvcdm::KEY_IV_SIZE);
AES_set_encrypt_key(&license_.keys[i].key_data[0], 128, &aes_key);
AES_cbc_encrypt(
@@ -436,7 +465,7 @@ void Session::VerifyClientSignature(size_t data_length) {
void Session::FillKeyArray(const MessageData& data,
OEMCrypto_KeyObject* key_array) {
for (int i = 0; i < num_keys_; i++) {
for (unsigned int i = 0; i < num_keys_; i++) {
key_array[i].key_id = data.keys[i].key_id;
key_array[i].key_id_length = data.keys[i].key_id_length;
key_array[i].key_data_iv = data.keys[i].key_iv;
@@ -502,9 +531,9 @@ void Session::TestDecryptCTR(bool select_key_first,
vector<uint8_t> unencryptedData(256);
for (size_t i = 0; i < unencryptedData.size(); i++)
unencryptedData[i] = i % 256;
EXPECT_EQ(1, RAND_pseudo_bytes(&unencryptedData[0], unencryptedData.size()));
EXPECT_EQ(1, GetRandBytes(&unencryptedData[0], unencryptedData.size()));
vector<uint8_t> encryptionIv(wvcdm::KEY_IV_SIZE);
EXPECT_EQ(1, RAND_pseudo_bytes(&encryptionIv[0], wvcdm::KEY_IV_SIZE));
EXPECT_EQ(1, GetRandBytes(&encryptionIv[0], wvcdm::KEY_IV_SIZE));
vector<uint8_t> encryptedData(unencryptedData.size());
EncryptCTR(unencryptedData, license_.keys[key_index].key_data,
&encryptionIv[0], &encryptedData);
@@ -528,32 +557,74 @@ void Session::TestDecryptCTR(bool select_key_first,
if (expected_result == OEMCrypto_SUCCESS) { // No error.
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
ASSERT_EQ(unencryptedData, outputBuffer);
} else if (expected_result == OEMCrypto_ERROR_KEY_EXPIRED) {
// Report stale keys.
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, sts);
ASSERT_NE(unencryptedData, outputBuffer);
} else if (expected_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP) {
// Report HDCP errors.
ASSERT_EQ(OEMCrypto_ERROR_INSUFFICIENT_HDCP, sts);
ASSERT_NE(unencryptedData, outputBuffer);
} else {
// OEM's can fine tune other error codes for debugging.
ASSERT_NE(OEMCrypto_SUCCESS, sts);
ASSERT_NO_FATAL_FAILURE(TestDecryptResult(expected_result, sts));
ASSERT_NE(unencryptedData, outputBuffer);
}
}
void Session::TestDecryptResult(OEMCryptoResult expected_result,
OEMCryptoResult actual_result) {
if (expected_result == OEMCrypto_SUCCESS) { // No error.
ASSERT_EQ(OEMCrypto_SUCCESS, actual_result);
} else if (expected_result == OEMCrypto_ERROR_KEY_EXPIRED &&
global_features.api_version >= 9) {
// Report stale keys, required in v9 and beyond.
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, actual_result);
} else if (expected_result == OEMCrypto_ERROR_INSUFFICIENT_HDCP) {
// Report HDCP errors.
ASSERT_EQ(OEMCrypto_ERROR_INSUFFICIENT_HDCP, actual_result);
} else if (expected_result == OEMCrypto_ERROR_ANALOG_OUTPUT) {
// Report analog errors.
ASSERT_EQ(OEMCrypto_ERROR_ANALOG_OUTPUT, actual_result);
} else {
// OEM's can fine tune other error codes for debugging.
ASSERT_NE(OEMCrypto_SUCCESS, actual_result);
}
}
void Session::TestSelectExpired(unsigned int key_index) {
if (global_features.api_version >= 13) {
OEMCryptoResult status =
OEMCrypto_SelectKey(session_id(), license().keys[key_index].key_id,
license().keys[key_index].key_id_length);
// It is OK for SelectKey to succeed with an expired key, but if there is
// an error, it must be OEMCrypto_ERROR_KEY_EXIRED.
if (status != OEMCrypto_SUCCESS) {
ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status);
}
}
}
void Session::LoadOEMCert(bool verify_cert) {
// Get the OEM Public Cert from OEMCrypto
vector<uint8_t> public_cert;
size_t public_cert_length = 0;
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
OEMCrypto_GetOEMPublicCertificate(session_id(), NULL,
&public_cert_length));
ASSERT_GT((int)public_cert_length, 0);
ASSERT_LT(0u, public_cert_length);
public_cert.resize(public_cert_length);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GetOEMPublicCertificate(session_id(), &public_cert[0],
&public_cert_length));
// Load the certificate chain into an OpenSSL X509 Stack
#ifdef OPENSSL_IS_BORINGSSL
const openssl_ptr<STACK_OF(X509), DeleteX509Stack> x509_stack(
sk_X509_new_null());
ASSERT_TRUE(x509_stack.NotNull()) << "Unable to allocate X509 stack.";
CBS pkcs7;
CBS_init(&pkcs7, public_cert.data(), public_cert.size());
if (!PKCS7_get_certificates(x509_stack.get(), &pkcs7)) {
dump_openssl_error();
FAIL() << "Unable to deserialize certificate chain.";
}
STACK_OF(X509)* certs = x509_stack.get();
#else
// load the cert into rsa_key_.
openssl_ptr<BIO, BIO_vfree> bio(
BIO_new_mem_buf(&public_cert[0], public_cert_length));
@@ -564,7 +635,10 @@ void Session::LoadOEMCert(bool verify_cert) {
EXPECT_EQ(OBJ_obj2nid(cert->type), NID_pkcs7_signed);
STACK_OF(X509)* certs = cert->d.sign->cert;
for (int i = 0; certs && i < sk_X509_num(certs); i++) {
#endif
// Load the public cert's key into public_rsa_ and verify, if requested
for (X509Count i = 0; certs && i < sk_X509_num(certs); i++) {
X509* x509_cert = sk_X509_value(certs, i);
openssl_ptr<EVP_PKEY, EVP_PKEY_free> pubkey(X509_get_pubkey(x509_cert));
ASSERT_TRUE(pubkey.NotNull());
@@ -589,13 +663,27 @@ void Session::LoadOEMCert(bool verify_cert) {
ASSERT_TRUE(store_ctx.NotNull());
X509_STORE_CTX_init(store_ctx.get(), store.get(), x509_cert, NULL);
// TODO(fredgc): Verify cert is signed by Google.
int result = X509_verify_cert(store_ctx.get());
ASSERT_GE(0, result) << " OEM Cert not valid. "
<< X509_verify_cert_error_string(store_ctx->error);
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
ASSERT_GE(0, result) << " OEM Cert not valid. " <<
X509_verify_cert_error_string(store_ctx->error);
#else
ASSERT_GE(0, result) << " OEM Cert not valid. " <<
X509_verify_cert_error_string(
X509_STORE_CTX_get_error(store_ctx.get()));
#endif
if (result == 0) {
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
printf("Cert not verified: %s.\n",
X509_verify_cert_error_string(store_ctx->error));
#else
printf("Cert not verified: %s.\n",
X509_verify_cert_error_string(
X509_STORE_CTX_get_error(store_ctx.get())));
#endif
}
}
}
@@ -619,7 +707,7 @@ void Session::MakeRSACertificate(struct RSAPrivateKeyMessage* encrypted,
memcpy(message.rsa_key, rsa_key.data(), rsa_key.size());
message.rsa_key_length = rsa_key.size();
}
EXPECT_EQ(1, RAND_pseudo_bytes(message.rsa_key_iv, wvcdm::KEY_IV_SIZE));
EXPECT_EQ(1, GetRandBytes(message.rsa_key_iv, wvcdm::KEY_IV_SIZE));
message.nonce = nonce_;
EncryptProvisioningMessage(&message, encrypted, *encryption_key);
@@ -652,10 +740,10 @@ void Session::RewrapRSAKey(const struct RSAPrivateKeyMessage& encrypted,
wrapped_key->clear();
}
}
void Session::RewrapRSAKey30(
const struct RSAPrivateKeyMessage& encrypted, size_t,
const std::vector<uint8_t>& encrypted_message_key,
vector<uint8_t>* wrapped_key, bool force) {
void Session::RewrapRSAKey30(const struct RSAPrivateKeyMessage& encrypted,
const std::vector<uint8_t>& encrypted_message_key,
vector<uint8_t>* wrapped_key, bool force) {
size_t wrapped_key_length = 0;
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER,
OEMCrypto_RewrapDeviceRSAKey30(
@@ -679,8 +767,8 @@ void Session::RewrapRSAKey30(
void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) {
if (rsa_key == NULL) {
rsa_key = kTestRSAPKCS8PrivateKeyInfo2_2048;
rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048);
rsa_key = wvcdm_test_auth::kRsaPrivateKey_2048;
rsa_key_length = wvcdm_test_auth::kRsaPrivateKeySize_2048;
}
uint8_t* p = const_cast<uint8_t*>(rsa_key);
openssl_ptr<BIO, BIO_vfree> bio(BIO_new_mem_buf(p, rsa_key_length));
@@ -713,38 +801,43 @@ bool Session::VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length) {
EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
EVP_PKEY_CTX* pctx = NULL;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_MD_CTX md_ctx_struct;
EVP_MD_CTX* md_ctx = &md_ctx_struct;
EVP_MD_CTX_init(md_ctx);
#else
EVP_MD_CTX* md_ctx = EVP_MD_CTX_new();
#endif
EVP_PKEY_CTX* pkey_ctx = NULL;
if (EVP_DigestVerifyInit(&ctx, &pctx, EVP_sha1(), NULL /* no ENGINE */,
if (EVP_DigestVerifyInit(md_ctx, &pkey_ctx, EVP_sha1(), NULL /* no ENGINE */,
pkey) != 1) {
LOGE("EVP_DigestVerifyInit failed in VerifyPSSSignature");
goto err;
}
if (EVP_PKEY_CTX_set_signature_md(pctx,
if (EVP_PKEY_CTX_set_signature_md(pkey_ctx,
const_cast<EVP_MD *>(EVP_sha1())) != 1) {
LOGE("EVP_PKEY_CTX_set_signature_md failed in VerifyPSSSignature");
goto err;
}
if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) != 1) {
if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1) {
LOGE("EVP_PKEY_CTX_set_rsa_padding failed in VerifyPSSSignature");
goto err;
}
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, SHA_DIGEST_LENGTH) != 1) {
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, SHA_DIGEST_LENGTH) != 1) {
LOGE("EVP_PKEY_CTX_set_rsa_pss_saltlen failed in VerifyPSSSignature");
goto err;
}
if (EVP_DigestVerifyUpdate(&ctx, message, message_length) != 1) {
if (EVP_DigestVerifyUpdate(md_ctx, message, message_length) != 1) {
LOGE("EVP_DigestVerifyUpdate failed in VerifyPSSSignature");
goto err;
}
if (EVP_DigestVerifyFinal(&ctx, const_cast<uint8_t*>(signature),
if (EVP_DigestVerifyFinal(md_ctx, const_cast<uint8_t*>(signature),
signature_length) != 1) {
LOGE(
"EVP_DigestVerifyFinal failed in VerifyPSSSignature. (Probably a bad "
@@ -752,12 +845,20 @@ bool Session::VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message,
goto err;
}
EVP_MD_CTX_cleanup(&ctx);
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_MD_CTX_cleanup(md_ctx);
#else
EVP_MD_CTX_free(md_ctx);
#endif
return true;
err:
dump_openssl_error();
EVP_MD_CTX_cleanup(&ctx);
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
EVP_MD_CTX_cleanup(md_ctx);
#else
EVP_MD_CTX_free(md_ctx);
#endif
return false;
}
@@ -821,8 +922,61 @@ void Session::InstallRSASessionTestKey(const vector<uint8_t>& wrapped_rsa_key) {
GenerateDerivedKeysFromSessionKey();
}
void Session::GenerateReport(const std::string& pst, bool expect_success,
void Session::CreateNewUsageEntry() {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_CreateNewUsageEntry(session_id(), &usage_entry_number_));
}
void Session::UpdateUsageEntry(std::vector<uint8_t>* header_buffer) {
size_t header_buffer_length = 0;
size_t entry_buffer_length = 0;
ASSERT_EQ(
OEMCrypto_ERROR_SHORT_BUFFER,
OEMCrypto_UpdateUsageEntry(session_id(), NULL, &header_buffer_length,
NULL, &entry_buffer_length));
ASSERT_LT(0u, header_buffer_length);
header_buffer->resize(header_buffer_length);
ASSERT_LT(0u, entry_buffer_length);
encrypted_usage_entry_.resize(entry_buffer_length);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_UpdateUsageEntry(
session_id(), &(header_buffer->front()), &header_buffer_length,
&encrypted_usage_entry_[0], &entry_buffer_length));
}
void Session::DeactivateUsageEntry(const std::string& pst) {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeactivateUsageEntry(
session_id(), reinterpret_cast<const uint8_t*>(pst.c_str()),
pst.length()));
}
void Session::LoadUsageEntry(uint32_t index, const vector<uint8_t>& buffer) {
usage_entry_number_ = index;
encrypted_usage_entry_ = buffer;
ASSERT_EQ(
OEMCrypto_SUCCESS,
OEMCrypto_LoadUsageEntry(session_id(), index, &buffer[0], buffer.size()));
}
void Session::MoveUsageEntry(uint32_t new_index,
std::vector<uint8_t>* header_buffer,
OEMCryptoResult expect_result) {
ASSERT_NO_FATAL_FAILURE(open());
ASSERT_NO_FATAL_FAILURE(ReloadUsageEntry());
ASSERT_EQ(expect_result, OEMCrypto_MoveEntry(session_id(), new_index));
if (expect_result == OEMCrypto_SUCCESS) {
usage_entry_number_ = new_index;
ASSERT_NO_FATAL_FAILURE(UpdateUsageEntry(header_buffer));
}
ASSERT_NO_FATAL_FAILURE(close());
}
void Session::GenerateReport(const std::string& pst,
OEMCryptoResult expected_result,
Session* other) {
ASSERT_TRUE(open_);
if (other) { // If other is specified, copy mac keys.
mac_key_server_ = other->mac_key_server_;
mac_key_client_ = other->mac_key_client_;
@@ -830,54 +984,120 @@ void Session::GenerateReport(const std::string& pst, bool expect_success,
size_t length = 0;
OEMCryptoResult sts = OEMCrypto_ReportUsage(
session_id(), reinterpret_cast<const uint8_t*>(pst.c_str()), pst.length(),
pst_report(), &length);
if (expect_success) {
&pst_report_buffer_[0], &length);
if (expected_result == OEMCrypto_SUCCESS) {
ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts);
}
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
ASSERT_LE(sizeof(OEMCrypto_PST_Report), length);
pst_report_buffer_.resize(length);
ASSERT_EQ(wvcdm::Unpacked_PST_Report::report_size(pst.length()), length);
pst_report_buffer_.assign(length, 0xFF); // Fill with garbage values.
}
sts = OEMCrypto_ReportUsage(session_id(),
reinterpret_cast<const uint8_t*>(pst.c_str()),
pst.length(), pst_report(), &length);
if (!expect_success) {
ASSERT_NE(OEMCrypto_SUCCESS, sts);
pst.length(), &pst_report_buffer_[0], &length);
ASSERT_EQ(expected_result, sts);
if (expected_result != OEMCrypto_SUCCESS) {
return;
}
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
ASSERT_EQ(pst_report_buffer_.size(), length);
vector<uint8_t> computed_signature(SHA_DIGEST_LENGTH);
unsigned int sig_len = SHA_DIGEST_LENGTH;
HMAC(EVP_sha1(), &mac_key_client_[0], mac_key_client_.size(),
reinterpret_cast<uint8_t*>(pst_report()) + SHA_DIGEST_LENGTH,
length - SHA_DIGEST_LENGTH, &computed_signature[0], &sig_len);
EXPECT_EQ(0, memcmp(&computed_signature[0], pst_report()->signature,
&pst_report_buffer_[SHA_DIGEST_LENGTH], length - SHA_DIGEST_LENGTH,
&computed_signature[0], &sig_len);
EXPECT_EQ(0, memcmp(&computed_signature[0], pst_report().signature(),
SHA_DIGEST_LENGTH));
EXPECT_GE(kInactive, pst_report()->status);
EXPECT_GE(kHardwareSecureClock, pst_report()->clock_security_level);
EXPECT_EQ(pst.length(), pst_report()->pst_length);
EXPECT_EQ(0, memcmp(pst.c_str(), pst_report()->pst, pst.length()));
EXPECT_GE(kInactiveUnused, pst_report().status());
EXPECT_GE(kHardwareSecureClock, pst_report().clock_security_level());
EXPECT_EQ(pst.length(), pst_report().pst_length());
EXPECT_EQ(0, memcmp(pst.c_str(), pst_report().pst(), pst.length()));
// Also, we the session to be able to sign the release message with the
// correct mac keys from the usage table entry.
ASSERT_NO_FATAL_FAILURE(VerifyClientSignature());
}
OEMCrypto_PST_Report* Session::pst_report() {
return reinterpret_cast<OEMCrypto_PST_Report*>(&pst_report_buffer_[0]);
void Session::VerifyPST(const Test_PST_Report& expected) {
wvcdm::Unpacked_PST_Report computed = pst_report();
EXPECT_EQ(expected.status, computed.status());
char* pst_ptr = reinterpret_cast<char *>(computed.pst());
std::string computed_pst(pst_ptr, pst_ptr + computed.pst_length());
ASSERT_EQ(expected.pst, computed_pst);
EXPECT_NEAR(expected.seconds_since_license_received,
computed.seconds_since_license_received(),
kTimeTolerance);
// Decrypt times only valid on licenses that have been active.
if (expected.status == kActive || expected.status == kInactiveUsed) {
EXPECT_NEAR(expected.seconds_since_first_decrypt,
computed.seconds_since_first_decrypt(),
kUsageTableTimeTolerance);
EXPECT_NEAR(expected.seconds_since_last_decrypt,
computed.seconds_since_last_decrypt(),
kUsageTableTimeTolerance);
}
std::vector<uint8_t> signature(SHA_DIGEST_LENGTH);
unsigned int md_len = SHA_DIGEST_LENGTH;
if (!HMAC(EVP_sha1(), &mac_key_client_[0], mac_key_client_.size(),
&pst_report_buffer_[0] + SHA_DIGEST_LENGTH,
pst_report_buffer_.size() - SHA_DIGEST_LENGTH,
&signature[0], &md_len)) {
cout << "Error computing HMAC.\n";
dump_openssl_error();
}
EXPECT_EQ(0, memcmp(computed.signature(), &signature[0],
SHA_DIGEST_LENGTH));
}
void Session::DeleteEntry(const std::string& pst) {
uint8_t* pst_ptr = encrypted_license().pst;
memcpy(pst_ptr, pst.c_str(), min(sizeof(license_.pst), pst.length()));
ServerSignBuffer(reinterpret_cast<const uint8_t*>(&padded_message_),
message_size_, &signature_);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeleteUsageEntry(session_id(), pst_ptr, pst.length(),
message_ptr(), message_size_,
&signature_[0], signature_.size()));
// This might adjust t to be "seconds since now". If t is small, we assume it
// is "seconds since now", but if the value of t is large, assume it is
// "absolute time" and convert to "seconds since now".
static int64_t MaybeAdjustTime(int64_t t, time_t now) {
int64_t k10Minutes = 60 * 10; // in seconds.
if (t > k10Minutes) return now - t;
return t;
}
void Session::ForceDeleteEntry(const std::string& pst) {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_ForceDeleteUsageEntry(
reinterpret_cast<const uint8_t*>(pst.c_str()), pst.length()));
void Session::GenerateVerifyReport(const std::string& pst,
OEMCrypto_Usage_Entry_Status status,
int64_t time_license_received,
int64_t time_first_decrypt,
int64_t time_last_decrypt) {
ASSERT_NO_FATAL_FAILURE(GenerateReport(pst));
Test_PST_Report expected(pst, status);
time_t now = time(NULL);
expected.seconds_since_license_received =
MaybeAdjustTime(time_license_received, now);
expected.seconds_since_first_decrypt =
MaybeAdjustTime(time_first_decrypt, now);
expected.seconds_since_last_decrypt = MaybeAdjustTime(time_last_decrypt, now);
ASSERT_NO_FATAL_FAILURE(VerifyPST(expected));
}
void Session::CreateOldEntry(const Test_PST_Report& report) {
OEMCryptoResult result = OEMCrypto_CreateOldUsageEntry(
report.seconds_since_license_received,
report.seconds_since_first_decrypt,
report.seconds_since_last_decrypt,
report.status, &mac_key_server_[0],
&mac_key_client_[0],
reinterpret_cast<const uint8_t*>(report.pst.c_str()),
report.pst.length());
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) return;
ASSERT_EQ(OEMCrypto_SUCCESS, result);
}
void Session::CopyAndVerifyOldEntry(const Test_PST_Report& report,
std::vector<uint8_t>* header_buffer) {
ASSERT_NO_FATAL_FAILURE(CreateNewUsageEntry());
OEMCryptoResult result = OEMCrypto_CopyOldUsageEntry(
session_id(), reinterpret_cast<const uint8_t*>(report.pst.c_str()),
report.pst.length());
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
cout << "WARNING: OEMCrypto CANNOT copy old usage table to new." << endl;
return;
}
ASSERT_NO_FATAL_FAILURE(UpdateUsageEntry(header_buffer));
ASSERT_NO_FATAL_FAILURE(GenerateReport(report.pst));
ASSERT_NO_FATAL_FAILURE(VerifyPST(report));
}
const uint8_t* Session::message_ptr() {