Merge OEMCrypto KDF and usage functions

Since KDF functions are only used right before specific functions, this
merges them to simplify internal state within OEMCrypto.

Fixes: 299527712
Change-Id: I426cfcdc102bd73cf65cd809b213da2474f44b34
This commit is contained in:
Jacob Trimble
2023-04-13 18:37:26 +00:00
committed by Robert Shih
parent b04fda2908
commit 488a4647db
21 changed files with 567 additions and 634 deletions

View File

@@ -605,7 +605,7 @@ typedef enum OEMCrypto_SignatureHashAlgorithm {
#define OEMCrypto_RewrapDeviceRSAKey _oecc18
#define OEMCrypto_LoadDeviceRSAKey _oecc19
#define OEMCrypto_GenerateRSASignature_V8 _oecc20
#define OEMCrypto_DeriveKeysFromSessionKey _oecc21
#define OEMCrypto_DeriveKeysFromSessionKey_V18 _oecc21
#define OEMCrypto_APIVersion _oecc22
#define OEMCrypto_SecurityLevel_V16 _oecc23
#define OEMCrypto_Generic_Encrypt_V17 _oecc24
@@ -669,13 +669,13 @@ typedef enum OEMCrypto_SignatureHashAlgorithm {
#define OEMCrypto_LoadEntitledContentKeys_V16 _oecc92
#define OEMCrypto_CopyBuffer _oecc93
#define OEMCrypto_MaximumUsageTableHeaderSize _oecc94
#define OEMCrypto_GenerateDerivedKeys _oecc95
#define OEMCrypto_GenerateDerivedKeys_V18 _oecc95
#define OEMCrypto_PrepAndSignLicenseRequest _oecc96
#define OEMCrypto_PrepAndSignRenewalRequest _oecc97
#define OEMCrypto_PrepAndSignProvisioningRequest _oecc98
#define OEMCrypto_LoadLicense _oecc99
#define OEMCrypto_LoadLicense_V18 _oecc99
#define OEMCrypto_LoadRenewal _oecc101
#define OEMCrypto_LoadProvisioning _oecc102
#define OEMCrypto_LoadProvisioning_V18 _oecc102
#define OEMCrypto_LoadOEMPrivateKey _oecc103
#define OEMCrypto_GetOEMPublicCertificate _oecc104
#define OEMCrypto_DecryptCENC_V17 _oecc105
@@ -716,6 +716,9 @@ typedef enum OEMCrypto_SignatureHashAlgorithm {
#define OEMCrypto_GetDeviceSignedCsrPayload _oecc141
#define OEMCrypto_FactoryInstallBCCSignature _oecc142
#define OEMCrypto_SetDecryptHash _oecc143
#define OEMCrypto_LoadLicense _oecc144
#define OEMCrypto_LoadProvisioning _oecc145
#define OEMCrypto_LoadProvisioningCast _oecc146
// clang-format on
/// @addtogroup initcontrol
@@ -953,159 +956,6 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session);
*/
OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session);
/**
* Generates three secondary keys, mac_key[server], mac_key[client], and
* encrypt_key, for handling signing and content key decryption under the
* license server protocol for CENC.
*
* Refer to the Key Derivation section above for more details. This function
* computes the AES-128-CMAC of the enc_key_context and stores it in secure
* memory as the encrypt_key. It then computes four cycles of AES-128-CMAC of
* the mac_key_context and stores it in the mac_keys -- the first two cycles
* generate the mac_key[server] and the second two cycles generate the
* mac_key[client]. These two keys will be stored until the next call to
* OEMCrypto_LoadLicense(). The device key from the keybox is used as the key
* for the AES-128-CMAC.
*
* @param[in] session: handle for the session to be used.
* @param[in] mac_key_context: pointer to memory containing context data for
* computing the HMAC generation key.
* @param[in] mac_key_context_length: length of the HMAC key context data, in
* bytes.
* @param[in] enc_key_context: pointer to memory containing context data for
* computing the encryption key.
* @param[in] enc_key_context_length: length of the encryption key context data,
* in bytes.
*
* Results:
* mac_key[server]: the 256 bit mac key is generated and stored in secure
* memory.
* mac_key[client]: the 256 bit mac key is generated and stored in secure
* memory.
* enc_key: the 128 bit encryption key is generated and stored in secure
* memory.
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_NO_DEVICE_KEY
* @retval OEMCrypto_ERROR_INVALID_SESSION
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
* @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
*
* @buffer_size
* OEMCrypto shall support mac_key_context and enc_key_context sizes as
* described in the section OEMCrypto_ResourceRatingTier() for messages. The
* key derivation context is about 25 bytes prepended to the request message.
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffers are
* too large.
*
* @threading
* This is a "Session Function" and may be called simultaneously with session
* functions for other sessions but not simultaneously with other functions
* for this session. It will not be called simultaneously with initialization
* or usage table functions. It is as if the CDM holds a write lock for this
* session, and a read lock on the OEMCrypto system.
*
* @version
* This method changed in API version 12.
*/
OEMCryptoResult OEMCrypto_GenerateDerivedKeys(
OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* mac_key_context,
size_t mac_key_context_length,
const OEMCrypto_SharedMemory* enc_key_context,
size_t enc_key_context_length);
/**
* Generates three secondary keys, mac_key[server], mac_key[client] and
* encrypt_key, for handling signing and content key decryption under the
* license server protocol for CENC.
*
* This function is similar to OEMCrypto_GenerateDerivedKeys(), except that it
* uses a session key to generate the secondary keys instead of the Widevine
* Keybox device key. These three keys will be stored in secure memory until
* the next call to LoadLicense or LoadProvisioning.
*
* If the session's private key is an RSA key, then the session key is passed
* in encrypted by the device RSA public key as the derivation_key, and must
* be decrypted with the RSA private key before use.
*
* If the sesion's private key is an ECC key, then the session key is the
* SHA256 of the shared secret key calculated by ECDH between the device's
* ECC private key and the derivation_key. See the document "OEMCrypto
* Elliptic Curve Support" for details.
*
* Once the enc_key and mac_keys have been generated, all calls to
* OEMCrypto_LoadLicense() proceed in the same manner for license requests using
* RSA or using a Widevine keybox token.
*
* This function is also used to derive keys before processing a Cast
* Certificate provisioning response in OEMCrypto_LoadProvisioning().
* See [Cast Receiver](../../cast) for more details.
*
* @verification
* If the RSA key's allowed_schemes is not kSign_RSASSA_PSS, then no keys are
* derived and the error OEMCrypto_ERROR_INVALID_KEY is returned. An RSA
* key cannot be used for both deriving session keys and also for PKCS1
* signatures.
*
* @param[in] session: handle for the session to be used.
* @param[in] derivation_key: session key, encrypted with the public RSA key
* (from the DRM certifcate) using RSA-OAEP.
* @param[in] derivation_key_length: length of derivation_key, in bytes.
* @param[in] mac_key_context: pointer to memory containing context data for
* computing the HMAC generation key.
* @param[in] mac_key_context_length: length of the HMAC key context data, in
* bytes.
* @param[in] enc_key_context: pointer to memory containing context data for
* computing the encryption key.
* @param[in] enc_key_context_length: length of the encryption key context data,
* in bytes.
*
* Results:
* mac_key[server]: the 256 bit mac key is generated and stored in secure
* memory.
* mac_key[client]: the 256 bit mac key is generated and stored in secure
* memory.
* enc_key: the 128 bit encryption key is generated and stored in secure
* memory.
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED
* @retval OEMCrypto_ERROR_INVALID_SESSION
* @retval OEMCrypto_ERROR_INVALID_CONTEXT
* @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
* @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
*
* @buffer_size
* OEMCrypto shall support mac_key_context and enc_key_context sizes as
* described in the section OEMCrypto_ResourceRatingTier() for messages. The
* key derivation context is about 25 bytes prepended to the request message.
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffers are
* too large.
*
* @threading
* This is a "Session Function" and may be called simultaneously with session
* functions for other sessions but not simultaneously with other functions
* for this session. It will not be called simultaneously with initialization
* or usage table functions. It is as if the CDM holds a write lock for this
* session, and a read lock on the OEMCrypto system.
*
* @version
* This method changed in API version 16.
*/
OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey(
OEMCrypto_SESSION session, const uint8_t* derivation_key,
size_t derivation_key_length, const OEMCrypto_SharedMemory* mac_key_context,
size_t mac_key_context_length,
const OEMCrypto_SharedMemory* enc_key_context,
size_t enc_key_context_length);
/**
* Generates a 32-bit nonce to detect possible replay attack on the key
* control block. The nonce is stored in secure memory and will be used in
@@ -1308,7 +1158,11 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest(
/**
* Install a set of keys for performing decryption in the current session.
*
* First, OEMCrypto shall verify the signature of the message using
* First, OEMCrypto should generate three secondary keys, mac_key[server],
* mac_key[client], and encryption_key, for handling signing and content key
* derivation under the license server protocol for CENC.
*
* Then OEMCrypto shall verify the signature of the message using
* HMAC-SHA256 with the derived mac_key[server]. The signature verification
* shall use a constant-time algorithm (a signature mismatch will always take
* the same time as a successful comparison). The signature is over the
@@ -1317,9 +1171,6 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest(
* OEMCrypto_ERROR_SIGNATURE_FAILURE. Otherwise, add the keys to the session
* context.
*
* NOTE: The calling software must have previously established the mac_keys
* and encrypt_key with a call to OEMCrypto_DeriveKeysFromSessionKey().
*
* Refer to the Verification of Messages from a Server section above for more
* details.
*
@@ -1517,6 +1368,10 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest(
* OEMCrypto_ERROR_INSUFFICIENT_HDCP at that time.
*
* @param[in] session: crypto session identifier.
* @param[in] context: pointer to memory containing context data.
* @param[in] context_length: length of the context, in bytes.
* @param[in] derivation_key: pointer to memory containing derivation key.
* @param[in] derivation_key_length: length of the derivation_key, in bytes.
* @param[in] message: pointer to memory containing data.
* @param[in] message_length: length of the message, in bytes.
* @param[in] core_message_length: length of the core submessage, in bytes.
@@ -1537,6 +1392,8 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest(
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
* @retval OEMCrypto_ERROR_LICENSE_RELOAD
* @retval OEMCrypto_ERROR_KEY_EXPIRED
* @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
* @retval OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED
*
* @buffer_size
* OEMCrypto shall support message sizes as described in the section
@@ -1554,12 +1411,11 @@ OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest(
* @version
* This method changed in API version 16.
*/
OEMCryptoResult OEMCrypto_LoadLicense(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
size_t core_message_length,
const uint8_t* signature,
size_t signature_length);
OEMCryptoResult OEMCrypto_LoadLicense(
OEMCrypto_SESSION session, const uint8_t* context, size_t context_length,
const uint8_t* derivation_key, size_t derivation_key_length,
const uint8_t* message, size_t message_length, size_t core_message_length,
const uint8_t* signature, size_t signature_length);
/**
* Updates the clock values and resets the renewal timer for the current
@@ -3783,9 +3639,7 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(void);
* The message size limit applies to all functions that sign or verify a
* message: OEMCrypto_PrepAndSignLicenseRequest(),
* OEMCrypto_PrepAndSignRenewalRequest(),
* OEMCrypto_PrepAndSignProvisioningRequest(), and OEMCrypto_LoadLicense(). A
* request message is also used as the context buffer in
* OEMCrypto_DeriveKeysFromSessionKey() and OEMCrypto_GenerateDerivedKeys().
* OEMCrypto_PrepAndSignProvisioningRequest(), and OEMCrypto_LoadLicense().
*
*
* @return
@@ -3918,24 +3772,19 @@ OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm(
/**
* Load and parse a provisioning response, and then rewrap the private key
* for storage on the filesystem. We recommend that the OEM use an encryption
* key and signing key generated using an algorithm at least as strong as
* that in GenerateDerivedKeys.
* for storage on the filesystem. We recommend that the OEM use a strong
* encryption key and signing key algorithm.
*
* First, OEMCrypto shall verify the signature of the message using the correct
* algorithm depending on if the device supports Provisioning 2.0, 3.0 or 4.0.
*
* For Provisioning 2.0, OEMCrypto shall verify the signature of the message
* using HMAC-SHA256 with the derived mac_key[server]. The signature
* verification shall use a constant-time algorithm (a signature mismatch will
* always take the same time as a successful comparison). The signature is over
* the entire message buffer starting at message with length message_length. If
* the signature verification fails, ignore all other arguments and return
* OEMCrypto_ERROR_SIGNATURE_FAILURE.
*
* NOTE: The calling software must have previously established the mac_keys
* and encrypt_key with a call to OEMCrypto_DeriveKeysFromSessionKey() or
* OEMCrypto_GenerateDerivedKeys().
* For Provisioning 2.0, OEMCrypto shall use the provisioning request to derive
* mac_key[server] and verify the signature of the message using HMAC-SHA256.
* The signature verification shall use a constant-time algorithm (a signature
* mismatch will always take the same time as a successful comparison). The
* signature is over the entire message buffer starting at message with length
* message_length. If the signature verification fails, ignore all other
* arguments and return OEMCrypto_ERROR_SIGNATURE_FAILURE.
*
* For Provisioning 3.0 and 4.0, the signature is not verified.
*
@@ -3973,8 +3822,7 @@ OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm(
* 2. Verify that (in) wrapped_private_key_length is large enough to hold
* the rewrapped key, returning OEMCrypto_ERROR_SHORT_BUFFER otherwise.
* 3. Verify the message signature, using the derived signing key
* (mac_key[server]) from a previous call to
* OEMCrypto_GenerateDerivedKeys() or OEMCrypto_DeriveKeysFromSessionKey().
* (mac_key[server]).
* 4. The function ODK_ParseProvisioning is called to parse the message.
* 5. Decrypt enc_private_key in the buffer private_key using the session's
* derived encryption key (enc_key). Use enc_private_key_iv as the initial
@@ -4011,6 +3859,8 @@ OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm(
* and the size of the wrapped key to wrapped_private_key_length.
*
* @param[in] session: crypto session identifier.
* @param[in] provision_request: the initial provisioning request.
* @param[in] provision_request_length: length of provision_request, in bytes.
* @param[in] message: pointer to memory containing data.
* @param[in] message_length: length of the message, in bytes.
* @param[in] core_message_length: length of the core submessage, in bytes.
@@ -4052,15 +3902,79 @@ OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm(
* This method changed in API version 16.
*/
OEMCryptoResult OEMCrypto_LoadProvisioning(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
size_t core_message_length, const uint8_t* signature,
OEMCrypto_SESSION session, const uint8_t* provision_request,
size_t provision_request_length, const uint8_t* message,
size_t message_length, size_t core_message_length, const uint8_t* signature,
size_t signature_length, uint8_t* wrapped_private_key,
size_t* wrapped_private_key_length);
/**
* Load and parse a provisioning response, and then rewrap the private key. We
* recommend that the OEM use a strong encryption key and signing key algorithm.
*
* This is the same as OEMCrypto_LoadProvisioning except it is for CAST devices.
* This should return OEMCrypto_ERROR_NOT_IMPLEMENTED for non-CAST devices.
*
* @param[in] session: crypto session identifier.
* @param[in] derivation_key: session key, encrypted with the public RSA key
* (from the DRM certifcate) using RSA-OAEP.
* @param[in] derivation_key_length: length of derivation_key, in bytes.
* @param[in] provision_request: the initial provisioning request.
* @param[in] provision_request_length: length of provision_request, in bytes.
* @param[in] message: pointer to memory containing data.
* @param[in] message_length: length of the message, in bytes.
* @param[in] core_message_length: length of the core submessage, in bytes.
* @param[in] signature: pointer to memory containing the signature.
* @param[in] signature_length: length of the signature, in bytes.
* @param[out] wrapped_private_key: pointer to buffer in which encrypted RSA or
* ECC private key should be stored. May be null on the first call in order
* to find required buffer size.
* @param[in,out] wrapped_private_key_length: (in) length of the encrypted
* private key, in bytes. (out) actual length of the encrypted private key
*
* @retval OEMCrypto_SUCCESS success
* @retval OEMCrypto_ERROR_NO_DEVICE_KEY
* @retval OEMCrypto_ERROR_INVALID_SESSION
* @retval OEMCrypto_ERROR_INVALID_KEY
* @retval OEMCrypto_ERROR_SIGNATURE_FAILURE
* @retval OEMCrypto_ERROR_INVALID_NONCE
* @retval OEMCrypto_ERROR_SHORT_BUFFER
* @retval OEMCrypto_ERROR_INSUFFICIENT_RESOURCES
* @retval OEMCrypto_ERROR_UNKNOWN_FAILURE
* @retval OEMCrypto_ERROR_BUFFER_TOO_LARGE
* @retval OEMCrypto_ERROR_SESSION_LOST_STATE
* @retval OEMCrypto_ERROR_SYSTEM_INVALIDATED
* @retval OEMCrypto_ERROR_NOT_IMPLEMENTED
*
* @buffer_size
* OEMCrypto shall support message sizes as described in the section
* OEMCrypto_ResourceRatingTier().
* OEMCrypto shall return OEMCrypto_ERROR_BUFFER_TOO_LARGE if the buffer is
* larger than the supported size.
*
* @threading
* This is a "Session Function" and may be called simultaneously with session
* functions for other sessions but not simultaneously with other functions
* for this session. It will not be called simultaneously with initialization
* or usage table functions. It is as if the CDM holds a write lock for this
* session, and a read lock on the OEMCrypto system.
*
* @version
* This method was added in API version 19.
*/
OEMCryptoResult OEMCrypto_LoadProvisioningCast(
OEMCrypto_SESSION session, const uint8_t* derivation_key,
size_t derivation_key_length, const uint8_t* provision_request,
size_t provision_request_length, const uint8_t* message,
size_t message_length, size_t core_message_length, const uint8_t* signature,
size_t signature_length, uint8_t* wrapped_private_key,
size_t* wrapped_private_key_length);
/**
* Loads a wrapped RSA or ECC private key to secure memory for use by this
* session in future calls to OEMCrypto_PrepAndSignLicenseRequest() or
* OEMCrypto_DeriveKeysFromSessionKey(). The wrapped private key will be the
* OEMCrypto_LoadLicense(). The wrapped private key will be the
* one verified and wrapped by OEMCrypto_LoadProvisioning(). The private key
* should be stored in secure memory.
*
@@ -4068,7 +3982,7 @@ OEMCryptoResult OEMCrypto_LoadProvisioning(
* value will be loaded and stored with the RSA key, and the key may be used
* with calls to OEMCrypto_GenerateRSASignature(). If there was not a bit field
* wrapped with the RSA key, the key will be used for
* OEMCrypto_PrepAndSignLicenseRequest() or OEMCrypto_DeriveKeysFromSessionKey()
* OEMCrypto_PrepAndSignLicenseRequest() or OEMCrypto_LoadLicense()
*
* @verification
* The following checks should be performed. If any check fails, an error is
@@ -4228,8 +4142,7 @@ OEMCryptoResult OEMCrypto_GenerateRSASignature(
* message with length message_length.
*
* For a device that has a keybox, i.e. Provisioning 2.0, OEMCrypto will sign
* the request with the session's derived client mac key from the previous
* call to OEMCrypto_GenerateDerivedKeys().
* the request with the session's derived client mac key using the message.
*
* For Provisioning 3.0, i.e. a device that has a baked in OEM Certificate,
* OEMCrypto will sign the request with the private key associated with the OEM
@@ -5845,6 +5758,56 @@ OEMCryptoResult OEMCrypto_Generic_Verify_V17(
size_t buffer_length, OEMCrypto_Algorithm algorithm,
const OEMCrypto_SharedMemory* signature, size_t signature_length);
/**
* OEMCrypto_GenerateDerivedKeys_V18
* @deprecated
* Not required for the current version of OEMCrypto. Declared here to
* help with backward compatibility.
*/
OEMCryptoResult OEMCrypto_GenerateDerivedKeys_V18(
OEMCrypto_SESSION session, const OEMCrypto_SharedMemory* mac_key_context,
size_t mac_key_context_length,
const OEMCrypto_SharedMemory* enc_key_context,
size_t enc_key_context_length);
/**
* OEMCrypto_DeriveKeysFromSessionKey_V18
* @deprecated
* Not required for the current version of OEMCrypto. Declared here to
* help with backward compatibility.
*/
OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey_V18(
OEMCrypto_SESSION session, const uint8_t* derivation_key,
size_t derivation_key_length, const OEMCrypto_SharedMemory* mac_key_context,
size_t mac_key_context_length,
const OEMCrypto_SharedMemory* enc_key_context,
size_t enc_key_context_length);
/**
* OEMCrypto_LoadLicense_V18
* @deprecated
* Not required for the current version of OEMCrypto. Declared here to
* help with backward compatibility.
*/
OEMCryptoResult OEMCrypto_LoadLicense_V18(OEMCrypto_SESSION session,
const uint8_t* message,
size_t message_length,
size_t core_message_length,
const uint8_t* signature,
size_t signature_length);
/**
* OEMCrypto_LoadProvisioning_V18
* @deprecated
* Not required for the current version of OEMCrypto. Declared here to
* help with backward compatibility.
*/
OEMCryptoResult OEMCrypto_LoadProvisioning_V18(
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
size_t core_message_length, const uint8_t* signature,
size_t signature_length, uint8_t* wrapped_private_key,
size_t* wrapped_private_key_length);
/****************************************************************************/
/****************************************************************************/

View File

@@ -37,6 +37,23 @@ using namespace std;
namespace wvoec {
namespace {
std::vector<uint8_t> CreateContext(const char* prefix,
const std::vector<uint8_t>& context,
uint32_t suffix) {
std::vector<uint8_t> ret;
// +1 to include the null-terminator
ret.insert(ret.end(), prefix, prefix + strlen(prefix) + 1);
ret.insert(ret.end(), context.begin(), context.end());
const uint32_t suffix_net = htonl(suffix);
auto* ptr = reinterpret_cast<const uint8_t*>(&suffix_net);
ret.insert(ret.end(), ptr, ptr + sizeof(suffix_net));
return ret;
}
} // namespace
void Encryptor::set_enc_key(const std::vector<uint8_t>& enc_key) {
enc_key_ = enc_key;
}
@@ -119,8 +136,21 @@ void KeyDeriver::DeriveKey(const uint8_t* key, size_t master_key_size,
// this function, then there is something wrong with the test program and its
// dependency on BoringSSL.
void KeyDeriver::DeriveKeys(const uint8_t* master_key, size_t master_key_size,
const vector<uint8_t>& mac_key_context,
const vector<uint8_t>& enc_key_context) {
const vector<uint8_t>& context) {
// TODO: Use ODK constants instead
DeriveKeys(master_key, master_key_size, context, "AUTHENTICATION",
"ENCRYPTION");
}
void KeyDeriver::DeriveKeys(const uint8_t* master_key, size_t master_key_size,
const vector<uint8_t>& context,
const char* mac_label, const char* enc_label) {
// TODO: Use ODK constants instead
const std::vector<uint8_t> mac_key_context =
CreateContext(mac_label, context, 0x200);
const std::vector<uint8_t> enc_key_context =
CreateContext(enc_label, context, 0x80);
// Generate derived key for mac key
std::vector<uint8_t> mac_key_part2;
DeriveKey(master_key, master_key_size, mac_key_context, 1, &mac_key_server_);

View File

@@ -73,8 +73,10 @@ class KeyDeriver : public Encryptor {
// Generate mac and enc keys give the master key.
void DeriveKeys(const uint8_t* master_key, size_t master_key_size,
const std::vector<uint8_t>& mac_key_context,
const std::vector<uint8_t>& enc_key_context);
const std::vector<uint8_t>& context);
void DeriveKeys(const uint8_t* master_key, size_t master_key_size,
const std::vector<uint8_t>& context, const char* mac_label,
const char* enc_label);
// Sign the buffer with server's mac key.
void ServerSignBuffer(const uint8_t* data, size_t data_length,
std::vector<uint8_t>* signature) const;

View File

@@ -234,7 +234,8 @@ RoundTrip<CoreRequest, PrepAndSignRequest, CoreResponse, ResponseData>::
// verified by the server. This simulates that.
size_t gen_signature_length = 0;
size_t core_message_length = 0;
constexpr size_t small_size = 42; // arbitrary.
const vector<uint8_t> context = session()->GetDefaultContext();
const size_t small_size = context.size(); // arbitrary.
if (RequestHasNonce()) {
session()->GenerateNonce();
}
@@ -252,7 +253,10 @@ RoundTrip<CoreRequest, PrepAndSignRequest, CoreResponse, ResponseData>::
size_t message_size =
std::max(required_message_size_, core_message_length + small_size);
vector<uint8_t> data(message_size);
for (size_t i = 0; i < data.size(); i++) data[i] = i & 0xFF;
memcpy(&data[core_message_length], context.data(), context.size());
for (size_t i = context.size() + core_message_length; i < data.size(); i++) {
data[i] = i & 0xFF;
}
if (ShouldGenerateCorpus()) {
WriteRequestApiCorpus<CoreRequest>(gen_signature_length,
core_message_length, data);
@@ -348,29 +352,37 @@ void ProvisioningRoundTrip::PrepareSession(
const wvoec::WidevineKeybox& keybox) {
ASSERT_NO_FATAL_FAILURE(session_->open());
if (global_features.provisioning_method == OEMCrypto_Keybox) {
session_->GenerateDerivedKeysFromKeybox(keybox);
encryptor_ = session_->key_deriver();
keybox_ = &keybox;
} else if (global_features.provisioning_method ==
OEMCrypto_BootCertificateChain) {
// TODO(chelu): change this to CSR provisioning.
session_->LoadOEMCert(true);
session_->GenerateRsaSessionKey(&message_key_, &encrypted_message_key_);
encryptor_.set_enc_key(message_key_);
session_->GenerateRsaSessionKey();
encryptor_.set_enc_key(session_->session_key());
} else {
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_OEMCertificate);
session_->LoadOEMCert(true);
session_->GenerateRsaSessionKey(&message_key_, &encrypted_message_key_);
encryptor_.set_enc_key(message_key_);
session_->GenerateRsaSessionKey();
encryptor_.set_enc_key(session_->session_key());
}
}
void ProvisioningRoundTrip::VerifyRequestSignature(
const vector<uint8_t>& data, const vector<uint8_t>& generated_signature,
size_t /* core_message_length */) {
if (global_features.provisioning_method == OEMCrypto_OEMCertificate) {
size_t core_message_length) {
if (keybox_ == nullptr) {
session()->VerifyRsaSignature(data, generated_signature.data(),
generated_signature.size(), kSign_RSASSA_PSS);
} else {
// Setup the derived keys using the proto message (ignoring the core
// message).
ASSERT_LE(core_message_length, data.size());
const std::vector<uint8_t> base_message(data.begin() + core_message_length,
data.end());
session()->GenerateDerivedKeysFromKeybox(*keybox_, base_message);
encryptor_ = session()->key_deriver();
request_ = base_message;
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox);
ASSERT_EQ(HMAC_SHA256_SIGNATURE_SIZE, generated_signature.size());
std::vector<uint8_t> expected_signature;
@@ -403,11 +415,11 @@ void ProvisioningRoundTrip::CreateDefaultResponse() {
response_data_.rsa_key_length = encoded_rsa_key_.size();
}
response_data_.nonce = session_->nonce();
if (encrypted_message_key_.size() > 0) {
ASSERT_LE(encrypted_message_key_.size(), kMaxTestRSAKeyLength);
memcpy(response_data_.enc_message_key, encrypted_message_key_.data(),
encrypted_message_key_.size());
response_data_.enc_message_key_length = encrypted_message_key_.size();
if (session_->enc_session_key().size() > 0) {
ASSERT_LE(session_->enc_session_key().size(), kMaxTestRSAKeyLength);
memcpy(response_data_.enc_message_key, session_->enc_session_key().data(),
session_->enc_session_key().size());
response_data_.enc_message_key_length = session_->enc_session_key().size();
} else {
response_data_.enc_message_key_length = 0;
}
@@ -463,9 +475,6 @@ void ProvisioningRoundTrip::SignResponse() {
memcpy(encrypted_response_.data() + serialized_core_message_.size(),
reinterpret_cast<const uint8_t*>(&encrypted_response_data_),
sizeof(encrypted_response_data_));
if (global_features.provisioning_method == OEMCrypto_OEMCertificate) {
session()->GenerateDerivedKeysFromSessionKey();
}
session()->key_deriver().ServerSignBuffer(encrypted_response_.data(),
encrypted_response_.size(),
&response_signature_);
@@ -532,10 +541,10 @@ OEMCryptoResult ProvisioningRoundTrip::LoadResponseNoRetry(
EXPECT_NE(session, nullptr);
VerifyEncryptAndSignResponseLengths();
return OEMCrypto_LoadProvisioning(
session->session_id(), encrypted_response_.data(),
encrypted_response_.size(), serialized_core_message_.size(),
response_signature_.data(), response_signature_.size(),
wrapped_rsa_key_.data(), wrapped_key_length);
session->session_id(), request_.data(), request_.size(),
encrypted_response_.data(), encrypted_response_.size(),
serialized_core_message_.size(), response_signature_.data(),
response_signature_.size(), wrapped_rsa_key_.data(), wrapped_key_length);
}
void ProvisioningRoundTrip::VerifyLoadFailed() {
@@ -754,11 +763,13 @@ OEMCryptoResult Provisioning40CastRoundTrip::LoadResponseNoRetry(
Session* session, size_t* wrapped_key_length) {
EXPECT_NE(session, nullptr);
VerifyEncryptAndSignResponseLengths();
return OEMCrypto_LoadProvisioning(
session->session_id(), encrypted_response_.data(),
encrypted_response_.size(), serialized_core_message_.size(),
response_signature_.data(), response_signature_.size(),
wrapped_rsa_key_.data(), wrapped_key_length);
const std::vector<uint8_t> context = session->GetDefaultContext();
return OEMCrypto_LoadProvisioningCast(
session->session_id(), session->enc_session_key().data(),
session->enc_session_key().size(), context.data(), context.size(),
encrypted_response_.data(), encrypted_response_.size(),
serialized_core_message_.size(), response_signature_.data(),
response_signature_.size(), wrapped_rsa_key_.data(), wrapped_key_length);
}
void LicenseRoundTrip::VerifyRequestSignature(
@@ -1118,6 +1129,8 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session,
core_response_.key_array_length * sizeof(*core_response_.key_array));
}
const vector<uint8_t> context = session->GetDefaultContext();
// Some tests adjust the offset to be beyond the length of the message. Here,
// we create a duplicate of the main message buffer so that these offsets do
// not point to garbage data. The goal is to make sure OEMCrypto is verifying
@@ -1134,7 +1147,9 @@ OEMCryptoResult LicenseRoundTrip::LoadResponse(Session* session,
reinterpret_cast<const uint8_t*>(&encrypted_response_data_) +
sizeof(encrypted_response_data_));
OEMCryptoResult result = OEMCrypto_LoadLicense(
session->session_id(), double_message.data(), encrypted_response_.size(),
session->session_id(), context.data(), context.size(),
session->enc_session_key().data(), session->enc_session_key().size(),
double_message.data(), encrypted_response_.size(),
serialized_core_message_.size(), response_signature_.data(),
response_signature_.size());
if (verify_keys && result == OEMCrypto_SUCCESS) {
@@ -1659,63 +1674,42 @@ void Session::GenerateNonce(int* error_counter) {
}
}
void Session::FillDefaultContext(vector<uint8_t>* mac_context,
vector<uint8_t>* enc_context) {
/* Context strings
* These context strings are normally created by the CDM layer
vector<uint8_t> Session::GetDefaultContext() {
/* Context string
* This context string is normally created by the CDM layer
* from a license request message.
* They are used to test MAC and ENC key generation.
*/
*mac_context = wvutil::a2b_hex(
"41555448454e5449434154494f4e000a4c08001248000000020000101907d9ff"
"de13aa95c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e5873"
"4930acebe899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a"
"230a14080112100915007caa9b5931b76a3a85f046523e10011a093938373635"
"34333231180120002a0c31383836373837343035000000000200");
*enc_context = wvutil::a2b_hex(
"454e4352595054494f4e000a4c08001248000000020000101907d9ffde13aa95"
"c122678053362136bdf8408f8276e4c2d87ec52b61aa1b9f646e58734930aceb"
"e899b3e464189a14a87202fb02574e70640bd22ef44b2d7e3912250a230a1408"
"0112100915007caa9b5931b76a3a85f046523e10011a09393837363534333231"
"180120002a0c31383836373837343035000000000080");
return wvutil::a2b_hex(
"0a4c08001248000000020000101907d9ffde13aa95c122678053362136bdf840"
"8f8276e4c2d87ec52b61aa1b9f646e58734930acebe899b3e464189a14a87202"
"fb02574e70640bd22ef44b2d7e3912250a230a14080112100915007caa9b5931"
"b76a3a85f046523e10011a09393837363534333231180120002a0c3138383637"
"38373430350000");
}
// This should only be called if the device uses Provisioning 2.0. A failure in
// this function is probably caused by a bad keybox.
void Session::GenerateDerivedKeysFromKeybox(
const wvoec::WidevineKeybox& keybox) {
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context);
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GenerateDerivedKeys(
session_id(), mac_context.data(), mac_context.size(),
enc_context.data(), enc_context.size()));
return GenerateDerivedKeysFromKeybox(keybox, GetDefaultContext());
}
void Session::GenerateDerivedKeysFromKeybox(
const wvoec::WidevineKeybox& keybox, const std::vector<uint8_t>& context) {
key_deriver_.DeriveKeys(keybox.device_key_, sizeof(keybox.device_key_),
mac_context, enc_context);
context);
}
void Session::GenerateDerivedKeysFromSessionKey() {
// Uses test certificate.
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
ASSERT_TRUE(public_rsa_ || public_ec_)
<< "No public RSA/ECC key loaded in test code";
// A failure here probably indicates that there is something wrong with the
// test program and its dependency on BoringSSL.
ASSERT_TRUE(GenerateSessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
FillDefaultContext(&mac_context, &enc_context);
// A failure here is probably caused by having the wrong RSA key loaded.
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
session_id(), enc_session_key.data(), enc_session_key.size(),
mac_context.data(), mac_context.size(), enc_context.data(),
enc_context.size()));
GenerateDerivedKeysFromSessionKey(GetDefaultContext());
}
key_deriver_.DeriveKeys(session_key.data(), session_key.size(), mac_context,
enc_context);
void Session::GenerateDerivedKeysFromSessionKey(
const std::vector<uint8_t>& context) {
// Uses test certificate.
ASSERT_TRUE(GenerateSessionKey());
key_deriver_.DeriveKeys(session_key_.data(), session_key_.size(), context);
}
void Session::TestDecryptCTR(bool get_fresh_key_handle_first,
@@ -2016,19 +2010,17 @@ void Session::VerifySignature(const vector<uint8_t>& message,
FAIL() << "No public RSA or ECC key loaded in test code";
}
bool Session::GenerateRsaSessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* enc_session_key) {
bool Session::GenerateRsaSessionKey() {
if (!public_rsa_) {
cerr << "No public RSA key loaded in test code\n";
return false;
}
*session_key = wvutil::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
*enc_session_key = public_rsa_->EncryptSessionKey(*session_key);
return !enc_session_key->empty();
session_key_ = wvutil::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1");
enc_session_key_ = public_rsa_->EncryptSessionKey(session_key_);
return !enc_session_key_.empty();
}
bool Session::GenerateEccSessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* ecdh_public_key_data) {
bool Session::GenerateEccSessionKey() {
if (!public_ec_) {
cerr << "No public ECC key loaded in test code\n";
return false;
@@ -2043,24 +2035,23 @@ bool Session::GenerateEccSessionKey(vector<uint8_t>* session_key,
<< util::EccCurveToString(curve) << std::endl;
return false;
}
*session_key = server_ephemeral_keys_[curve]->DeriveSessionKey(*public_ec_);
if (session_key->empty()) {
session_key_ = server_ephemeral_keys_[curve]->DeriveSessionKey(*public_ec_);
if (session_key_.empty()) {
return false;
}
*ecdh_public_key_data = server_ephemeral_keys_[curve]->SerializeAsPublicKey();
if (ecdh_public_key_data->empty()) {
session_key->clear();
enc_session_key_ = server_ephemeral_keys_[curve]->SerializeAsPublicKey();
if (enc_session_key_.empty()) {
session_key_.clear();
return false;
}
return true;
}
bool Session::GenerateSessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* key_material) {
bool Session::GenerateSessionKey() {
if (public_rsa_ != nullptr) {
return GenerateRsaSessionKey(session_key, key_material);
return GenerateRsaSessionKey();
} else if (public_ec_ != nullptr) {
return GenerateEccSessionKey(session_key, key_material);
return GenerateEccSessionKey();
}
cerr << "No public RSA or ECC key loaded in test code\n";
return false;

View File

@@ -276,7 +276,7 @@ class ProvisioningRoundTrip
const std::vector<uint8_t>& encoded_rsa_key)
: RoundTrip(session),
allowed_schemes_(kSign_RSASSA_PSS),
encryptor_(),
keybox_(nullptr),
encoded_rsa_key_(encoded_rsa_key) {}
// Prepare the session for signing the request.
virtual void PrepareSession(const wvoec::WidevineKeybox& keybox);
@@ -317,9 +317,9 @@ class ProvisioningRoundTrip
uint32_t allowed_schemes_;
Encryptor encryptor_;
std::vector<uint8_t> request_;
const wvoec::WidevineKeybox* keybox_;
// The message key used for Prov 3.0.
std::vector<uint8_t> message_key_;
std::vector<uint8_t> encrypted_message_key_;
std::vector<uint8_t> encoded_rsa_key_;
std::vector<uint8_t> wrapped_rsa_key_;
};
@@ -673,15 +673,17 @@ class Session {
// and try again if a nonce flood has been detected. If error_counter is
// not null, it will be incremented when a nonce flood is detected.
void GenerateNonce(int* error_counter = nullptr);
// Fill the vectors with test context which generate known mac and enc keys.
void FillDefaultContext(vector<uint8_t>* mac_context,
vector<uint8_t>* enc_context);
// Fill the vector with test context which generate known mac and enc keys.
std::vector<uint8_t> GetDefaultContext();
// Generate known mac and enc keys using OEMCrypto_GenerateDerivedKeys and
// also fill out enc_key_, mac_key_server_, and mac_key_client_.
void GenerateDerivedKeysFromKeybox(const wvoec::WidevineKeybox& keybox);
void GenerateDerivedKeysFromKeybox(const wvoec::WidevineKeybox& keybox,
const std::vector<uint8_t>& context);
// Generate known mac and enc keys using OEMCrypto_DeriveKeysFromSessionKey
// and also fill out enc_key_, mac_key_server_, and mac_key_client_.
void GenerateDerivedKeysFromSessionKey();
void GenerateDerivedKeysFromSessionKey(const std::vector<uint8_t>& context);
// Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption.
void TestDecryptCTR(bool get_fresh_key_handle_first = true,
OEMCryptoResult expected_result = OEMCrypto_SUCCESS,
@@ -747,17 +749,14 @@ class Session {
// Encrypts a known session key with public_rsa_ for use in future calls to
// OEMCrypto_DeriveKeysFromSessionKey or OEMCrypto_RewrapDeviceRSAKey30.
// The unencrypted session key is stored in session_key.
bool GenerateRsaSessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* enc_session_key);
bool GenerateRsaSessionKey();
// Derives a session key with public_ec_ and a ephemeral "server" ECC key
// for use in future calls to OEMCrypto_DeriveKeysFromSessionKey.
// The unencrypted session key is stored in session_key.
bool GenerateEccSessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* ecdh_public_key_data);
bool GenerateEccSessionKey();
// Based on the key type installed, call GenerateRsaSessionKey or
// GenerateEccSessionKey.
bool GenerateSessionKey(vector<uint8_t>* session_key,
vector<uint8_t>* key_material);
bool GenerateSessionKey();
// Calls OEMCrypto_RewrapDeviceRSAKey30 with the given provisioning response
// message. If force is true, we assert that the key loads successfully.
@@ -840,6 +839,11 @@ class Session {
// functions.
vector<uint8_t>& key_handle() { return key_handle_; }
const std::vector<uint8_t>& session_key() const { return session_key_; }
const std::vector<uint8_t>& enc_session_key() const {
return enc_session_key_;
}
const KeyDeriver& key_deriver() const { return key_deriver_; }
void set_mac_keys(const uint8_t* mac_keys) {
key_deriver_.set_mac_keys(mac_keys);
@@ -882,6 +886,8 @@ class Session {
vector<uint8_t> pst_report_buffer_;
MessageData license_ = {};
vector<uint8_t> key_handle_;
std::vector<uint8_t> session_key_;
std::vector<uint8_t> enc_session_key_;
vector<uint8_t> encrypted_usage_entry_;
uint32_t usage_entry_number_ = 0;

View File

@@ -49,7 +49,6 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, ForbidUseAsDRMCert) {
if (key_loaded_) {
// The other padding scheme should fail.
DisallowForbiddenPaddingDRMKey(kSign_RSASSA_PSS, 83);
DisallowDeriveKeys();
}
}

View File

@@ -51,26 +51,6 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate {
licenseRequest, signature.data(), signature_length, scheme));
}
void DisallowDeriveKeys() {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
s.GenerateNonce();
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
ASSERT_TRUE(s.GenerateRsaSessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
s.FillDefaultContext(&mac_context, &enc_context);
ASSERT_NE(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
s.session_id(), enc_session_key.data(),
enc_session_key.size(), mac_context.data(),
mac_context.size(), enc_context.data(), enc_context.size()));
}
// If force is true, we assert that the key loads successfully.
void LoadCastCertificateKey(bool force) {
if (!wvoec::global_features.cast_receiver) {

View File

@@ -472,9 +472,12 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyUnalignedMessageAPI16) {
license_messages_.encrypted_response_buffer().end());
// Thus, buffer[offset] is NOT word aligned.
const uint8_t* unaligned_message = &buffer[offset];
const std::vector<uint8_t> context = session_.GetDefaultContext();
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_LoadLicense(
session_.session_id(), unaligned_message,
session_.session_id(), context.data(), context.size(),
session_.enc_session_key().data(),
session_.enc_session_key().size(), unaligned_message,
license_messages_.encrypted_response_buffer().size(),
license_messages_.serialized_core_message().size(),
license_messages_.response_signature().data(),

View File

@@ -67,24 +67,6 @@ TEST_F(OEMCryptoKeyboxTest, ProductionKeyboxValid) {
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_IsKeyboxValid());
}
// This tests GenerateDerivedKeys with an 8k context.
TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
const size_t max_size = GetResourceValue(kLargeMessageSize);
vector<uint8_t> mac_context(max_size);
vector<uint8_t> enc_context(max_size);
// Stripe the data so the two vectors are not identical, and not all zeroes.
for (size_t i = 0; i < max_size; i++) {
mac_context[i] = i % 0x100;
enc_context[i] = (3 * i) % 0x100;
}
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_GenerateDerivedKeys(
s.session_id(), mac_context.data(), mac_context.size(),
enc_context.data(), enc_context.size()));
}
// This verifies that the device really does claim to have a certificate.
// It should be filtered out for devices that have a keybox.
TEST_F(OEMCryptoProv30Test, DeviceClaimsOEMCertificate) {
@@ -164,7 +146,6 @@ TEST_F(OEMCryptoProv30Test, GetCertOnlyAPI16) {
// Derive keys from the session key -- this should use the DRM Cert's key.
// It should NOT use the OEM Private key because that key should not have
// been loaded.
ASSERT_NO_FATAL_FAILURE(s.GenerateDerivedKeysFromSessionKey());
// Now fill a message and try to load it.
LicenseRoundTrip license_messages(&s);
license_messages.set_control(0);
@@ -745,14 +726,8 @@ TEST_F(OEMCryptoLoadsCertificate, SignProvisioningRequest) {
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
}
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
if (global_features.provisioning_method == OEMCrypto_OEMCertificate) {
s.LoadOEMCert(true);
} else {
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox);
s.GenerateDerivedKeysFromKeybox(keybox_);
}
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
ASSERT_NO_FATAL_FAILURE(provisioning_messages.PrepareSession(keybox_));
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
}
@@ -764,16 +739,10 @@ TEST_F(OEMCryptoLoadsCertificate, SignLargeProvisioningRequestAPI16) {
GTEST_SKIP() << "Test for non Prov 4.0 devices only.";
}
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
if (global_features.provisioning_method == OEMCrypto_OEMCertificate) {
s.LoadOEMCert(true);
} else {
EXPECT_EQ(global_features.provisioning_method, OEMCrypto_Keybox);
s.GenerateDerivedKeysFromKeybox(keybox_);
}
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
const size_t max_size = GetResourceValue(kLargeMessageSize);
provisioning_messages.set_message_size(max_size);
ASSERT_NO_FATAL_FAILURE(provisioning_messages.PrepareSession(keybox_));
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
}
@@ -788,7 +757,7 @@ TEST_F(OEMCryptoLoadsCertificate, CertificateProvision) {
}
Session s;
ProvisioningRoundTrip provisioning_messages(&s, encoded_rsa_key_);
provisioning_messages.PrepareSession(keybox_);
ASSERT_NO_FATAL_FAILURE(provisioning_messages.PrepareSession(keybox_));
ASSERT_NO_FATAL_FAILURE(provisioning_messages.SignAndVerifyRequest());
ASSERT_NO_FATAL_FAILURE(provisioning_messages.CreateDefaultResponse());
ASSERT_NO_FATAL_FAILURE(provisioning_messages.EncryptAndSignResponse());
@@ -1326,41 +1295,17 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) {
Session s;
ASSERT_NO_FATAL_FAILURE(s.open());
ASSERT_NO_FATAL_FAILURE(s.LoadWrappedRsaDrmKey(wrapped_drm_key_));
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
ASSERT_NO_FATAL_FAILURE(s.SetRsaPublicKeyFromPrivateKeyInfo(
encoded_rsa_key_.data(), encoded_rsa_key_.size()));
ASSERT_TRUE(s.GenerateRsaSessionKey(&session_key, &enc_session_key));
vector<uint8_t> mac_context;
vector<uint8_t> enc_context;
s.FillDefaultContext(&mac_context, &enc_context);
enc_session_key = wvutil::a2b_hex(
"7789c619aa3b9fa3c0a53f57a4abc6"
"02157c8aa57e3c6fb450b0bea22667fb"
"0c3200f9d9d618e397837c720dc2dadf"
"486f33590744b2a4e54ca134ae7dbf74"
"434c2fcf6b525f3e132262f05ea3b3c1"
"198595c0e52b573335b2e8a3debd0d0d"
"d0306f8fcdde4e76476be71342957251"
"e1688c9ca6c1c34ed056d3b989394160"
"cf6937e5ce4d39cc73d11a2e93da21a2"
"fa019d246c852fe960095b32f120c3c2"
"7085f7b64aac344a68d607c0768676ce"
"d4c5b2d057f7601921b453a451e1dea0"
"843ebfef628d9af2784d68e86b730476"
"e136dfe19989de4be30a4e7878efcde5"
"ad2b1254f80c0c5dd3cf111b56572217"
"b9f58fc1dacbf74b59d354a1e62cfa0e"
"bf");
LicenseRoundTrip license_messages(&s);
license_messages.SignAndVerifyRequest();
license_messages.CreateDefaultResponse();
start_time = clock.now();
count = 0;
do {
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
s.session_id(), enc_session_key.data(),
enc_session_key.size(), mac_context.data(),
mac_context.size(), enc_context.data(), enc_context.size()));
license_messages.LoadResponse(&s, /* verify_keys= */ false);
count++;
} while (clock.now() - start_time < kTestDuration);
delta_time = clock.now() - start_time;
@@ -1376,24 +1321,4 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) {
derive_keys_time);
}
// Test DeriveKeysFromSessionKey using the maximum size for the HMAC context.
TEST_F(OEMCryptoUsesCertificate, GenerateDerivedKeysLargeBuffer) {
vector<uint8_t> session_key;
vector<uint8_t> enc_session_key;
ASSERT_TRUE(session_.GenerateSessionKey(&session_key, &enc_session_key));
const size_t max_size = GetResourceValue(kLargeMessageSize);
vector<uint8_t> mac_context(max_size);
vector<uint8_t> enc_context(max_size);
// Stripe the data so the two vectors are not identical, and not all zeroes.
for (size_t i = 0; i < max_size; i++) {
mac_context[i] = i % 0x100;
enc_context[i] = (3 * i) % 0x100;
}
ASSERT_EQ(OEMCrypto_SUCCESS,
OEMCrypto_DeriveKeysFromSessionKey(
session_.session_id(), enc_session_key.data(),
enc_session_key.size(), mac_context.data(), mac_context.size(),
enc_context.data(), enc_context.size()));
}
} // namespace wvoec

