OEMCrypto was being initialized on session creation. Calls to get property information may occur before any sessions are created. This resulted in calls to OEMCrypto before a call to OEMCrypto_Initialize which caused a segfault. OEMCrypto initialization is now verified before any other calls are made. Unit tests have been modified to verify that this indeed works. bug: 8660973 Change-Id: I1b14fa8ad2e88750776b28715a48d8a1d1c57089
243 lines
5.6 KiB
C++
243 lines
5.6 KiB
C++
// Copyright 2012 Google Inc. All Rights Reserved.
|
|
//
|
|
// Crypto - wrapper classes for OEMCrypto interface
|
|
//
|
|
|
|
#include "crypto_engine.h"
|
|
|
|
#include <arpa/inet.h> // TODO(fredgc): Add ntoh to wv_cdm_utilities.h
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
#include "log.h"
|
|
#include "OEMCryptoCENC.h"
|
|
#include "properties.h"
|
|
#include "wv_cdm_constants.h"
|
|
|
|
namespace wvcdm {
|
|
|
|
CryptoEngine* CryptoEngine::crypto_engine_ = NULL;
|
|
Lock CryptoEngine::crypto_engine_lock_;
|
|
|
|
// wrapper classes for OEMCrypto interface
|
|
// CryptoEngine -- top-level interface
|
|
// CryptoSession -- session-specific interface
|
|
// CryptoKey -- key interface
|
|
|
|
// CryptoEngine methods
|
|
|
|
CryptoEngine::CryptoEngine() : initialized_(false) {}
|
|
|
|
CryptoEngine::~CryptoEngine() {
|
|
if (initialized_) {
|
|
Terminate();
|
|
}
|
|
|
|
CryptoSessionMap::iterator i(sessions_.begin());
|
|
for (; i != sessions_.end(); ++i)
|
|
delete i->second;
|
|
sessions_.clear();
|
|
}
|
|
|
|
// get the instance of OEMCrypto Client
|
|
CryptoEngine* CryptoEngine::GetInstance() {
|
|
if (NULL == crypto_engine_) {
|
|
crypto_engine_ = CreateSingleton();
|
|
}
|
|
return crypto_engine_;
|
|
}
|
|
|
|
CryptoEngine* CryptoEngine::CreateSingleton() {
|
|
AutoLock auto_lock(crypto_engine_lock_);
|
|
if (NULL == crypto_engine_) {
|
|
crypto_engine_ = new CryptoEngine;
|
|
}
|
|
return crypto_engine_;
|
|
}
|
|
|
|
void CryptoEngine::DeleteInstance() {
|
|
if (NULL != crypto_engine_) {
|
|
delete crypto_engine_;
|
|
LOGV("CryptoEngine::DeleteInstance");
|
|
crypto_engine_ = NULL;
|
|
}
|
|
}
|
|
|
|
bool CryptoEngine::Init() {
|
|
LOGV("CryptoEngine::Init: Lock");
|
|
AutoLock auto_lock(crypto_lock_);
|
|
if (!initialized_) {
|
|
OEMCryptoResult result = OEMCrypto_Initialize();
|
|
initialized_ = (OEMCrypto_SUCCESS == result);
|
|
}
|
|
return initialized_;
|
|
}
|
|
|
|
bool CryptoEngine::Terminate() {
|
|
DestroySessions();
|
|
LOGV("CryptoEngine::Terminate: Lock");
|
|
AutoLock auto_lock(crypto_lock_);
|
|
OEMCryptoResult result = OEMCrypto_Terminate();
|
|
if (OEMCrypto_SUCCESS == result) {
|
|
initialized_ = false;
|
|
}
|
|
return !initialized_;
|
|
}
|
|
|
|
bool CryptoEngine::ValidateKeybox() {
|
|
LOGV("CryptoEngine::ValidateKeybox: Lock");
|
|
AutoLock auto_lock(crypto_lock_);
|
|
OEMCryptoResult result = OEMCrypto_IsKeyboxValid();
|
|
return (OEMCrypto_SUCCESS == result);
|
|
}
|
|
|
|
CryptoSession* CryptoEngine::CreateSession(const CdmSessionId& session_id) {
|
|
LOGV("CryptoEngine::CreateSession: SLock");
|
|
AutoLock auto_lock(sessions_lock_);
|
|
if (0 == sessions_.size()) {
|
|
if (!Init()) {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
CryptoSessionMap::iterator it = sessions_.find(session_id);
|
|
if (it != sessions_.end()) {
|
|
LOGE("CryptoEngine::CreateSession : Duplicate session ID.");
|
|
return NULL;
|
|
}
|
|
|
|
CryptoSession* new_session = new CryptoSession(session_id);
|
|
if (!new_session) {
|
|
return NULL;
|
|
}
|
|
|
|
if (!new_session->Open()) {
|
|
delete new_session;
|
|
return NULL;
|
|
}
|
|
|
|
sessions_[session_id] = new_session;
|
|
return new_session;
|
|
}
|
|
|
|
CryptoSession* CryptoEngine::FindSessionInternal(
|
|
const CdmSessionId& session_id) {
|
|
// must hold sessions_lock_
|
|
CryptoSessionMap::iterator it = sessions_.find(session_id);
|
|
if (it != sessions_.end()) {
|
|
return it->second;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CryptoSession* CryptoEngine::FindSession(const CdmSessionId& session_id) {
|
|
LOGV("CryptoEngine::FindSession: SLock");
|
|
AutoLock auto_lock(sessions_lock_);
|
|
return FindSessionInternal(session_id);
|
|
}
|
|
|
|
bool CryptoEngine::DestroySession(const CdmSessionId& session_id) {
|
|
LOGV("CryptoEngine::DestroySession: SLock");
|
|
AutoLock auto_lock(sessions_lock_);
|
|
if (0 == sessions_.size()) {
|
|
return false;
|
|
}
|
|
CryptoSession* session = FindSessionInternal(session_id);
|
|
if (session) {
|
|
delete session;
|
|
sessions_.erase(session_id);
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CryptoEngine::DestroySessions() {
|
|
for (CryptoSessionMap::iterator it = sessions_.begin();
|
|
it != sessions_.end(); ++it) {
|
|
delete it->second;
|
|
}
|
|
sessions_.clear();
|
|
return true;
|
|
}
|
|
|
|
bool CryptoEngine::GetToken(std::string* token) {
|
|
LOGV("CryptoEngine::GetToken: Lock");
|
|
AutoLock auto_lock(crypto_lock_);
|
|
if (!token) {
|
|
LOGE("CryptoEngine::GetToken : No token passed to method.");
|
|
return false;
|
|
}
|
|
uint8_t buf[72];
|
|
size_t buflen = 72;
|
|
OEMCryptoResult sts = OEMCrypto_GetKeyData(buf, &buflen);
|
|
if (OEMCrypto_SUCCESS != sts) {
|
|
return false;
|
|
}
|
|
token->assign((const char*)buf, (size_t)buflen);
|
|
return true;
|
|
}
|
|
|
|
CryptoEngine::SecurityLevel CryptoEngine::GetSecurityLevel() {
|
|
if (!Init())
|
|
return kSecurityLevelUnknown;
|
|
|
|
std::string security_level = OEMCrypto_SecurityLevel();
|
|
|
|
if ((security_level.size() != 2) ||
|
|
(security_level.at(0) != 'L')) {
|
|
return kSecurityLevelUnknown;
|
|
}
|
|
|
|
switch (security_level.at(1)) {
|
|
case '1': return kSecurityLevelL1;
|
|
case '2': return kSecurityLevelL2;
|
|
case '3': return kSecurityLevelL3;
|
|
default : return kSecurityLevelUnknown;
|
|
}
|
|
|
|
return kSecurityLevelUnknown;
|
|
}
|
|
|
|
bool CryptoEngine::GetDeviceUniqueId(std::string* deviceId) {
|
|
if (!Init())
|
|
return false;
|
|
|
|
std::vector<uint8_t> id;
|
|
size_t idLength = 32;
|
|
|
|
id.resize(idLength);
|
|
|
|
OEMCryptoResult sts = OEMCrypto_GetDeviceID(&id[0], &idLength);
|
|
|
|
if (OEMCrypto_SUCCESS != sts) {
|
|
return false;
|
|
}
|
|
|
|
*deviceId = reinterpret_cast<const char*>(&id[0]);
|
|
return true;
|
|
}
|
|
|
|
bool CryptoEngine::GetSystemId(uint32_t* systemId) {
|
|
if (!Init())
|
|
return false;
|
|
|
|
uint8_t buf[72];
|
|
size_t buflen = 72;
|
|
|
|
OEMCryptoResult sts = OEMCrypto_GetKeyData(buf, &buflen);
|
|
|
|
if (OEMCrypto_SUCCESS != sts) {
|
|
return false;
|
|
}
|
|
|
|
// Decode 32-bit int encoded as network-byte-order byte array starting at
|
|
// index 4.
|
|
uint32_t* id = reinterpret_cast<uint32_t*>(&buf[4]);
|
|
|
|
*systemId = ntohl(*id);
|
|
return true;
|
|
}
|
|
|
|
}; // namespace wvcdm
|