Support CAST V2 authentication - OEMCrypto Interface - DO NOT MERGE

Squashed commit of these CLs from the widevine cdm repo:

Allow Version 8 OEMCrypto to be linked with CDM (KLP Modular Branch)
https://widevine-internal-review.googlesource.com/#/c/9434/

Allow OEMCrypto v8 or v9 (KLP Modular Branch)
https://widevine-internal-review.googlesource.com/#/c/9172/

Add alternate RSA signing (KLP Modular Branch)
https://widevine-internal-review.googlesource.com/#/c/9171/

bug: 12702350
Change-Id: Ifd0c88c566bb10efe2411af49bc83265ed56cb23
This commit is contained in:
Fred Gylys-Colwell
2014-03-24 13:46:38 -07:00
parent f1e87b1b04
commit a59b935928
14 changed files with 1930 additions and 322 deletions

View File

@@ -34,6 +34,7 @@ OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
SecurityLevel level);
uint32_t OEMCrypto_APIVersion(SecurityLevel level);
const char* OEMCrypto_SecurityLevel(SecurityLevel level);
bool OEMCrypto_SupportsUsageTable(SecurityLevel level);
} // namespace wvcdm
#endif // OEMCRYPTO_ADAPTER_H_

View File

@@ -50,6 +50,11 @@ typedef OEMCryptoResult (*L1_LoadKeys_t)(
const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys,
const OEMCrypto_KeyObject* key_array,
const uint8_t* pst, size_t pst_length);
typedef OEMCryptoResult (*L1_LoadKeys_V8_t)(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length,
const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys,
const OEMCrypto_KeyObject* key_array);
typedef OEMCryptoResult (*L1_RefreshKeys_t)(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length, size_t num_keys,
@@ -90,7 +95,12 @@ typedef OEMCryptoResult (*L1_GenerateRSASignature_t)(OEMCrypto_SESSION session,
size_t message_length,
uint8_t* signature,
size_t* signature_length,
RSA_Padding_Scheme algorithm);
RSA_Padding_Scheme padding_scheme);
typedef OEMCryptoResult (*L1_GenerateRSASignature_V8_t)(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
typedef OEMCryptoResult (*L1_DeriveKeysFromSessionKey_t)(
OEMCrypto_SESSION session, const uint8_t* enc_session_key,
size_t enc_session_key_length, const uint8_t* mac_key_context,
@@ -118,8 +128,28 @@ typedef OEMCryptoResult (*L1_Generic_Verify_t)(OEMCrypto_SESSION session,
size_t signature_length);
typedef uint32_t (*L1_APIVersion_t)();
typedef const char* (*L1_SecurityLevel_t)();
typedef OEMCryptoResult (*L1_GetHDCPCapability_t)(OEMCrypto_HDCP_Capability *current,
OEMCrypto_HDCP_Capability *maximum);
typedef bool (*L1_SupportsUsageTable_t)();
typedef OEMCryptoResult (*L1_UpdateUsageTable_t)();
typedef OEMCryptoResult (*L1_DeactivateUsageEntry_t)(const uint8_t *pst,
size_t pst_length);
typedef OEMCryptoResult (*L1_ReportUsage_t)(OEMCrypto_SESSION session,
const uint8_t *pst,
size_t pst_length,
OEMCrypto_PST_Report *buffer,
size_t *buffer_length);
typedef OEMCryptoResult (*L1_DeleteUsageEntry_t)(OEMCrypto_SESSION session,
const uint8_t* pst,
size_t pst_length,
const uint8_t *message,
size_t message_length,
const uint8_t *signature,
size_t signature_length);
typedef OEMCryptoResult (*L1_DeleteUsageTable_t)();
struct FunctionPointers {
uint32_t version;
L1_Initialize_t Initialize;
L1_Terminate_t Terminate;
L1_OpenSession_t OpenSession;
@@ -147,6 +177,16 @@ struct FunctionPointers {
L1_Generic_Decrypt_t Generic_Decrypt;
L1_Generic_Sign_t Generic_Sign;
L1_Generic_Verify_t Generic_Verify;
L1_GetHDCPCapability_t GetHDCPCapability;
L1_SupportsUsageTable_t SupportsUsageTable;
L1_UpdateUsageTable_t UpdateUsageTable;
L1_DeactivateUsageEntry_t DeactivateUsageEntry;
L1_ReportUsage_t ReportUsage;
L1_DeleteUsageEntry_t DeleteUsageEntry;
L1_DeleteUsageTable_t DeleteUsageTable;
L1_LoadKeys_V8_t LoadKeys_V8;
L1_GenerateRSASignature_V8_t GenerateRSASignature_V8;
};
struct LevelSession {
@@ -212,7 +252,6 @@ class Adapter {
LOOKUP(GenerateDerivedKeys, OEMCrypto_GenerateDerivedKeys);
LOOKUP(GenerateNonce, OEMCrypto_GenerateNonce);
LOOKUP(GenerateSignature, OEMCrypto_GenerateSignature);
LOOKUP(LoadKeys, OEMCrypto_LoadKeys);
LOOKUP(RefreshKeys, OEMCrypto_RefreshKeys);
LOOKUP(SelectKey, OEMCrypto_SelectKey);
LOOKUP(DecryptCTR, OEMCrypto_DecryptCTR);
@@ -224,7 +263,6 @@ class Adapter {
LOOKUP(WrapKeybox, OEMCrypto_WrapKeybox);
LOOKUP(RewrapDeviceRSAKey, OEMCrypto_RewrapDeviceRSAKey);
LOOKUP(LoadDeviceRSAKey, OEMCrypto_LoadDeviceRSAKey);
LOOKUP(GenerateRSASignature, OEMCrypto_GenerateRSASignature);
LOOKUP(DeriveKeysFromSessionKey, OEMCrypto_DeriveKeysFromSessionKey);
LOOKUP(APIVersion, OEMCrypto_APIVersion);
LOOKUP(SecurityLevel, OEMCrypto_SecurityLevel);
@@ -240,13 +278,27 @@ class Adapter {
LOGW("Could not initialize L1. Falling Back to L3.");
return false;
}
uint32_t level1_version = level1_.APIVersion();
level1_.version = level1_.APIVersion();
uint32_t minimum_version = 8; // TODO(fredgc): allow version 8 and 9?
if (level1_version < minimum_version) {
if (level1_.version < minimum_version) {
LOGW("liboemcrypto.so is version %d, not %d. Falling Back to L3.",
level1_version, minimum_version);
level1_.version, minimum_version);
return false;
}
if( level1_.version == 8 ) {
LOOKUP(LoadKeys_V8, OEMCrypto_LoadKeys_V8);
LOOKUP(GenerateRSASignature_V8, OEMCrypto_GenerateRSASignature_V8);
} else {
LOOKUP(LoadKeys, OEMCrypto_LoadKeys);
LOOKUP(GenerateRSASignature, OEMCrypto_GenerateRSASignature);
LOOKUP(GetHDCPCapability, OEMCrypto_GetHDCPCapability);
LOOKUP(SupportsUsageTable, OEMCrypto_SupportsUsageTable);
LOOKUP(UpdateUsageTable, OEMCrypto_UpdateUsageTable);
LOOKUP(DeactivateUsageEntry, OEMCrypto_DeactivateUsageEntry);
LOOKUP(ReportUsage, OEMCrypto_ReportUsage);
LOOKUP(DeleteUsageEntry, OEMCrypto_DeleteUsageEntry);
LOOKUP(DeleteUsageTable, OEMCrypto_DeleteUsageTable);
}
if (OEMCrypto_SUCCESS == level1_.IsKeyboxValid()) {
return true;
}
@@ -300,6 +352,14 @@ class Adapter {
level3_.Generic_Encrypt = Level3_Generic_Encrypt;
level3_.Generic_Sign = Level3_Generic_Sign;
level3_.Generic_Verify = Level3_Generic_Verify;
level3_.GetHDCPCapability = Level3_GetHDCPCapability;
level3_.SupportsUsageTable = Level3_SupportsUsageTable;
level3_.UpdateUsageTable = Level3_UpdateUsageTable;
level3_.DeactivateUsageEntry = Level3_DeactivateUsageEntry;
level3_.ReportUsage = Level3_ReportUsage;
level3_.DeleteUsageEntry = Level3_DeleteUsageEntry;
level3_.DeleteUsageTable = Level3_DeleteUsageTable;
level3_.version = Level3_APIVersion();
}
OEMCryptoResult Terminate() {
@@ -318,7 +378,7 @@ class Adapter {
}
LevelSession get(OEMCrypto_SESSION session) {
AutoLock auto_lock(lookup_lock_);
AutoLock auto_lock(session_map_lock_);
map_iterator pair = session_map_.find(session);
if (pair == session_map_.end()) {
return LevelSession();
@@ -327,7 +387,6 @@ class Adapter {
}
OEMCryptoResult OpenSession(OEMCrypto_SESSION* session, SecurityLevel level) {
AutoLock auto_lock(lookup_lock_);
LevelSession new_session;
OEMCryptoResult result;
if (level == kLevelDefault && level1_valid_) {
@@ -340,6 +399,7 @@ class Adapter {
*session = new_session.session + kLevel3Offset;
}
if (result == OEMCrypto_SUCCESS) {
AutoLock auto_lock(session_map_lock_);
// Make sure session is not already in my list of sessions.
while (session_map_.find(*session) != session_map_.end()) {
(*session)++;
@@ -350,7 +410,7 @@ class Adapter {
}
OEMCryptoResult CloseSession(OEMCrypto_SESSION session) {
AutoLock auto_lock(lookup_lock_);
AutoLock auto_lock(session_map_lock_);
map_iterator pair = session_map_.find(session);
if (pair == session_map_.end()) {
return OEMCrypto_ERROR_INVALID_SESSION;
@@ -367,7 +427,7 @@ class Adapter {
struct FunctionPointers level1_;
struct FunctionPointers level3_;
std::map<OEMCrypto_SESSION, LevelSession> session_map_;
Lock lookup_lock_;
Lock session_map_lock_;
// This is just for debugging the map between session ids.
// If we add this to the level 3 session id, then the external session
// id will match the internal session id in the last two digits.
@@ -447,9 +507,15 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
LevelSession pair = kAdapter->get(session);
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return pair.fcn->LoadKeys(pair.session, message, message_length, signature,
signature_length, enc_mac_key_iv, enc_mac_key,
num_keys, key_array, pst, pst_length);
if (pair.fcn->version == 8) {
return pair.fcn->LoadKeys_V8(pair.session, message, message_length, signature,
signature_length, enc_mac_key_iv, enc_mac_key,
num_keys, key_array);
} else {
return pair.fcn->LoadKeys(pair.session, message, message_length, signature,
signature_length, enc_mac_key_iv, enc_mac_key,
num_keys, key_array, pst, pst_length);
}
}
extern "C" OEMCryptoResult OEMCrypto_RefreshKeys(
@@ -583,12 +649,18 @@ extern "C" OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(
extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme algorithm) {
uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
LevelSession pair = kAdapter->get(session);
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
return pair.fcn->GenerateRSASignature(pair.session, message, message_length,
signature, signature_length, algorithm);
if (pair.fcn->version == 8) {
return pair.fcn->GenerateRSASignature_V8(pair.session, message, message_length,
signature, signature_length);
} else {
return pair.fcn->GenerateRSASignature(pair.session, message, message_length,
signature, signature_length,
padding_scheme);
}
}
extern "C" OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
@@ -671,4 +743,96 @@ extern "C" OEMCryptoResult OEMCrypto_Generic_Verify(
algorithm, signature, signature_length);
}
extern "C"
OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability *current,
OEMCrypto_HDCP_Capability *maximum) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn = kAdapter->get(kLevelDefault);
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
if( fcn->version == 8 ) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
return fcn->GetHDCPCapability(current, maximum);
}
extern "C" bool OEMCrypto_SupportsUsageTable() {
return OEMCrypto_SupportsUsageTable(kLevelDefault);
}
bool OEMCrypto_SupportsUsageTable(SecurityLevel level) {
if (!kAdapter) return false;
const FunctionPointers* fcn = kAdapter->get(level);
if (!fcn) return false;
if( fcn->version == 8 ) return false;
return fcn->SupportsUsageTable();
}
extern "C" OEMCryptoResult OEMCrypto_UpdateUsageTable() {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault);
const FunctionPointers* fcn3 = kAdapter->get(kLevel3);
OEMCryptoResult sts = OEMCrypto_ERROR_NOT_IMPLEMENTED;
if (fcn3 && fcn3->version > 8) sts = fcn3->UpdateUsageTable();
if (fcn1 && fcn1 != fcn3 && fcn1->version > 8) sts = fcn1->UpdateUsageTable();
return sts;
}
extern "C" OEMCryptoResult OEMCrypto_DeactivateUsageEntry(const uint8_t *pst,
size_t pst_length) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault);
const FunctionPointers* fcn3 = kAdapter->get(kLevel3);
OEMCryptoResult sts = OEMCrypto_ERROR_NOT_IMPLEMENTED;
if (fcn3 && fcn3->version > 8) {
sts = fcn3->DeactivateUsageEntry(pst, pst_length);
}
if (fcn1 && fcn1 != fcn3 && fcn1->version > 8) {
sts = fcn1->DeactivateUsageEntry(pst, pst_length);
}
return sts;
}
extern "C" OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session,
const uint8_t *pst,
size_t pst_length,
OEMCrypto_PST_Report *buffer,
size_t *buffer_length) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
LevelSession pair = kAdapter->get(session);
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
if( pair.fcn->version > 8 ) {
return pair.fcn->ReportUsage(pair.session, pst, pst_length,buffer,
buffer_length);
} else {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
}
extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION session,
const uint8_t* pst,
size_t pst_length,
const uint8_t *message,
size_t message_length,
const uint8_t *signature,
size_t signature_length) {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
LevelSession pair = kAdapter->get(session);
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
if( pair.fcn->version > 8 ) {
return pair.fcn->DeleteUsageEntry(session, pst, pst_length, message,
message_length, signature,
signature_length);
} else {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
}
extern "C" OEMCryptoResult OEMCrypto_DeleteUsageTable() {
if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault);
const FunctionPointers* fcn3 = kAdapter->get(kLevel3);
OEMCryptoResult sts = OEMCrypto_ERROR_NOT_IMPLEMENTED;
if (fcn3 && fcn3->version > 8) sts = fcn3->DeleteUsageTable();
if (fcn1 && fcn1 != fcn3 && fcn1->version > 8) sts = fcn1->DeleteUsageTable();
return sts;
}
}; // namespace wvcdm

View File

@@ -0,0 +1,127 @@
/*******************************************************************************
*
* Copyright 2013 Google Inc. All Rights Reserved.
*
* Wrapper of OEMCrypto APIs for platforms that support Level 1 only.
* This should be used when liboemcrypto.so is linked with the CDM code at
* compile time.
* An implementation should compile either oemcrypto_adapter_dynamic.cpp or
* oemcrypto_adapter_static.cpp, but not both.
* This version contains shim code to allow an older, version 8 API, oemcrypto,
* to be linked with CDM.
*
******************************************************************************/
#include "OEMCryptoCENC.h"
#include "oemcrypto_adapter.h"
extern "C"
OEMCryptoResult OEMCrypto_LoadKeys_V8(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
const uint8_t* signature,
size_t signature_length,
const uint8_t* enc_mac_keys_iv,
const uint8_t* enc_mac_keys,
size_t num_keys,
const OEMCrypto_KeyObject* key_array);
extern "C"
OEMCryptoResult OEMCrypto_GenerateRSASignature_V8(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t *signature_length);
namespace wvcdm {
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
SecurityLevel level) {
return ::OEMCrypto_OpenSession(session);
}
OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel level) {
return ::OEMCrypto_IsKeyboxValid();
}
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength,
SecurityLevel level) {
return ::OEMCrypto_GetDeviceID(deviceID, idLength);
}
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength,
SecurityLevel level) {
return ::OEMCrypto_GetKeyData(keyData, keyDataLength);
}
OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
size_t keyBoxLength,
SecurityLevel level) {
return ::OEMCrypto_InstallKeybox(keybox, keyBoxLength);
}
uint32_t OEMCrypto_APIVersion(SecurityLevel level) {
return ::OEMCrypto_APIVersion();
}
const char* OEMCrypto_SecurityLevel(SecurityLevel level) {
return ::OEMCrypto_SecurityLevel();
}
extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
const uint8_t* signature, size_t signature_length,
const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys,
const OEMCrypto_KeyObject* key_array,
const uint8_t* pst, size_t pst_length) {
return LoadKeys_V8(pair.session, message, message_length, signature,
signature_length, enc_mac_key_iv, enc_mac_key,
num_keys, key_array);
}
extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme) {
return GenerateRSASignature_V8(pair.session, message, message_length,
signature, signature_length);
}
extern "C"
OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability *current,
OEMCrypto_HDCP_Capability *maximum) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
extern "C" bool OEMCrypto_SupportsUsageTable() {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
extern "C" OEMCryptoResult OEMCrypto_UpdateUsageTable() {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
extern "C" OEMCryptoResult OEMCrypto_DeactivateUsageEntry(const uint8_t *pst,
size_t pst_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
extern "C" OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session,
const uint8_t *pst,
size_t pst_length,
OEMCrypto_PST_Report *buffer,
size_t *buffer_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry(OEMCrypto_SESSION session,
const uint8_t* pst,
size_t pst_length,
const uint8_t *message,
size_t message_length,
const uint8_t *signature,
size_t signature_length) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
}; // namespace wvcdm

View File

@@ -192,7 +192,8 @@ typedef enum OEMCrypto_Algorithm {
#define OEMCrypto_FirstSubsample 1
#define OEMCrypto_LastSubsample 2
/* OEMCrypto_Usage_Entry_Status.
/*
* OEMCrypto_Usage_Entry_Status.
* Valid values for status in the usage table.
*/
typedef enum OEMCrypto_Usage_Entry_Status {
@@ -215,7 +216,8 @@ typedef struct {
uint8_t pst[];
} OEMCrypto_PST_Report;
/* OEMCrypto_Clock_Security_Level.
/*
* OEMCrypto_Clock_Security_Level.
* Valid values for clock_security_level in OEMCrypto_PST_Report.
*/
typedef enum OEMCrypto_Clock_Security_Level {
@@ -231,7 +233,9 @@ typedef enum RSA_Padding_Scheme {
} RSA_Padding_Scheme;
/* Obfuscation Renames. */
/*
* Obfuscation Renames.
*/
#define OEMCrypto_Initialize _oecc01
#define OEMCrypto_Terminate _oecc02
#define OEMCrypto_InstallKeybox _oecc03
@@ -246,12 +250,12 @@ typedef enum RSA_Padding_Scheme {
#define OEMCrypto_GenerateDerivedKeys _oecc12
#define OEMCrypto_GenerateSignature _oecc13
#define OEMCrypto_GenerateNonce _oecc14
#define OEMCrypto_LoadKeys _oecc15
#define OEMCrypto_LoadKeys_V8 _oecc15
#define OEMCrypto_RefreshKeys _oecc16
#define OEMCrypto_SelectKey _oecc17
#define OEMCrypto_RewrapDeviceRSAKey _oecc18
#define OEMCrypto_LoadDeviceRSAKey _oecc19
#define OEMCrypto_GenerateRSASignature _oecc20
#define OEMCrypto_GenerateRSASignature_V8 _oecc20
#define OEMCrypto_DeriveKeysFromSessionKey _oecc21
#define OEMCrypto_APIVersion _oecc22
#define OEMCrypto_SecurityLevel _oecc23
@@ -266,27 +270,28 @@ typedef enum RSA_Padding_Scheme {
#define OEMCrypto_ReportUsage _oecc32
#define OEMCrypto_DeleteUsageEntry _oecc33
#define OEMCrypto_DeleteUsageTable _oecc34
#define OEMCrypto_LoadKeys _oecc35
#define OEMCrypto_GenerateRSASignature _oecc36
/*
* OEMCrypto_Initialize
*
Initializes the crypto hardware.
Parameters:
None
Returns:
OEMCrypto_SUCCESS success
OEMCrypto_ERROR_INIT_FAILED failed to initialize crypto hardware
Threading:
No other function calls will be made while this function is running. This
function will not be called again before OEMCrypto_Terminate().
Version:
This method is supported by all API versions.
* Description:
* Initialize the crypto firmware/hardware.
*
* Parameters:
* N/A
*
* Threading:
* No other function calls will be made while this function is running. This
* function will not be called again before OEMCrypto_Terminate.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_INIT_FAILED failed to initialize crypto hardware
*
* Version:
* This method is supported by all API versions.
*/
OEMCryptoResult OEMCrypto_Initialize(void);
@@ -428,8 +433,12 @@ OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
*
* Because the nonce will be used to prevent replay attacks, it is desirable
* that a rogue application cannot rapidly call this function until a
* repeated nonce is created randomly. With this in mind, we require that
* creation of more than 20 nonces will take at least one full second.
* repeated nonce is created randomly. With this in mind, if more than 20
* nonces are requested within one second, OEMCrypto will return an error
* after the 20th and not generate any more nonces for the rest of the
* second. After an error, if the application waits at least one second
* before requesting more nonces, then OEMCrypto will reset the error
* condition and generate valid nonces again.
*
* Parameters:
* session (in) - crypto session identifier.
@@ -1028,52 +1037,52 @@ OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t *keybox,
/*
* OEMCrypto_IsKeyboxValid
*
Validates the Widevine Keybox loaded into the security processor device. This
method verifies two fields in the keybox:
Verify the MAGIC field contains a valid signature (such as, kbox).
Compute the CRC using CRC-32-POSIX-1003.2 standard and compare the checksum
to the CRC stored in the Keybox. The CRC is computed over the entire Keybox
excluding the 4 bytes of the CRC (for example, Keybox[0..123]). For a
description of the fields stored in the keybox, see Keybox Definition.
Parameters:
none
Returns:
OEMCrypto_SUCCESS
OEMCrypto_ERROR_BAD_MAGIC
OEMCrypto_ERROR_BAD_CRC
Threading:
This function may be called simultaneously with any session functions.
Version:
This method is supported in all API versions.
* Description:
* Validate the Widevine Keybox stored on the device.
*
* The API performs two verification steps on the Keybox. It first verifies
* the MAGIC field contains a valid signature (must be 'kbox'). The API then
* computes the CRC using CRC-32 (Posix 1003.2 standard) and compares the
* checksum to the CRC stored in the Keybox. The CRC is computed over the
* entire Keybox excluding the 4 CRC bytes (i.e. Keybox[0..123]).
*
* Parameters:
* none
*
* Threading:
* This function may be called simultaneously with any session functions.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_BAD_MAGIC
* OEMCrypto_ERROR_BAD_CRC
*
* Version:
* This method is supported by all API versions.
*/
OEMCryptoResult OEMCrypto_IsKeyboxValid(void);
/*
* OEMCrypto_GetDeviceID
*
Retrieve DeviceID from the Keybox.
Parameters:
[out] deviceId - pointer to the buffer that receives the Device ID
[in/out] idLength on input, size of the callers device ID buffer. On
output, the number of bytes written into the buffer.
Returns:
OEMCrypto_SUCCESS success
OEMCrypto_ERROR_SHORT_BUFFER if the buffer is too small to return device ID
OEMCrypto_ERROR_NO_DEVICEID failed to return Device Id
Threading:
This function may be called simultaneously with any session functions.
Version:
This method is supported in all API versions.
* Description:
* Retrieve the device's unique identifier from the Keybox.
*
* Parameters:
* deviceId (out) - pointer to the buffer that receives the Device ID
* idLength (in/out) - on input, size of the caller's device ID buffer.
* On output, the number of bytes written into the buffer.
*
* Threading:
* This function may be called simultaneously with any session functions.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_SHORT_BUFFER buffer is too small to return the device ID
* OEMCrypto_ERROR_NO_DEVICEID failed to return Device Id
*
* Version:
* This method is supported by all API versions.
*/
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
size_t *idLength);
@@ -1081,24 +1090,31 @@ OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID,
/*
* OEMCrypto_GetKeyData
*
Return the Key Data field from the Keybox.
Parameters:
[out] keyData - pointer to the buffer to hold the Key Data field from the
Keybox
[in/out] keyDataLength on input, the allocated buffer size. On output, the
number of bytes in Key Data
Returns:
OEMCrypto_SUCCESS success
OEMCrypto_ERROR_SHORT_BUFFER if the buffer is too small to return KeyData
OEMCrypto_ERROR_NO_KEYDATA
Threading:
This function may be called simultaneously with any session functions.
Version:
This method is supported in all API versions.
* Description:
* Returns the Key Data field from the Keybox. The Key Data field does not
* need to be encrypted by an OEM root key, but may be if desired.
*
* If the Key Data field was encrypted with an OEM root key when the Keybox
* was stored on the device, then this function should decrypt it and return
* the clear Key Data. If the Key Data was not encrypted, then this function
* should just access and return the clear Key data.
*
* Parameters:
* keyData (out) - pointer to a caller-managed buffer to hold the Key Data
* field from the Keybox
* dataLength (in/out) - on input, the allocated buffer size. On output,
* the number of bytes in KeyData.
*
* Threading:
* This function may be called simultaneously with any session functions.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_SHORT_BUFFER the buffer is too small to return the KeyData
* OEMCrypto_ERROR_NO_KEYDATA failed to return KeyData
*
* Version:
* This method is supported by all API versions.
*/
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,
size_t *keyDataLength);
@@ -1106,23 +1122,25 @@ OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,
/*
* OEMCrypto_GetRandom
*
Returns a buffer filled with hardware-generated random bytes, if supported by
the hardware.
Parameters:
[out] randomData - pointer to the buffer that receives random data
[in] dataLength - length of the random data buffer in bytes
Returns:
OEMCrypto_SUCCESS success
OEMCrypto_ERROR_RNG_FAILED failed to generate random number
OEMCrypto_ERROR_RNG_NOT_SUPPORTED function not supported
Threading:
This function may be called simultaneously with any session functions.
Version:
This method is supported in all API versions.
* Description:
* Return a buffer filled with hardware-generated random bytes. If the
* hardware feature does not exist, return OEMCrypto_ERROR_RNG_NOT_SUPPORTED.
*
* Parameters:
* randomData (out) - Pointer to caller-manager buffer that will receive the
* random data.
* dataLength (in) - Length of the random data buffer in bytes.
*
* Threading:
* This function may be called simultaneously with any session functions.
*
* Returns:
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_RNG_FAILED failed to generate random number
* OEMCrypto_ERROR_RNG_NOT_SUPPORTED function not supported
*
* Version:
* This method is supported by all API versions.
*/
OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData,
size_t dataLength);
@@ -1263,8 +1281,6 @@ OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey(OEMCrypto_SESSION session,
* - padding. This is the wrapped key generated
* - by OEMCrypto_RewrapDeviceRSAKey.
* wrapped_rsa_key_length (in) - length of the wrapped key buffer, in bytes.
* wrapped_rsa_key_iv (in) - The initialization vector used to encrypt
* - wrapped_rsa_key.
*
* Threading:
* This function may be called simultaneously with functions on other sessions,
@@ -1546,41 +1562,25 @@ bool OEMCrypto_SupportsUsageTable();
* that entry is “inactive”, then return OEMCrypto_ERROR_INVALID_SESSION.
*
* Parameters:
* current (out) - this is the current HDCP version, based on the device itself,
* and the display to which it is connected.
* maximum (out) - this is the maximum supported HDCP version for the device,
* ignoring any attached device.
*
* Threading:
* This function may be called simultaneously with any other functions.
* [in] session: crypto session identifier.
* [in] in_buffer: pointer to memory containing data to be encrypted.
* [in] buffer_length: length of the buffer, in bytes.
* [in] iv: IV for encrypting data. Size is specified by the algorithm.
* [in] algorithm: Specifies which encryption algorithm to use. See
* OEMCrypto_Algorithm for valid values.
* [out] out_buffer: pointer to buffer in which encrypted data should be stored.
*
* Returns:
* OEMCrypto_SUCCESS
* OEMCrypto_ERROR_UNKNOWN_FAILURE
*
* Version:
* This method changed in API version 9.
*/
typedef uint8_t OEMCrypto_HDCP_Capability;
OEMCryptoResult OEMCrypto_GetHDCPCapability(OEMCrypto_HDCP_Capability *current,
OEMCrypto_HDCP_Capability *maximum);
/*
* OEMCrypto_SupportsUsageTable()
*
* Description:
* This is used to determine if the device can support a usage table. Since this
* function is spoofable, it is not relied on for security purposes. It is for
* information only. The usage table is described in the section above.
*
* Parameters:
* none
* OEMCrypto_SUCCESS success
* OEMCrypto_ERROR_KEY_EXPIRED
* OEMCrypto_ERROR_NO_DEVICE_KEY
* OEMCrypto_ERROR_INVALID_SESSION
* OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
* OEMCrypto_ERROR_UNKNOWN_FAILURE
*
* Threading:
* This function may be called simultaneously with any other functions.
*
* Returns:
* Returns true if the device can maintain a usage table. Returns false otherwise.
* This function may be called simultaneously with functions on other sessions,
* but not with other functions on this session.
*
* Version:
* This method changed in API version 9.

View File

@@ -43,6 +43,13 @@ namespace wvoec3 {
#define Level3_Generic_Decrypt _lcc25
#define Level3_Generic_Sign _lcc26
#define Level3_Generic_Verify _lcc27
#define Level3_GetHDCPCapability _lcc28
#define Level3_SupportsUsageTable _lcc29
#define Level3_UpdateUsageTable _lcc30
#define Level3_DeactivateUsageEntry _lcc31
#define Level3_ReportUsage _lcc32
#define Level3_DeleteUsageEntry _lcc33
#define Level3_DeleteUsageTable _lcc34
extern "C" {
@@ -125,7 +132,7 @@ OEMCryptoResult Level3_GenerateRSASignature(OEMCrypto_SESSION session,
size_t message_length,
uint8_t* signature,
size_t *signature_length,
RSA_Padding_Scheme algorithm);
RSA_Padding_Scheme padding_scheme);
OEMCryptoResult Level3_DeriveKeysFromSessionKey(OEMCrypto_SESSION session,
const uint8_t* enc_session_key,
size_t enc_session_key_length,
@@ -159,6 +166,26 @@ OEMCryptoResult Level3_Generic_Verify(OEMCrypto_SESSION session,
OEMCrypto_Algorithm algorithm,
const uint8_t* signature,
size_t signature_length);
OEMCryptoResult Level3_GetHDCPCapability(OEMCrypto_HDCP_Capability *current,
OEMCrypto_HDCP_Capability *maximum);
bool Level3_SupportsUsageTable();
OEMCryptoResult Level3_UpdateUsageTable();
OEMCryptoResult Level3_DeactivateUsageEntry(const uint8_t *pst,
size_t pst_length);
OEMCryptoResult Level3_ReportUsage(OEMCrypto_SESSION session,
const uint8_t *pst,
size_t pst_length,
OEMCrypto_PST_Report *buffer,
size_t *buffer_length);
OEMCryptoResult Level3_DeleteUsageEntry(OEMCrypto_SESSION session,
const uint8_t* pst,
size_t pst_length,
const uint8_t *message,
size_t message_length,
const uint8_t *signature,
size_t signature_length);
OEMCryptoResult Level3_DeleteUsageTable();
};
}

View File

@@ -8,6 +8,7 @@
#include "oemcrypto_engine_mock.h"
#include <arpa/inet.h>
#include <iostream>
#include <vector>
#include <string.h>
@@ -31,8 +32,9 @@
static const int kPssSaltLength = 20;
namespace {
// Increment counter for AES-CTR
void ctr128_inc(uint8_t* counter) {
// Increment counter for AES-CTR. The CENC spec specifies we increment only
// the low 64 bits of the IV counter, and leave the high 64 bits alone.
void ctr128_inc64(uint8_t* counter) {
uint32_t n = 16;
do {
if (++counter[--n] != 0) return;
@@ -252,7 +254,8 @@ size_t SessionContext::RSASignatureSize() {
bool SessionContext::GenerateRSASignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length) {
size_t* signature_length,
RSA_Padding_Scheme padding_scheme) {
if (message == NULL || message_length == 0 ||
signature == NULL || signature_length == 0) {
LOGE("[GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]");
@@ -266,33 +269,55 @@ bool SessionContext::GenerateRSASignature(const uint8_t* message,
*signature_length = RSA_size(rsa_key_);
return false;
}
// Hash the message using SHA1.
uint8_t hash[SHA_DIGEST_LENGTH];
if (!SHA1(message, message_length, hash)) {
LOGE("[GeneratRSASignature(): error creating signature hash.]");
dump_openssl_error();
if ((padding_scheme & allowed_schemes_) != padding_scheme) {
LOGE("[GenerateRSASignature(): padding_scheme not allowed]");
return false;
}
// Add PSS padding.
std::vector<uint8_t> padded_digest(*signature_length);
int status = RSA_padding_add_PKCS1_PSS(rsa_key_, &padded_digest[0], hash,
EVP_sha1(), kPssSaltLength);
if (status == -1) {
LOGE("[GeneratRSASignature(): error padding hash.]");
dump_openssl_error();
if (padding_scheme == kSign_RSASSA_PSS) {
// Hash the message using SHA1.
uint8_t hash[SHA_DIGEST_LENGTH];
if (!SHA1(message, message_length, hash)) {
LOGE("[GeneratRSASignature(): error creating signature hash.]");
dump_openssl_error();
return false;
}
// Add PSS padding.
std::vector<uint8_t> padded_digest(*signature_length);
int status = RSA_padding_add_PKCS1_PSS(rsa_key_, &padded_digest[0], hash,
EVP_sha1(), kPssSaltLength);
if (status == -1) {
LOGE("[GeneratRSASignature(): error padding hash.]");
dump_openssl_error();
return false;
}
// Encrypt PSS padded digest.
status = RSA_private_encrypt(*signature_length, &padded_digest[0], signature,
rsa_key_, RSA_NO_PADDING);
if (status == -1) {
LOGE("[GeneratRSASignature(): error in private encrypt.]");
dump_openssl_error();
return false;
}
} else if (padding_scheme == kSign_PKCS1_Block1) {
if (message_length > 83) {
LOGE("[GeneratRSASignature(): RSA digest too large.]");
return false;
}
// Pad the message with PKCS1 padding, and then encrypt.
int status = RSA_private_encrypt(message_length, message, signature,
rsa_key_, RSA_PKCS1_PADDING);
if (status != *signature_length) {
LOGE("[GeneratRSASignature(): error in RSA private encrypt. status=%d]", status);
dump_openssl_error();
return false;
}
} else { // Bad RSA_Padding_Scheme
return false;
}
// Encrypt PSS padded digest.
status = RSA_private_encrypt(*signature_length, &padded_digest[0], signature,
rsa_key_, RSA_NO_PADDING);
if (status == -1) {
LOGE("[GeneratRSASignature(): error in private encrypt.]");
dump_openssl_error();
return false;
}
return true;
}
@@ -485,6 +510,16 @@ bool SessionContext::LoadRSAKey(uint8_t* pkcs8_rsa_key,
RSA_free(rsa_key_);
rsa_key_ = NULL;
}
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);
allowed_schemes_ = htonl(*schemes_n);
pkcs8_rsa_key += 8;
rsa_key_length -= 8;
}
BIO *bio = BIO_new_mem_buf(pkcs8_rsa_key, rsa_key_length);
if( bio == NULL ) {
LOGE("[LoadRSAKey(): Could not allocate bio buffer]");
@@ -899,11 +934,11 @@ bool CryptoEngine::DecryptCTR(SessionContext* session,
const uint8_t* cipher_data,
size_t cipher_data_length,
bool is_encrypted,
void* clear_data,
uint8_t* clear_data,
BufferType buffer_type) {
// If the data is clear, we do not need a current key selected.
if (!is_encrypted) {
if (!is_encrypted && buffer_type != kBufferTypeDirect) {
memcpy(reinterpret_cast<uint8_t*>(clear_data),
cipher_data, cipher_data_length);
return true;
@@ -961,20 +996,20 @@ bool CryptoEngine::DecryptCTR(SessionContext* session,
// Encrypt the IV.
uint8_t ecount_buf[AES_BLOCK_SIZE];
if (block_offset != 0) {
// The context is needed only when not starting a new block.
AES_encrypt(aes_iv, ecount_buf, &aes_key);
ctr128_inc(aes_iv);
}
// Decryption.
unsigned int block_offset_cur = block_offset;
AES_ctr128_encrypt(
cipher_data, reinterpret_cast<uint8_t*>(clear_data), cipher_data_length,
&aes_key, aes_iv, ecount_buf, &block_offset_cur);
if (block_offset_cur != ((block_offset + cipher_data_length) % AES_BLOCK_SIZE)) {
LOGE("[DecryptCTR(): FAILURE: byte offset wrong.]");
return false;
// The CENC spec specifies we increment only the low 64 bits of the IV
// counter, and leave the high 64 bits alone. This is different from the
// OpenSSL implementation, which increments the entire 128 bit iv. That is
// why we implement the CTR loop ourselves.
size_t l = 0;
while (l < cipher_data_length) {
AES_encrypt(aes_iv, ecount_buf, &aes_key);
for (int n = block_offset; n < AES_BLOCK_SIZE && l < cipher_data_length;
++n, ++l) {
clear_data[l] = cipher_data[l] ^ ecount_buf[n];
}
ctr128_inc64(aes_iv);
block_offset = 0;
}
return true;
}

View File

@@ -88,7 +88,7 @@ class SessionContext {
public:
explicit SessionContext(CryptoEngine* ce, SessionId sid)
: valid_(true), ce_(ce), id_(sid), current_content_key_(NULL),
rsa_key_(NULL) {}
rsa_key_(NULL), allowed_schemes_(kSign_RSASSA_PSS) {}
~SessionContext() {}
void Open();
@@ -110,7 +110,8 @@ class SessionContext {
bool GenerateRSASignature(const uint8_t* message,
size_t message_length,
uint8_t* signature,
size_t* signature_length);
size_t* signature_length,
RSA_Padding_Scheme padding_scheme);
bool ValidateMessage(const uint8_t* message,
size_t message_length,
const uint8_t* signature,
@@ -177,6 +178,7 @@ class SessionContext {
encryption_key_ = enc_key;
}
const std::vector<uint8_t>& encryption_key() { return encryption_key_; }
const uint32_t allowed_schemes() { return allowed_schemes_; }
void AddNonce(uint32_t nonce);
bool CheckNonce(uint32_t nonce);
@@ -198,6 +200,7 @@ class SessionContext {
SessionKeyTable session_keys_;
NonceTable nonce_table_;
RSA* rsa_key_;
uint32_t allowed_schemes_; // for RSA signatures.
time_t timer_start_;
CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext);
@@ -251,7 +254,7 @@ class CryptoEngine {
const uint8_t* cipher_data,
size_t cipher_data_length,
bool is_encrypted,
void* clear_data,
uint8_t* clear_data,
BufferType buffer_type);
private:

View File

@@ -18,6 +18,9 @@
namespace wvoec_mock {
const WidevineKeybox kDefaultKeybox = {
// change to #if 0 for test provisioning server with mock library
#if 1
// Sample keybox used for test vectors
{
// deviceID
@@ -47,6 +50,38 @@ const WidevineKeybox kDefaultKeybox = {
// Crc
0x0a, 0x7a, 0x2c, 0x35,
}
#else
// Test keybox for temporary CAST provisioning server
{
// deviceID
0x61, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // a1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ........
}, {
// key
0x92, 0x13, 0xa7, 0xb0, 0x0e, 0xd9, 0x2c, 0xb0,
0xba, 0x61, 0xc1, 0x89, 0x1f, 0x45, 0x34, 0x4a,
}, {
// data
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, 0x04,
0x20, 0x8b, 0xf0, 0xba, 0x89, 0x39, 0x73, 0xb6,
0x59, 0x82, 0x62, 0xa4, 0x72, 0x0c, 0xfe, 0xf4,
0x70, 0xa7, 0x0a, 0xc6, 0xe5, 0x7c, 0x5e, 0x04,
0x43, 0x8f, 0xa2, 0x87, 0x2b, 0xe1, 0x01, 0x67,
0xba, 0x04, 0x99, 0x73, 0xe1, 0x92, 0x6e, 0x6e,
0x9a, 0xf7, 0x67, 0x4e, 0xcd, 0xff, 0xb8, 0x43,
0xc0, 0xb7, 0xa5, 0x5e, 0xc4, 0xd7, 0x3f, 0x35,
0xf3, 0xc1, 0x84, 0x22, 0xe6, 0xf8, 0x2e, 0xfc,
}, {
// magic
0x6b, 0x62, 0x6f, 0x78,
}, {
// Crc
0x74, 0x57, 0x35, 0x2f,
}
#endif
};
WvKeybox::WvKeybox() : valid_(false) {

View File

@@ -895,7 +895,7 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(OEMCrypto_SESSION session,
size_t message_length,
uint8_t* signature,
size_t* signature_length,
RSA_Padding_Scheme algorithm) {
RSA_Padding_Scheme padding_scheme) {
if (trace_all_calls) {
printf("-- OEMCryptoResult OEMCrypto_GenerateRSASignature()\n");
dump_hex("message", message, message_length);
@@ -928,15 +928,11 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(OEMCrypto_SESSION session,
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
if (algorithm != kSign_RSASSA_PSS) {
LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_NOT_IMPLEMENTED]");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
if (session_ctx->GenerateRSASignature(message,
message_length,
signature,
signature_length)) {
signature_length,
padding_scheme)) {
if (trace_all_calls) {
dump_hex("signature", signature, *signature_length);
}
@@ -971,6 +967,11 @@ OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
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(mac_key_context,

File diff suppressed because it is too large Load Diff