View File

@@ -173,15 +173,11 @@ class OTAKeyboxProvisioningTest : public ::testing::Test, public SessionUtil {
TEST_F(OTAKeyboxProvisioningTest, BasicTest) {
OEMCryptoResult result = OEMCrypto_IsKeyboxValid();
if (result == OEMCrypto_SUCCESS) {
cout << " "
<< "Keybox valid after initialization. Skipping rest of test." << endl;
return;
GTEST_SKIP() << "Keybox valid after initialization. Skipping rest of test.";
}
if (result != OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING) {
cout << " "
<< "OTA Keybox functions not supported. Skipping rest of test."
<< endl;
return;
GTEST_SKIP()
<< "OTA Keybox functions not supported. Skipping rest of test.";
}
cout << " "
<< "OTA Keybox functions supported. Device needs provisioning." << endl;
@@ -235,28 +231,11 @@ TEST_F(OTAKeyboxProvisioningTest, BasicTest) {
const std::vector<uint8_t> model_key = GetModelKey(device_id);
#endif
// The server should derive the same set of keys as the client.
const std::string mac_label = "WV_SIGN";
std::vector<uint8_t> mac_context(mac_label.begin(), mac_label.end());
mac_context.push_back(0);
std::copy(cert.begin(), cert.end(), std::back_inserter(mac_context));
std::copy(device_id.begin(), device_id.end(),
std::back_inserter(mac_context));
uint32_t bit_size = MAC_KEY_SIZE * 8 * 2;
std::string bit_size_string = wvutil::EncodeUint32(bit_size);
std::copy(bit_size_string.begin(), bit_size_string.end(),
std::back_inserter(mac_context));
std::string enc_label = "WV_ENCRYPT";
std::vector<uint8_t> enc_context(enc_label.begin(), enc_label.end());
enc_context.push_back(0);
std::copy(cert.begin(), cert.end(), std::back_inserter(enc_context));
std::copy(device_id.begin(), device_id.end(),
std::back_inserter(enc_context));
bit_size = KEY_SIZE * 8;
bit_size_string = wvutil::EncodeUint32(bit_size);
std::copy(bit_size_string.begin(), bit_size_string.end(),
std::back_inserter(enc_context));
KeyDeriver keys;
keys.DeriveKeys(model_key.data(), model_key.size(), mac_context, enc_context);
std::vector<uint8_t> context = cert;
context.insert(context.end(), device_id.begin(), device_id.end());
keys.DeriveKeys(model_key.data(), model_key.size(), context, "WV_SIGN",
"WV_ENCRYPT");
const std::vector<uint8_t> message(
request.data(),
request.data() + request.size() - HMAC_SHA256_SIGNATURE_SIZE);