Source release v3.5.0
This commit is contained in:
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user