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:
Alex Dale
2021-02-18 19:53:12 -08:00
parent e4ee4eb404
commit f6f5099604
11 changed files with 187 additions and 458 deletions

View File

@@ -187,7 +187,6 @@ bool AuthenticationRoot::Initialize(OEMCrypto_ProvisioningMethod method) {
// If provisioning method is something other than ProvisioningError
// indicates it has already been initialized before. Must
// existing data.
rsa_key_set_ = false;
rsa_key_.reset();
test_rsa_key_.reset();
keybox_.reset();
@@ -196,8 +195,11 @@ bool AuthenticationRoot::Initialize(OEMCrypto_ProvisioningMethod method) {
prov_method_ = method;
switch (method) {
case OEMCrypto_DrmCertificate: {
rsa_key_set_ = rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize);
if (!rsa_key_set_) {
std::unique_ptr<RsaPrivateKey> key =
RsaPrivateKey::Load(kPrivateKey, kPrivateKeySize);
if (key) {
rsa_key_ = std::move(key);
} else {
// This error message is OK in unit tests which use test certificate.
LOGE(
"FATAL ERROR: Platform uses a baked-in certificate instead of a "
@@ -222,7 +224,7 @@ bool AuthenticationRoot::Initialize(OEMCrypto_ProvisioningMethod method) {
bool AuthenticationRoot::IsValid() const {
switch (prov_method_) {
case OEMCrypto_DrmCertificate: {
return rsa_key_set_ && HasDeviceKey();
return HasDrmCertKey() && HasDeviceKey();
}
case OEMCrypto_Keybox: {
return HasDeviceKey();
@@ -324,17 +326,18 @@ OEMCryptoResult AuthenticationRoot::LoadTestRsaKey() {
LOGE("System does not support DRM certificates");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (test_rsa_key_.get() != nullptr) {
if (test_rsa_key_) {
LOGE("Test RSA key is already loaded");
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
if (!test_rsa_key_.LoadPkcs8RsaKey(
kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048))) {
std::unique_ptr<RsaPrivateKey> key =
RsaPrivateKey::Load(kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
if (!key) {
LOGE("Failed to load test RSA key");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
rsa_key_set_ = true;
test_rsa_key_ = std::move(key);
return OEMCrypto_SUCCESS;
}

View File

@@ -8,17 +8,14 @@
#define OEMCRYPTO_AUTH_REF_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include <openssl/rsa.h>
#include "OEMCryptoCENC.h" // Needed for enums only.
#include "disallow_copy_and_assign.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_keybox_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "oemcrypto_types.h"
#include "oemcrypto_rsa_key.h"
namespace wvoec_ref {
// The AuthenticationRoot class contains the OEMCrypto information
@@ -69,13 +66,13 @@ class AuthenticationRoot {
// Returns the shared RSA private key from the built-in DRM
// Certificate.
RSA_shared_ptr& SharedRsaKey() {
return test_rsa_key_.get() != nullptr ? test_rsa_key_ : rsa_key_;
std::shared_ptr<RsaPrivateKey> ShareDrmCertKey() {
return test_rsa_key_ ? test_rsa_key_ : rsa_key_;
}
RSA* rsa_key() {
return test_rsa_key_.get() != nullptr ? test_rsa_key_.get()
: rsa_key_.get();
RsaPrivateKey* DrmCertKey() const {
return test_rsa_key_ ? test_rsa_key_.get() : rsa_key_.get();
}
bool HasDrmCertKey() const { return test_rsa_key_ || rsa_key_; }
// Loads the system's built-in RSA key. Only implemented for
// devices that are that pre-provisioned with a built-in DRM
@@ -144,11 +141,10 @@ class AuthenticationRoot {
OEMCrypto_ProvisioningMethod prov_method_ = OEMCrypto_ProvisioningError;
// DRM certificate.
// TODO(b/168544740): Remove |rsa_key_set_| when RSA_shared_ptr has
// been replaced with scoped RsaPrivateKey.
bool rsa_key_set_ = false;
RSA_shared_ptr rsa_key_; // If no keybox, this is baked in certificate.
RSA_shared_ptr test_rsa_key_;
// If no keybox, this is the private key of the baked-in DRM
// Certificate.
std::shared_ptr<RsaPrivateKey> rsa_key_;
std::shared_ptr<RsaPrivateKey> test_rsa_key_;
// Keybox data.
std::unique_ptr<WvKeybox> keybox_;

View File

@@ -65,7 +65,7 @@ class Prov30CryptoEngine : public CryptoEngine {
return OEMCrypto_ERROR_SHORT_BUFFER;
}
memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize);
if (!session->LoadRSAKey(kOEMPrivateKey, kOEMPrivateKeySize)) {
if (!session->LoadRsaDrmKey(kOEMPrivateKey, kOEMPrivateKeySize)) {
LOGE("Private RSA Key did not load correctly.");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}

View File

@@ -20,7 +20,6 @@
#include "keys.h"
#include "log.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "string_conversions.h"
namespace {
@@ -81,7 +80,10 @@ SessionId CryptoEngine::OpenSession() {
}
SessionContext* CryptoEngine::MakeSession(SessionId sid) {
return new SessionContext(this, sid, root_of_trust_.SharedRsaKey());
if (root_of_trust_.HasDrmCertKey()) {
return new SessionContext(this, sid, root_of_trust_.ShareDrmCertKey());
}
return new SessionContext(this, sid);
}
UsageTable* CryptoEngine::MakeUsageTable() { return new UsageTable(this); }

View File

@@ -8,19 +8,16 @@
#define REF_OEMCRYPTO_ENGINE_REF_H_
#include <stdint.h>
#include <time.h>
#include <map>
#include <memory>
#include <mutex>
#include <vector>
#include <openssl/rsa.h>
#include "OEMCryptoCENC.h"
#include "file_store.h"
#include "oemcrypto_auth_ref.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "oemcrypto_session.h"
#include "oemcrypto_types.h"
#include "oemcrypto_usage_table_ref.h"

View File

@@ -172,11 +172,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
enc_key_context, enc_key_context + enc_key_context_length);
// Generate mac and encryption keys for current session context
if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), mac_ctx_str,
enc_ctx_str)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
return session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), mac_ctx_str,
enc_ctx_str);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session,
@@ -893,8 +890,10 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
return OEMCrypto_ERROR_INVALID_NONCE;
}
if (!session_ctx->InstallRSAEncryptedKey(encrypted_message_key,
encrypted_message_key_length)) {
const std::vector<uint8_t> enc_encryption_key(
encrypted_message_key,
encrypted_message_key + encrypted_message_key_length);
if (!session_ctx->InstallRSAEncryptedKey(enc_encryption_key)) {
LOGE(
"OEMCrypto_RewrapDeviceRSAKey30: "
"Error loading encrypted_message_key.");
@@ -904,11 +903,11 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
// Decrypt RSA key.
std::vector<uint8_t> pkcs8_rsa_key(enc_rsa_key_length);
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
enc_rsa_key_iv, &pkcs8_rsa_key[0])) {
enc_rsa_key_iv, pkcs8_rsa_key.data())) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) {
LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Failed to LoadRSAKey.");
if (!session_ctx->LoadRsaDrmKey(pkcs8_rsa_key.data(), enc_rsa_key_length)) {
LOGE("Failed to load RSA DRM key");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
@@ -926,23 +925,24 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30(
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->DeviceRootKey(), context,
context)) {
const OEMCryptoResult derive_key_result =
session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, context);
if (derive_key_result != OEMCrypto_SUCCESS) {
LOGE("[_RewrapDeviceRSAKey30(): DeriveKeys failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
return derive_key_result;
}
// Encrypt rsa key with keybox.
if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length,
if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key.data(), enc_rsa_key_length,
wrapped->iv, wrapped->enc_rsa_key)) {
LOGE("[_RewrapDeviceRSAKey30(): EncrypteRSAKey failed.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
// The wrapped keybox must be signed with the same key we verify with. I'll
// pick the server key, so I don't have to modify LoadRSAKey.
// The wrapped keybox must be signed with the same key we verify with.
// Reference implementation uses the server key.
unsigned int sig_length = sizeof(wrapped->signature);
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
if (!HMAC(EVP_sha256(), session_ctx->mac_key_server().data(),
session_ctx->mac_key_server().size(), wrapped->context,
buffer_size - sizeof(wrapped->signature), wrapped->signature,
&sig_length)) {
@@ -1006,10 +1006,10 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
// Decrypt RSA key and verify it.
std::vector<uint8_t> pkcs8_rsa_key(enc_rsa_key_length);
if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length,
enc_rsa_key_iv, &pkcs8_rsa_key[0])) {
enc_rsa_key_iv, pkcs8_rsa_key.data())) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) {
if (!session_ctx->LoadRsaDrmKey(pkcs8_rsa_key.data(), enc_rsa_key_length)) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
@@ -1025,21 +1025,22 @@ static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(
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->DeviceRootKey(), context,
context)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const OEMCryptoResult derive_key_result =
session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, context);
if (derive_key_result != OEMCrypto_SUCCESS) {
return derive_key_result;
}
// Encrypt rsa key with keybox.
if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length,
if (!session_ctx->EncryptRSAKey(pkcs8_rsa_key.data(), enc_rsa_key_length,
wrapped->iv, wrapped->enc_rsa_key)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey);
// The wrapped keybox must be signed with the same key we verify with. I'll
// pick the server key, so I don't have to modify LoadRSAKey.
// The wrapped keybox must be signed with the same key we verify with.
// Reference implementation uses the server key.
unsigned int sig_length = sizeof(wrapped->signature);
if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0],
if (!HMAC(EVP_sha256(), session_ctx->mac_key_server().data(),
session_ctx->mac_key_server().size(), wrapped->context,
buffer_size - sizeof(wrapped->signature), wrapped->signature,
&sig_length)) {
@@ -1173,9 +1174,10 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDRMPrivateKey(
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->DeviceRootKey(), context,
context)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const OEMCryptoResult derive_key_result =
session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, context);
if (derive_key_result != OEMCrypto_SUCCESS) {
return derive_key_result;
}
// verify signature.
if (!session_ctx->ValidateMessage(
@@ -1189,7 +1191,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDRMPrivateKey(
sizeof(wrapped->signature));
size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey);
if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length,
wrapped->iv, &pkcs8_rsa_key[0])) {
wrapped->iv, pkcs8_rsa_key.data())) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1];
@@ -1198,7 +1200,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDRMPrivateKey(
padding = 0;
}
size_t rsa_key_length = enc_rsa_key_length - padding;
if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) {
if (!session_ctx->LoadRsaDrmKey(pkcs8_rsa_key.data(), rsa_key_length)) {
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
return OEMCrypto_SUCCESS;
@@ -1231,22 +1233,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature(
LOGE("[OEMCrypto_GenerateRSASignature(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
size_t required_size = session_ctx->RSASignatureSize();
if (*signature_length < required_size) {
*signature_length = required_size;
return OEMCrypto_ERROR_SHORT_BUFFER;
}
if (message == nullptr || message_length == 0 || signature == nullptr ||
signature_length == 0) {
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
OEMCryptoResult sts = session_ctx->GenerateRSASignature(
message, message_length, signature, signature_length, padding_scheme);
return sts;
return session_ctx->GenerateRSASignature(message, message_length, signature,
signature_length, padding_scheme);
}
OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
@@ -1259,27 +1247,22 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if (!crypto_engine->ValidRootOfTrust()) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]");
LOGE("[OEMCrypto_DeriveKeysFromSessionKey(): ERROR_KEYBOX_INVALID]");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
if (mac_key_context_length > kMaxContextKeyLength ||
enc_key_context_length > kMaxContextKeyLength ||
enc_session_key_length > kMaxContextKeyLength) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_BUFFER_TOO_LARGE]");
LOGE("[OEMCrypto_DeriveKeysFromSessionKey(): ERROR_BUFFER_TOO_LARGE]");
return OEMCrypto_ERROR_BUFFER_TOO_LARGE;
}
SessionContext* session_ctx = crypto_engine->FindSession(session);
if (session_ctx == nullptr || !session_ctx->isValid()) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_INVALID_SESSION]");
LOGE("[OEMCrypto_DeriveKeysFromSessionKey(): ERROR_INVALID_SESSION]");
return OEMCrypto_ERROR_INVALID_SESSION;
}
if (session_ctx->allowed_schemes() != kSign_RSASSA_PSS) {
LOGE("[OEMCrypto_GenerateDerivedKeys(): x509 key used to derive keys]");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
const std::vector<uint8_t> ssn_key_str(
enc_session_key, enc_session_key + enc_session_key_length);
const std::vector<uint8_t> mac_ctx_str(
@@ -1288,10 +1271,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
enc_key_context, enc_key_context + enc_key_context_length);
// Generate mac and encryption keys for current session context
if (!session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str)) {
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
return OEMCrypto_SUCCESS;
return session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str);
}
OEMCRYPTO_API uint32_t OEMCrypto_APIVersion() {

View File

@@ -993,7 +993,6 @@ bool RsaPrivateKey::InitFromBuffer(const uint8_t* buffer, size_t length) {
}
// Step 3: Verify field width.
const int bits = RSA_bits(key.get());
LOGD("Loaded RSA private key size: bits = %d", bits);
field_size_ = RealBitSizeToFieldSize(bits);
if (field_size_ == kRsaFieldUnknown) {
LOGE("Unsupported RSA key size: bits = %d", bits);

View File

@@ -1,101 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#include "oemcrypto_rsa_key_shared.h"
#include <assert.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
#include "log.h"
namespace wvoec_ref {
void dump_boringssl_error() {
int count = 0;
while (unsigned long err = ERR_get_error()) {
count++;
char buffer[120];
ERR_error_string_n(err, buffer, sizeof(buffer));
LOGE("BoringSSL Error %d -- %lu -- %s", count, err, buffer);
}
LOGE("Reported %d BoringSSL Errors", count);
}
void RSA_shared_ptr::reset() {
if (rsa_key_ && key_owned_) {
RSA_free(rsa_key_);
}
key_owned_ = false;
rsa_key_ = nullptr;
}
bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
assert(buffer != nullptr);
reset();
uint8_t* pkcs8_rsa_key = const_cast<uint8_t*>(buffer);
BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length);
if (bio == nullptr) {
LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]");
return false;
}
bool success = true;
PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr);
if (pkcs8_pki == nullptr) {
BIO_reset(bio);
pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr);
if (pkcs8_pki == nullptr) {
LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned nullptr]");
dump_boringssl_error();
success = false;
}
}
EVP_PKEY* evp = nullptr;
if (success) {
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == nullptr) {
LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned nullptr]");
dump_boringssl_error();
success = false;
}
}
if (success) {
rsa_key_ = EVP_PKEY_get1_RSA(evp);
if (rsa_key_ == nullptr) {
LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]");
success = false;
}
key_owned_ = true;
}
if (evp != nullptr) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != nullptr) {
PKCS8_PRIV_KEY_INFO_free(pkcs8_pki);
}
BIO_free(bio);
if (!success) {
return false;
}
switch (RSA_check_key(rsa_key_)) {
case 1: // valid.
return true;
case 0: // not valid.
LOGE("[LoadPkcs8RsaKey(): rsa key not valid]");
dump_boringssl_error();
return false;
default: // -1 == check failed.
LOGE("[LoadPkcs8RsaKey(): error checking rsa key]");
dump_boringssl_error();
return false;
}
}
} // namespace wvoec_ref

