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:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user