Restructed reference root of trust (2/3 DRM Cert)
[ Merge of http://go/wvgerrit/115551 ] This change is the second part of a three part change for restructing the root of trust used by the reference implementation. The use of RSA_shared_ptr has been replaced with the standard library std::shared_ptr using the RsaPrivateKey wrapper class. The AuthenticationRoot class now uses this for the built-in DRM cert key. RSA decryption and signature operations within the session context are now performed the RsaPrivateKey class. This has reduced the code size and complexity within the reference and testbed, focusing their implementation on key policy and less on mechanics. Bug: 168544740 Bug: 135283522 Test: oemcrypto_unittests ce_cdm_tests Change-Id: Ic743a529a9858f3182290d8bcf5e1633737b005b
This commit is contained in:
@@ -25,20 +25,17 @@
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include "advance_iv_ctr.h"
|
||||
#include "disallow_copy_and_assign.h"
|
||||
#include "keys.h"
|
||||
#include "log.h"
|
||||
#include "odk.h"
|
||||
#include "oemcrypto_engine_ref.h"
|
||||
#include "oemcrypto_key_ref.h"
|
||||
#include "oemcrypto_rsa_key_shared.h"
|
||||
#include "oemcrypto_types.h"
|
||||
#include "platform.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wvcrc32.h"
|
||||
|
||||
static const int kPssSaltLength = 20;
|
||||
|
||||
namespace wvoec_ref {
|
||||
namespace {
|
||||
|
||||
// Increment counter for AES-CTR. The CENC spec specifies we increment only
|
||||
@@ -66,11 +63,8 @@ void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvoec_ref {
|
||||
|
||||
/***************************************/
|
||||
|
||||
class ContentKeysContext : public SessionContextKeys {
|
||||
@@ -181,31 +175,17 @@ EntitlementKey* EntitlementKeysContext::GetEntitlementKey(
|
||||
|
||||
/***************************************/
|
||||
|
||||
SessionContext::SessionContext(CryptoEngine* ce, SessionId sid,
|
||||
const RSA_shared_ptr& rsa_key)
|
||||
: valid_(true),
|
||||
ce_(ce),
|
||||
id_(sid),
|
||||
current_content_key_(nullptr),
|
||||
session_keys_(nullptr),
|
||||
license_request_hash_(),
|
||||
rsa_key_(rsa_key),
|
||||
allowed_schemes_(kSign_RSASSA_PSS),
|
||||
decrypt_started_(false),
|
||||
timer_limits_(),
|
||||
clock_values_(),
|
||||
usage_entry_(nullptr),
|
||||
srm_requirements_status_(NoSRMVersion),
|
||||
usage_entry_status_(kNoUsageEntry),
|
||||
compute_hash_(false),
|
||||
current_hash_(0),
|
||||
bad_frame_number_(0),
|
||||
hash_error_(OEMCrypto_SUCCESS),
|
||||
state_nonce_created_(false),
|
||||
state_request_signed_(false),
|
||||
state_response_loaded_(false) {
|
||||
SessionContext::SessionContext(CryptoEngine* ce, SessionId sid)
|
||||
: valid_(ce != nullptr), ce_(ce), id_(sid) {
|
||||
ODK_InitializeSessionValues(&timer_limits_, &clock_values_, &nonce_values_,
|
||||
CryptoEngine::kApiVersion, sid);
|
||||
memset(license_request_hash_, 0, sizeof(license_request_hash_));
|
||||
}
|
||||
|
||||
SessionContext::SessionContext(CryptoEngine* ce, SessionId sid,
|
||||
std::shared_ptr<RsaPrivateKey>&& rsa_key)
|
||||
: SessionContext(ce, sid) {
|
||||
rsa_key_ = std::move(rsa_key);
|
||||
}
|
||||
|
||||
SessionContext::~SessionContext() {}
|
||||
@@ -258,27 +238,28 @@ bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::DeriveKeys(const std::vector<uint8_t>& master_key,
|
||||
const std::vector<uint8_t>& mac_key_context,
|
||||
const std::vector<uint8_t>& enc_key_context) {
|
||||
OEMCryptoResult SessionContext::DeriveKeys(
|
||||
const std::vector<uint8_t>& master_key,
|
||||
const std::vector<uint8_t>& mac_key_context,
|
||||
const std::vector<uint8_t>& enc_key_context) {
|
||||
// Generate derived key for mac key
|
||||
std::vector<uint8_t> mac_key_server;
|
||||
std::vector<uint8_t> mac_key_client;
|
||||
std::vector<uint8_t> mac_key_part2;
|
||||
if (!DeriveKey(master_key, mac_key_context, 1, &mac_key_server)) {
|
||||
return false;
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (!DeriveKey(master_key, mac_key_context, 2, &mac_key_part2)) {
|
||||
return false;
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
mac_key_server.insert(mac_key_server.end(), mac_key_part2.begin(),
|
||||
mac_key_part2.end());
|
||||
|
||||
if (!DeriveKey(master_key, mac_key_context, 3, &mac_key_client)) {
|
||||
return false;
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (!DeriveKey(master_key, mac_key_context, 4, &mac_key_part2)) {
|
||||
return false;
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
mac_key_client.insert(mac_key_client.end(), mac_key_part2.begin(),
|
||||
mac_key_part2.end());
|
||||
@@ -286,48 +267,31 @@ bool SessionContext::DeriveKeys(const std::vector<uint8_t>& master_key,
|
||||
// Generate derived key for encryption key
|
||||
std::vector<uint8_t> enc_key;
|
||||
if (!DeriveKey(master_key, enc_key_context, 1, &enc_key)) {
|
||||
return false;
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
set_mac_key_server(mac_key_server);
|
||||
set_mac_key_client(mac_key_client);
|
||||
set_encryption_key(enc_key);
|
||||
return true;
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
bool SessionContext::RSADeriveKeys(
|
||||
OEMCryptoResult SessionContext::RSADeriveKeys(
|
||||
const std::vector<uint8_t>& enc_session_key,
|
||||
const std::vector<uint8_t>& mac_key_context,
|
||||
const std::vector<uint8_t>& enc_key_context) {
|
||||
if (!rsa_key()) {
|
||||
LOGE("[RSADeriveKeys(): no RSA key set]");
|
||||
return false;
|
||||
if (!rsa_key_) {
|
||||
LOGE("No RSA key set");
|
||||
return OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED;
|
||||
}
|
||||
const size_t actual_key_size = static_cast<size_t>(RSA_size(rsa_key()));
|
||||
if (enc_session_key.size() != actual_key_size) {
|
||||
LOGE(
|
||||
"[RSADeriveKeys(): encrypted session key wrong size: %zu, expected "
|
||||
"%zu]",
|
||||
enc_session_key.size(), actual_key_size);
|
||||
dump_boringssl_error();
|
||||
return false;
|
||||
if (!(rsa_key_->allowed_schemes() & kSign_RSASSA_PSS)) {
|
||||
LOGE("Key cannot be used for session key decryption");
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
session_key_.resize(RSA_size(rsa_key()));
|
||||
const int decrypted_size =
|
||||
RSA_private_decrypt(enc_session_key.size(), &enc_session_key[0],
|
||||
&session_key_[0], rsa_key(), RSA_PKCS1_OAEP_PADDING);
|
||||
if (-1 == decrypted_size) {
|
||||
LOGE("[RSADeriveKeys(): error decrypting session key.]");
|
||||
dump_boringssl_error();
|
||||
return false;
|
||||
}
|
||||
session_key_.resize(decrypted_size);
|
||||
if (decrypted_size != static_cast<int>(wvoec::KEY_SIZE)) {
|
||||
LOGE("[RSADeriveKeys(): error. Session key is wrong size: %d.]",
|
||||
decrypted_size);
|
||||
dump_boringssl_error();
|
||||
session_key_.clear();
|
||||
return false;
|
||||
session_key_ = rsa_key_->DecryptSessionKey(enc_session_key);
|
||||
if (session_key_.empty()) {
|
||||
LOGE("Failed decrypt session key");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return DeriveKeys(session_key_, mac_key_context, enc_key_context);
|
||||
}
|
||||
@@ -336,8 +300,13 @@ OEMCryptoResult SessionContext::PrepAndSignLicenseRequest(
|
||||
uint8_t* message, size_t message_length, size_t* core_message_length,
|
||||
uint8_t* signature, size_t* signature_length) {
|
||||
if (signature_length == nullptr || core_message_length == nullptr) {
|
||||
LOGE("Output length parameters are null");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (!rsa_key_) {
|
||||
LOGE("No DRM key available for signature");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
const size_t required_signature_size = CertSignatureSize();
|
||||
OEMCryptoResult result = ODK_PrepareCoreLicenseRequest(
|
||||
message, message_length, core_message_length, &nonce_values_);
|
||||
@@ -424,6 +393,10 @@ OEMCryptoResult SessionContext::PrepAndSignProvisioningRequest(
|
||||
if (signature_length == nullptr || core_message_length == nullptr) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (!rsa_key_ && mac_key_client_.empty()) {
|
||||
LOGE("Session cannot sign request");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
if (state_request_signed_) {
|
||||
LOGE("Attempt to sign prov request after license request");
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
@@ -488,29 +461,20 @@ OEMCryptoResult SessionContext::GenerateSignature(const uint8_t* message,
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
// This is ussd when the device is a cast receiver.
|
||||
size_t SessionContext::RSASignatureSize() {
|
||||
if (!rsa_key()) {
|
||||
LOGE("no RSA key set");
|
||||
size_t SessionContext::CertSignatureSize() const {
|
||||
if (!rsa_key_) {
|
||||
LOGE("No RSA key set");
|
||||
return 0;
|
||||
}
|
||||
return static_cast<size_t>(RSA_size(rsa_key()));
|
||||
return rsa_key_->SignatureSize();
|
||||
}
|
||||
|
||||
size_t SessionContext::CertSignatureSize() {
|
||||
// TODO(b/67735947): Add ECC cert support.
|
||||
if (!rsa_key()) {
|
||||
LOGE("No private key set");
|
||||
return 0;
|
||||
}
|
||||
return static_cast<size_t>(RSA_size(rsa_key()));
|
||||
}
|
||||
|
||||
size_t SessionContext::ROTSignatureSize() {
|
||||
size_t SessionContext::ROTSignatureSize() const {
|
||||
if (ce_->config_provisioning_method() == OEMCrypto_Keybox)
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
if (ce_->config_provisioning_method() == OEMCrypto_OEMCertificate)
|
||||
if (ce_->config_provisioning_method() == OEMCrypto_OEMCertificate) {
|
||||
return CertSignatureSize();
|
||||
}
|
||||
LOGE("Bad prov method = %d",
|
||||
static_cast<int>(ce_->config_provisioning_method()));
|
||||
return 0;
|
||||
@@ -519,92 +483,27 @@ size_t SessionContext::ROTSignatureSize() {
|
||||
OEMCryptoResult SessionContext::GenerateCertSignature(
|
||||
const uint8_t* message, size_t message_length, uint8_t* signature,
|
||||
size_t* signature_length) {
|
||||
// TODO(b/67735947): Add ECC cert support.
|
||||
if (message == nullptr || message_length == 0 || signature == nullptr ||
|
||||
signature_length == 0) {
|
||||
LOGE("OEMCrypto_ERROR_INVALID_CONTEXT");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (!rsa_key()) {
|
||||
if (!rsa_key_) {
|
||||
LOGE("No RSA key set");
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
if (*signature_length < static_cast<size_t>(RSA_size(rsa_key()))) {
|
||||
*signature_length = CertSignatureSize();
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
if (allowed_schemes_ != kSign_RSASSA_PSS) {
|
||||
LOGE("Message signing not allowed");
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
|
||||
// Hash the message using SHA1.
|
||||
uint8_t hash[SHA_DIGEST_LENGTH];
|
||||
if (!SHA1(message, message_length, hash)) {
|
||||
LOGE("Error creating signature hash");
|
||||
dump_boringssl_error();
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
// Add PSS padding.
|
||||
std::vector<uint8_t> padded_digest(*signature_length);
|
||||
int status = RSA_padding_add_PKCS1_PSS_mgf1(
|
||||
rsa_key(), &padded_digest[0], hash, EVP_sha1(), nullptr, kPssSaltLength);
|
||||
if (status == -1) {
|
||||
LOGE("Error padding hash");
|
||||
dump_boringssl_error();
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
// Encrypt PSS padded digest.
|
||||
status = RSA_private_encrypt(*signature_length, &padded_digest[0], signature,
|
||||
rsa_key(), RSA_NO_PADDING);
|
||||
if (status == -1) {
|
||||
LOGE("Error in private encrypt");
|
||||
dump_boringssl_error();
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
return OEMCrypto_SUCCESS;
|
||||
return rsa_key_->GenerateSignature(message, message_length, kRsaPssDefault,
|
||||
signature, signature_length);
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::GenerateRSASignature(
|
||||
const uint8_t* message, size_t message_length, uint8_t* signature,
|
||||
size_t* signature_length, RSA_Padding_Scheme padding_scheme) {
|
||||
if (message == nullptr || message_length == 0 || signature == nullptr ||
|
||||
signature_length == 0) {
|
||||
LOGE("OEMCrypto_ERROR_INVALID_CONTEXT");
|
||||
if (padding_scheme != kSign_PKCS1_Block1) {
|
||||
LOGE("Only PKCS1 block1 padding scheme allowed");
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
if (!rsa_key()) {
|
||||
if (!rsa_key_) {
|
||||
LOGE("No RSA key set");
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
if (*signature_length < static_cast<size_t>(RSA_size(rsa_key()))) {
|
||||
*signature_length = RSA_size(rsa_key());
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
if (((padding_scheme & allowed_schemes_) != padding_scheme) ||
|
||||
(padding_scheme != kSign_PKCS1_Block1)) {
|
||||
LOGE("padding_scheme not allowed");
|
||||
return OEMCrypto_ERROR_INVALID_RSA_KEY;
|
||||
}
|
||||
// This is the maximum digest size possible for PKCS1 block type 1,
|
||||
// as used for a CAST receiver.
|
||||
const size_t max_digest_size = 83u;
|
||||
if (message_length > max_digest_size) {
|
||||
LOGE("RSA digest too large");
|
||||
return OEMCrypto_ERROR_SIGNATURE_FAILURE;
|
||||
}
|
||||
// Pad the message with PKCS1 padding, and then encrypt.
|
||||
const int status = RSA_private_encrypt(message_length, message, signature,
|
||||
rsa_key(), RSA_PKCS1_PADDING);
|
||||
if (status < 0) {
|
||||
LOGE("Error in RSA private encrypt. status = %d", status);
|
||||
dump_boringssl_error();
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
*signature_length = static_cast<size_t>(RSA_size(rsa_key()));
|
||||
return OEMCrypto_SUCCESS;
|
||||
return rsa_key_->GenerateSignature(message, message_length, kRsaPkcs1Cast,
|
||||
signature, signature_length);
|
||||
}
|
||||
|
||||
// Validate message signature
|
||||
@@ -1034,24 +933,19 @@ OEMCryptoResult SessionContext::InstallKey(
|
||||
}
|
||||
|
||||
bool SessionContext::InstallRSAEncryptedKey(
|
||||
const uint8_t* encrypted_message_key, size_t encrypted_message_key_length) {
|
||||
encryption_key_.resize(RSA_size(rsa_key()));
|
||||
const int decrypted_size = RSA_private_decrypt(
|
||||
encrypted_message_key_length, encrypted_message_key, &encryption_key_[0],
|
||||
rsa_key(), RSA_PKCS1_OAEP_PADDING);
|
||||
if (-1 == decrypted_size) {
|
||||
LOGE("[RSADeriveKeys(): error decrypting session key.]");
|
||||
dump_boringssl_error();
|
||||
const std::vector<uint8_t>& enc_encryption_key) {
|
||||
if (!rsa_key_) {
|
||||
LOGE("Session does not have an OEM cert key");
|
||||
return false;
|
||||
}
|
||||
encryption_key_.resize(decrypted_size);
|
||||
if (decrypted_size != static_cast<int>(wvoec::KEY_SIZE)) {
|
||||
LOGE("[RSADeriveKeys(): error. Session key is wrong size: %d.]",
|
||||
decrypted_size);
|
||||
dump_boringssl_error();
|
||||
encryption_key_.clear();
|
||||
|
||||
std::vector<uint8_t> encryption_key =
|
||||
rsa_key_->DecryptEncryptionKey(enc_encryption_key);
|
||||
if (encryption_key.empty()) {
|
||||
LOGE("Failed to decrypt session encryption key");
|
||||
return false;
|
||||
}
|
||||
encryption_key_ = std::move(encryption_key);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1162,23 +1056,23 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionContext::LoadRSAKey(const uint8_t* pkcs8_rsa_key,
|
||||
size_t rsa_key_length) {
|
||||
rsa_key_.reset();
|
||||
if (rsa_key_length < 8) {
|
||||
LOGE("[LoadRSAKey(): Very Short Buffer]");
|
||||
bool SessionContext::LoadRsaDrmKey(const uint8_t* pkcs8_rsa_key,
|
||||
size_t rsa_key_length) {
|
||||
std::unique_ptr<RsaPrivateKey> key =
|
||||
RsaPrivateKey::Load(pkcs8_rsa_key, rsa_key_length);
|
||||
if (!key) {
|
||||
LOGE("Failed to parse RSA key");
|
||||
return false;
|
||||
}
|
||||
if ((memcmp(pkcs8_rsa_key, "SIGN", 4) == 0)) {
|
||||
uint32_t schemes_n;
|
||||
memcpy((uint8_t*)&schemes_n, pkcs8_rsa_key + 4, sizeof(uint32_t));
|
||||
allowed_schemes_ = htonl(schemes_n);
|
||||
pkcs8_rsa_key += 8;
|
||||
rsa_key_length -= 8;
|
||||
} else {
|
||||
allowed_schemes_ = kSign_RSASSA_PSS;
|
||||
constexpr uint8_t kAllSchemes = kSign_RSASSA_PSS | kSign_PKCS1_Block1;
|
||||
if (key->allowed_schemes() == 0 ||
|
||||
(key->allowed_schemes() & kAllSchemes) == kAllSchemes) {
|
||||
LOGE("RSA DRM key has an invalid set of schemes: allowed_schemes = 0x%08x",
|
||||
key->allowed_schemes());
|
||||
return false;
|
||||
}
|
||||
return rsa_key_.LoadPkcs8RsaKey(pkcs8_rsa_key, rsa_key_length);
|
||||
rsa_key_ = std::move(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string,
|
||||
@@ -1361,7 +1255,6 @@ OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer,
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
LOGE("[Generic_Sign(): hmac failed");
|
||||
dump_boringssl_error();
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
@@ -1402,7 +1295,6 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
|
||||
}
|
||||
}
|
||||
LOGE("[Generic_Verify(): HMAC failed");
|
||||
dump_boringssl_error();
|
||||
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user