View File

@@ -1,42 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Reference implementation of OEMCrypto APIs
//
#ifndef OEMCRYPTO_RSA_KEY_SHARED_H_
#define OEMCRYPTO_RSA_KEY_SHARED_H_
#include <stdint.h>
#include <openssl/rsa.h>
namespace wvoec_ref {
// Shared pointer with specialized destructor. This pointer is only shared
// from a CryptoEngine to a Session -- so we don't have to use full reference
// counting.
class RSA_shared_ptr {
public:
RSA_shared_ptr() : rsa_key_(nullptr), key_owned_(false) {}
~RSA_shared_ptr() { reset(); };
// Explicitly allow copy as share.
explicit RSA_shared_ptr(const RSA_shared_ptr& other) :
rsa_key_(other.rsa_key_), key_owned_(false) {}
RSA* get() { return rsa_key_; }
void reset();
bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length);
private:
void operator=(const RSA_shared_ptr); // disallow assign.
RSA* rsa_key_;
bool key_owned_;
};
// Log errors from BoringSSL.
void dump_boringssl_error();
} // namespace wvoec_ref
#endif // OEMCRYPTO_RSA_KEY_SHARED_H_

View File

@@ -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;
}

View File

@@ -18,7 +18,7 @@
#include "odk_structs.h"
#include "oemcrypto_auth_ref.h"
#include "oemcrypto_key_ref.h"
#include "oemcrypto_rsa_key_shared.h"
#include "oemcrypto_rsa_key.h"
#include "oemcrypto_session_key_table.h"
#include "oemcrypto_types.h"
#include "oemcrypto_usage_table_ref.h"
@@ -59,21 +59,22 @@ class SessionContextKeys {
};
class SessionContext {
public:
SessionContext(CryptoEngine* ce, SessionId sid);
SessionContext(CryptoEngine* ce, SessionId sid,
const RSA_shared_ptr& rsa_key);
std::shared_ptr<RsaPrivateKey>&& rsa_key);
SessionContext() = delete;
virtual ~SessionContext();
bool isValid() { return valid_; }
bool isValid() const { return valid_; }
virtual bool DeriveKeys(const std::vector<uint8_t>& master_key,
const std::vector<uint8_t>& mac_context,
const std::vector<uint8_t>& enc_context);
virtual bool RSADeriveKeys(const std::vector<uint8_t>& enc_session_key,
const std::vector<uint8_t>& mac_context,
const std::vector<uint8_t>& enc_context);
virtual OEMCryptoResult DeriveKeys(const std::vector<uint8_t>& master_key,
const std::vector<uint8_t>& mac_context,
const std::vector<uint8_t>& enc_context);
virtual OEMCryptoResult RSADeriveKeys(
const std::vector<uint8_t>& enc_session_key,
const std::vector<uint8_t>& mac_context,
const std::vector<uint8_t>& enc_context);
virtual OEMCryptoResult PrepAndSignLicenseRequest(uint8_t* message,
size_t message_length,
size_t* core_message_length,
@@ -87,9 +88,7 @@ class SessionContext {
virtual OEMCryptoResult PrepAndSignProvisioningRequest(
uint8_t* message, size_t message_length, size_t* core_message_length,
uint8_t* signature, size_t* signature_length);
// The size of an RSA signature. This is used when signing as a CAST
// receiver.
size_t RSASignatureSize();
// Restricted to CAST receivers using PKCS1 block padding only.
virtual OEMCryptoResult GenerateRSASignature(
const uint8_t* message, size_t message_length, uint8_t* signature,
size_t* signature_length, RSA_Padding_Scheme padding_scheme);
@@ -141,13 +140,12 @@ class SessionContext {
const std::vector<uint8_t>& key_data_iv,
const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv);
bool InstallRSAEncryptedKey(const uint8_t* encrypted_message_key,
size_t encrypted_message_key_length);
bool InstallRSAEncryptedKey(const std::vector<uint8_t>& enc_encryption_key);
bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length,
const uint8_t* wrapped_rsa_key_iv, uint8_t* pkcs8_rsa_key);
bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length,
const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key);
bool LoadRSAKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length);
bool LoadRsaDrmKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length);
virtual OEMCryptoResult LoadRenewal(const uint8_t* message,
size_t message_length,
size_t core_message_length,
@@ -179,7 +177,6 @@ class SessionContext {
encryption_key_ = enc_key;
}
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
uint32_t allowed_schemes() const { return allowed_schemes_; }
// Return true if nonce was set.
bool set_nonce(uint32_t nonce);
@@ -205,9 +202,9 @@ class SessionContext {
protected:
// Signature size of the currently loaded private key.
size_t CertSignatureSize();
size_t CertSignatureSize() const;
// Signature size when using a keybox or OEM Cert's private key.
size_t ROTSignatureSize();
size_t ROTSignatureSize() const;
virtual OEMCryptoResult GenerateCertSignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
@@ -257,46 +254,52 @@ class SessionContext {
// entry, it also checks the usage entry.
OEMCryptoResult CheckKeyUse(const std::string& log_string, uint32_t use_type,
OEMCryptoBufferType buffer_type);
RSA* rsa_key() { return rsa_key_.get(); }
bool valid_;
CryptoEngine* ce_;
bool valid_ = false;
CryptoEngine* ce_ = nullptr;
SessionId id_;
// Message keys.
std::shared_ptr<RsaPrivateKey> rsa_key_;
std::vector<uint8_t> mac_key_server_;
std::vector<uint8_t> mac_key_client_;
std::vector<uint8_t> encryption_key_;
std::vector<uint8_t> session_key_;
const Key* current_content_key_;
std::unique_ptr<SessionContextKeys> session_keys_;
ODK_NonceValues nonce_values_;
uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE];
RSA_shared_ptr rsa_key_;
uint32_t allowed_schemes_; // for RSA signatures.
bool decrypt_started_; // If the license has been used in this session.
// Content/entitlement keys.
const Key* current_content_key_ = nullptr;
std::unique_ptr<SessionContextKeys> session_keys_;
bool decrypt_started_ =
false; // If the license has been used in this session.
ODK_TimerLimits timer_limits_;
ODK_ClockValues clock_values_;
std::unique_ptr<UsageTableEntry> usage_entry_;
SRMVersionStatus srm_requirements_status_;
SRMVersionStatus srm_requirements_status_ = NoSRMVersion;
enum UsageEntryStatus {
kNoUsageEntry, // No entry loaded for this session.
kUsageEntryNew, // After entry was created.
kUsageEntryLoaded, // After loading entry or loading keys.
};
UsageEntryStatus usage_entry_status_;
UsageEntryStatus usage_entry_status_ = kNoUsageEntry;
// These are used when doing full decrypt path testing.
bool compute_hash_; // True if the current frame needs a hash.
uint32_t current_hash_; // Running CRC hash of frame.
uint32_t given_hash_; // True CRC hash of frame.
uint32_t current_frame_number_; // Current frame for CRC hash.
uint32_t bad_frame_number_; // Frame number with bad hash.
OEMCryptoResult hash_error_; // Error code for first bad frame.
bool compute_hash_ = false; // True if the current frame needs a hash.
uint32_t current_hash_ = 0; // Running CRC hash of frame.
uint32_t given_hash_ = 0; // True CRC hash of frame.
uint32_t current_frame_number_ = 0; // Current frame for CRC hash.
uint32_t bad_frame_number_ = 0; // Frame number with bad hash.
OEMCryptoResult hash_error_ =
OEMCrypto_SUCCESS; // Error code for first bad frame.
// The bare minimum state machine is to only call each of these function
// categories at most once.
bool state_nonce_created_;
bool state_request_signed_;
bool state_response_loaded_;
bool state_nonce_created_ = false;
bool state_request_signed_ = false;
bool state_response_loaded_ = false;
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
};