Add Support for Baked-In Certificates

Port from the widevine repo of http://go/wvgerrit/15628

This change enables easy support for baked-in certificates. Platforms
using this feature need only change the supports_keybox property to
false, replace keys.cpp with the file provided by Google, and make
sure the cert.bin provided by Google is preinstalled in the storage.

To enable this, new files defining storage for the embedded private
key were added to MockOEMCrypto. When supports_keybox is false, these
are referenced to get the embedded private key. As this code is mostly
shared with the existing test utility function that loads the test
certificate, the shared code was moved to a helper. Also, the behavior
of the MockOEMCrypto implementation OEMCrypto_LoadDeviceRSAKey when
supports_keybox is false was changed from erroring to validating that
the "wrapped private key" is actually the magic value 0xDEADBEEF.

Bug: 23554998
Change-Id: I8b5d7b4d37b8ec80bb4342e441625cbc5046df89
This commit is contained in:
Fred Gylys-Colwell
2015-09-16 13:34:15 -07:00
parent ff6b79d945
commit 914e13067f
6 changed files with 101 additions and 54 deletions

View File

@@ -5,6 +5,7 @@
#include "oemcrypto_engine_mock.h"
#include <arpa/inet.h>
#include <assert.h>
#include <string.h>
#include <iostream>
#include <vector>
@@ -20,6 +21,7 @@
#include <openssl/sha.h>
#include <openssl/x509.h>
#include "keys.h"
#include "log.h"
#include "oemcrypto_key_mock.h"
#include "oemcrypto_logging.h"
@@ -1165,6 +1167,11 @@ CryptoEngine::CryptoEngine()
: current_session_(NULL), use_test_keybox_(false),
usage_table_(new UsageTable(this)), rsa_key_(NULL) {
ERR_load_crypto_strings();
if (!supports_keybox() && !LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) {
LOGE("FATAL ERROR: Platform uses a baked-in certificate instead of a "
"keybox, but the certificate could not be loaded.");
}
}
CryptoEngine::~CryptoEngine() {
@@ -1183,59 +1190,8 @@ bool CryptoEngine::LoadTestRSAKey() {
RSA_free(rsa_key_);
rsa_key_ = NULL;
}
uint8_t *pkcs8_rsa_key
= const_cast<uint8_t *>(kTestRSAPKCS8PrivateKeyInfo2_2048);
size_t rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048);
BIO *bio = BIO_new_mem_buf(pkcs8_rsa_key, rsa_key_length);
if ( bio == NULL ) {
LOGE("[LoadTestRSAKey(): 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("[LoadTestRSAKey(): rsa key not valid]");
dump_openssl_error();
return false;
default: // -1 == check failed.
LOGE("[LoadTestRSAKey(): error checking rsa key]");
dump_openssl_error();
return false;
}
return LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048));
}
SessionId CryptoEngine::CreateSession() {
@@ -1268,6 +1224,59 @@ 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,