Implement provisioning 3.0 functionality in oemcrypto mock

Merge from widevine repo of http://go/wvgerrit/21684

This CL adds provisioning 3.0 functionality to the OEMCrypto reference
implementation.

Change-Id: I60c1fd88f246d443e0ae59ad56862c2ea9d95445
This commit is contained in:
Fred Gylys-Colwell
2016-11-29 16:00:22 -08:00
parent 3e525dfdd3
commit 08ad98cad9
9 changed files with 673 additions and 248 deletions

View File

@@ -242,12 +242,71 @@ void SessionKeyTable::UpdateDuration(const KeyControlBlock& control) {
}
}
void RSA_shared_ptr::reset() {
if (rsa_key_ && key_owned_) {
RSA_free(rsa_key_);
}
key_owned_ = false;
rsa_key_ = NULL;
}
bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
assert(buffer != NULL);
reset();
key_owned_ = true;
uint8_t* pkcs8_rsa_key = const_cast<uint8_t*>(buffer);
BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length);
if (bio == NULL) {
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, NULL);
if (pkcs8_pki == NULL) {
LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL]");
success = false;
}
EVP_PKEY* evp = NULL;
if (success) {
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == NULL) {
LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned NULL]");
success = false;
}
}
if (success) {
rsa_key_ = EVP_PKEY_get1_RSA(evp);
if (rsa_key_ == NULL) {
LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]");
success = false;
}
}
if (evp != NULL) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != NULL) {
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_openssl_error();
return false;
default: // -1 == check failed.
LOGE("[LoadPkcs8RsaKey(): error checking rsa key]");
dump_openssl_error();
return false;
}
}
SessionContext::~SessionContext() {
if (usage_entry_) usage_entry_->set_session(NULL);
if (rsa_key_ && rsa_key_ != ce_->rsa_key()) {
RSA_free(rsa_key_);
rsa_key_ = NULL;
}
}
// Internal utility function to derive key using CMAC-128
@@ -339,20 +398,20 @@ bool SessionContext::DeriveKeys(const std::vector<uint8_t>& master_key,
bool 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_) {
if (!rsa_key()) {
LOGE("[RSADeriveKeys(): no RSA key set]");
return false;
}
if (enc_session_key.size() != static_cast<size_t>(RSA_size(rsa_key_))) {
if (enc_session_key.size() != static_cast<size_t>(RSA_size(rsa_key()))) {
LOGE("[RSADeriveKeys(): encrypted session key wrong size:%zu, expected %d]",
enc_session_key.size(), RSA_size(rsa_key_));
enc_session_key.size(), RSA_size(rsa_key()));
dump_openssl_error();
return false;
}
session_key_.resize(RSA_size(rsa_key_));
session_key_.resize(RSA_size(rsa_key()));
int decrypted_size = RSA_private_decrypt(enc_session_key.size(),
&enc_session_key[0],
&session_key_[0], rsa_key_,
&session_key_[0], rsa_key(),
RSA_PKCS1_OAEP_PADDING);
if (-1 == decrypted_size) {
LOGE("[RSADeriveKeys(): error decrypting session key.]");
@@ -402,11 +461,11 @@ bool SessionContext::GenerateSignature(const uint8_t* message,
}
size_t SessionContext::RSASignatureSize() {
if (!rsa_key_) {
if (!rsa_key()) {
LOGE("[GenerateRSASignature(): no RSA key set]");
return 0;
}
return static_cast<size_t>(RSA_size(rsa_key_));
return static_cast<size_t>(RSA_size(rsa_key()));
}
OEMCryptoResult SessionContext::GenerateRSASignature(
@@ -417,19 +476,18 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
LOGE("[GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (!rsa_key_) {
if (!rsa_key()) {
LOGE("[GenerateRSASignature(): 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_);
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) {
LOGE("[GenerateRSASignature(): padding_scheme not allowed]");
return OEMCrypto_ERROR_INVALID_RSA_KEY;
}
// This is the standard padding scheme used for license requests.
if (padding_scheme == kSign_RSASSA_PSS) {
// Hash the message using SHA1.
@@ -442,7 +500,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
// Add PSS padding.
std::vector<uint8_t> padded_digest(*signature_length);
int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa_key_, &padded_digest[0],
int status = RSA_padding_add_PKCS1_PSS_mgf1(rsa_key(), &padded_digest[0],
hash, EVP_sha1(), NULL,
kPssSaltLength);
if (status == -1) {
@@ -453,7 +511,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
// Encrypt PSS padded digest.
status = RSA_private_encrypt(*signature_length, &padded_digest[0], signature,
rsa_key_, RSA_NO_PADDING);
rsa_key(), RSA_NO_PADDING);
if (status == -1) {
LOGE("[GeneratRSASignature(): error in private encrypt.]");
dump_openssl_error();
@@ -467,7 +525,7 @@ OEMCryptoResult SessionContext::GenerateRSASignature(
}
// Pad the message with PKCS1 padding, and then encrypt.
size_t status = RSA_private_encrypt(message_length, message, signature,
rsa_key_, RSA_PKCS1_PADDING);
rsa_key(), RSA_PKCS1_PADDING);
if (status != *signature_length) {
LOGE("[GeneratRSASignature(): error in RSA private encrypt. status=%d]", status);
dump_openssl_error();
@@ -711,6 +769,29 @@ bool SessionContext::InstallKey(const KeyId& key_id,
return true;
}
bool SessionContext::InstallRSAEncryptedKey(const uint8_t *encrypted_message_key,
size_t encrypted_message_key_length) {
encryption_key_.resize(RSA_size(rsa_key()));
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_openssl_error();
return false;
}
encryption_key_.resize(decrypted_size);
if (decrypted_size != static_cast<int>(wvcdm::KEY_SIZE)) {
LOGE("[RSADeriveKeys(): error. session key is wrong size: %d.]",
decrypted_size);
dump_openssl_error();
encryption_key_.clear();
return false;
}
return true;
}
OEMCryptoResult SessionContext::RefreshKey(
const KeyId& key_id, const std::vector<uint8_t>& key_control,
const std::vector<uint8_t>& key_control_iv) {
@@ -790,7 +871,7 @@ bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key,
const uint8_t* enc_rsa_key_iv,
uint8_t* pkcs8_rsa_key) {
// Decrypt rsa key with keybox.
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_decrypt_key(&encryption_key_[0], 128, &aes_key);
@@ -804,7 +885,7 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
const uint8_t* enc_rsa_key_iv,
uint8_t* enc_rsa_key) {
// Encrypt rsa key with keybox.
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, enc_rsa_key_iv, wvcdm::KEY_IV_SIZE);
AES_KEY aes_key;
AES_set_encrypt_key(&encryption_key_[0], 128, &aes_key);
@@ -813,79 +894,22 @@ bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key,
return true;
}
bool SessionContext::LoadRSAKey(uint8_t* pkcs8_rsa_key,
size_t rsa_key_length,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length) {
// Validate message signature
if (!ValidateMessage(message, message_length, signature, signature_length)) {
LOGE("[LoadRSAKey(): Could not verify signature]");
return false;
}
if (rsa_key_) {
RSA_free(rsa_key_);
rsa_key_ = NULL;
}
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]");
return false;
}
if( (memcmp(pkcs8_rsa_key, "SIGN", 4) == 0) ) {
uint32_t *schemes_n = (uint32_t *)(pkcs8_rsa_key + 4);
if ((memcmp(pkcs8_rsa_key, "SIGN", 4) == 0)) {
uint32_t* schemes_n = (uint32_t*)(pkcs8_rsa_key + 4);
allowed_schemes_ = htonl(*schemes_n);
pkcs8_rsa_key += 8;
rsa_key_length -= 8;
} else {
allowed_schemes_ = kSign_RSASSA_PSS;
}
BIO *bio = BIO_new_mem_buf(pkcs8_rsa_key, rsa_key_length);
if ( bio == NULL ) {
LOGE("[LoadRSAKey(): Could not allocate bio buffer]");
return false;
}
bool success = true;
PKCS8_PRIV_KEY_INFO *pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL);
if (pkcs8_pki == NULL) {
LOGE("d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL.");
success = false;
}
EVP_PKEY *evp = NULL;
if (success) {
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == NULL) {
LOGE("EVP_PKCS82PKEY returned NULL.");
success = false;
}
}
if (success) {
rsa_key_ = EVP_PKEY_get1_RSA(evp);
if (rsa_key_ == NULL) {
LOGE("PrivateKeyInfo did not contain an RSA key.");
success = false;
}
}
if (evp != NULL) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != NULL) {
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("[LoadRSAKey(): rsa key not valid]");
dump_openssl_error();
return false;
default: // -1 == check failed.
LOGE("[LoadRSAKey(): error checking rsa key]");
dump_openssl_error();
return false;
}
return rsa_key_.LoadPkcs8RsaKey(pkcs8_rsa_key, rsa_key_length);
}
OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
@@ -921,11 +945,11 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if ( algorithm != OEMCrypto_AES_CBC_128_NO_PADDING ) {
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
LOGE("[Generic_Encrypt(): algorithm bad.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if ( buffer_length % AES_BLOCK_SIZE != 0 ) {
if (buffer_length % AES_BLOCK_SIZE != 0) {
LOGE("[Generic_Encrypt(): buffers size bad.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -935,7 +959,7 @@ OEMCryptoResult SessionContext::Generic_Encrypt(const uint8_t* in_buffer,
LOGE("[Generic_Encrypt(): FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE);
AES_cbc_encrypt(in_buffer, out_buffer, buffer_length,
&aes_key, iv_buffer, AES_ENCRYPT);
@@ -981,11 +1005,11 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if ( algorithm != OEMCrypto_AES_CBC_128_NO_PADDING ) {
if (algorithm != OEMCrypto_AES_CBC_128_NO_PADDING) {
LOGE("[Generic_Decrypt(): bad algorithm.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
if ( buffer_length % AES_BLOCK_SIZE != 0 ) {
if (buffer_length % AES_BLOCK_SIZE != 0) {
LOGE("[Generic_Decrypt(): bad buffer size.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -995,7 +1019,7 @@ OEMCryptoResult SessionContext::Generic_Decrypt(const uint8_t* in_buffer,
LOGE("[Generic_Decrypt(): FAILURE]");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
uint8_t iv_buffer[ wvcdm::KEY_IV_SIZE];
uint8_t iv_buffer[wvcdm::KEY_IV_SIZE];
memcpy(iv_buffer, iv, wvcdm::KEY_IV_SIZE);
AES_cbc_encrypt(in_buffer, out_buffer, buffer_length,
&aes_key, iv_buffer, AES_DECRYPT);
@@ -1039,7 +1063,7 @@ OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if( algorithm != OEMCrypto_HMAC_SHA256 ) {
if (algorithm != OEMCrypto_HMAC_SHA256) {
LOGE("[Generic_Sign(): bad algorithm.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -1089,7 +1113,7 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer,
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
}
if ( algorithm != OEMCrypto_HMAC_SHA256 ) {
if (algorithm != OEMCrypto_HMAC_SHA256) {
LOGE("[Generic_Verify(): bad algorithm.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
@@ -1190,21 +1214,20 @@ bool SessionContext::IsUsageEntryValid() {
void SessionContext::ReleaseUsageEntry() { usage_entry_ = NULL; }
CryptoEngine::CryptoEngine(wvcdm::FileSystem* file_system)
: current_session_(NULL),
use_test_keybox_(false),
: use_test_keybox_(false),
file_system_(file_system),
usage_table_(new UsageTable(this)),
rsa_key_(NULL) {
usage_table_(new UsageTable(this)) {
ERR_load_crypto_strings();
if (!supports_keybox() && !LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) {
if ((provisioning_method() == OEMCrypto_DrmCertificate) &&
!rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) {
// This error message is OK in unit tests which use test certificate.
LOGE("FATAL ERROR: Platform uses a baked-in certificate instead of a "
"keybox, but the certificate could not be loaded.");
}
}
CryptoEngine::~CryptoEngine() {
current_session_ = NULL;
sessions_.clear();
if (usage_table_) delete usage_table_;
}
@@ -1214,19 +1237,15 @@ void CryptoEngine::Terminate() {}
KeyboxError CryptoEngine::ValidateKeybox() { return keybox().Validate(); }
bool CryptoEngine::LoadTestRSAKey() {
if (rsa_key_) {
RSA_free(rsa_key_);
rsa_key_ = NULL;
}
return LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
return rsa_key_.LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
}
SessionId CryptoEngine::CreateSession() {
wvcdm::AutoLock lock(session_table_lock_);
static int unique_id = 1;
SessionId sid = (SessionId)++unique_id;
SessionContext* sctx = new SessionContext(this, sid, this->rsa_key_);
SessionContext* sctx = new SessionContext(this, sid, rsa_key_);
sessions_[sid] = sctx;
return sid;
}
@@ -1252,59 +1271,6 @@ SessionContext* CryptoEngine::FindSession(SessionId sid) {
return NULL;
}
bool CryptoEngine::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) {
assert(buffer != NULL);
uint8_t* pkcs8_rsa_key = const_cast<uint8_t*>(buffer);
BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length);
if (bio == NULL) {
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, NULL);
if (pkcs8_pki == NULL) {
LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL]");
success = false;
}
EVP_PKEY* evp = NULL;
if (success) {
evp = EVP_PKCS82PKEY(pkcs8_pki);
if (evp == NULL) {
LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned NULL]");
success = false;
}
}
if (success) {
rsa_key_ = EVP_PKEY_get1_RSA(evp);
if (rsa_key_ == NULL) {
LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]");
success = false;
}
}
if (evp != NULL) {
EVP_PKEY_free(evp);
}
if (pkcs8_pki != NULL) {
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_openssl_error();
return false;
default: // -1 == check failed.
LOGE("[LoadPkcs8RsaKey(): error checking rsa key]");
dump_openssl_error();
return false;
}
}
// Internal utility function to decrypt the message
bool SessionContext::DecryptMessage(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& iv,