OEMCrypto v16.1
Merge of http://go/wvgerrit/93404 This CL updates the Widevine CDM to support OEMCrypto v16.1 Test: Tested in 16.2 CL Bug: 141247171 Change-Id: I69bd993500f6fb63bf6010c8b0250dc7acc3d71b
This commit is contained in:
@@ -1,14 +1,13 @@
|
||||
/*
|
||||
* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary
|
||||
* source code may only be used and distributed under the Widevine Master
|
||||
* License Agreement.
|
||||
*/
|
||||
/* Copyright 2019 Google LLC. All rights reserved. This file and proprietary */
|
||||
/* source code may only be used and distributed under the Widevine Master */
|
||||
/* License Agreement. */
|
||||
|
||||
#include "odk.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "odk.h"
|
||||
#include "odk_overflow.h"
|
||||
#include "odk_serialize.h"
|
||||
#include "odk_structs.h"
|
||||
@@ -18,6 +17,7 @@
|
||||
#define ODK_LICENSE_REQUEST_SIZE 20
|
||||
#define ODK_RENEWAL_REQUEST_SIZE 28
|
||||
#define ODK_PROVISIONING_REQUEST_SIZE 88
|
||||
#define OEC_API_VERSION 16
|
||||
|
||||
/* @ private odk functions */
|
||||
|
||||
@@ -35,7 +35,9 @@ static OEMCryptoResult ODK_PrepareRequest(uint8_t* buffer, size_t buffer_length,
|
||||
AllocateMessage(&msg, message_block);
|
||||
InitMessage(msg, buffer, *core_message_length);
|
||||
*core_message = (ODK_CoreMessage){
|
||||
message_type, 0, *nonce_values,
|
||||
message_type,
|
||||
0,
|
||||
*nonce_values,
|
||||
};
|
||||
|
||||
switch (message_type) {
|
||||
@@ -69,13 +71,21 @@ static OEMCryptoResult ODK_PrepareRequest(uint8_t* buffer, size_t buffer_length,
|
||||
|
||||
static OEMCryptoResult ODK_ParseResponse(const uint8_t* buf,
|
||||
size_t message_length,
|
||||
size_t core_message_length,
|
||||
uint32_t message_type,
|
||||
const ODK_NonceValues* nonce_values,
|
||||
ODK_CoreMessage* const core_message) {
|
||||
if (core_message_length > message_length) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
Message* msg = NULL;
|
||||
AllocateMessage(&msg, message_block);
|
||||
/* We initialize the message buffer with a size of the entire message
|
||||
* length. */
|
||||
InitMessage(msg, (uint8_t*)buf, message_length);
|
||||
SetSize(msg, message_length);
|
||||
/* The core message should be at the beginning of the buffer, and with a
|
||||
* shorter length. The core message is the part we are parsing. */
|
||||
SetSize(msg, core_message_length);
|
||||
|
||||
switch (message_type) {
|
||||
case ODK_License_Response_Type: {
|
||||
@@ -121,33 +131,44 @@ static OEMCryptoResult ODK_ParseResponse(const uint8_t* buf,
|
||||
OEMCryptoResult ODK_PrepareCoreLicenseRequest(
|
||||
uint8_t* message, size_t message_length, size_t* core_message_length,
|
||||
const ODK_NonceValues* nonce_values) {
|
||||
ODK_PreparedLicense license_request = {0};
|
||||
ODK_PreparedLicense license_request = {
|
||||
{0},
|
||||
};
|
||||
return ODK_PrepareRequest(message, message_length, core_message_length,
|
||||
ODK_License_Request_Type, nonce_values,
|
||||
&license_request.core_message);
|
||||
}
|
||||
|
||||
OEMCryptoResult ODK_PrepareCoreRenewalRequest(
|
||||
uint8_t* message, size_t message_length, size_t* core_message_length,
|
||||
const ODK_NonceValues* nonce_values,
|
||||
const ODK_ClockValues* clock_values, uint64_t system_time_seconds) {
|
||||
uint8_t* message, size_t message_length, size_t* core_message_size,
|
||||
const ODK_NonceValues* nonce_values, ODK_ClockValues* clock_values,
|
||||
uint64_t system_time_seconds) {
|
||||
ODK_RenewalMessage renewal_request = {
|
||||
{0},
|
||||
};
|
||||
if (odk_sub_overflow_u64(system_time_seconds,
|
||||
clock_values->time_of_first_decrypt,
|
||||
&renewal_request.playback_time)) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
if (clock_values->time_of_first_decrypt == 0) {
|
||||
/* It is OK to preemptively request a renewal before playback starts.
|
||||
* We'll treat this as asking for a renewal at playback time 0. */
|
||||
renewal_request.playback_time = 0;
|
||||
} else {
|
||||
/* Otherwise, playback_time is relative to the first decrypt. */
|
||||
if (odk_sub_overflow_u64(system_time_seconds,
|
||||
clock_values->time_of_first_decrypt,
|
||||
&renewal_request.playback_time)) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
}
|
||||
return ODK_PrepareRequest(message, message_length, core_message_length,
|
||||
/* Save time for this request so that we can verify the response. */
|
||||
clock_values->time_of_renewal_request = renewal_request.playback_time;
|
||||
return ODK_PrepareRequest(message, message_length, core_message_size,
|
||||
ODK_Renewal_Request_Type, nonce_values,
|
||||
&renewal_request.core_message);
|
||||
}
|
||||
|
||||
OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
|
||||
uint8_t* message, size_t message_length, size_t* core_message_length,
|
||||
const ODK_NonceValues* nonce_values,
|
||||
const uint8_t* device_id, size_t device_id_length) {
|
||||
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
|
||||
size_t device_id_length) {
|
||||
ODK_ProvisioningMessage provisioning_request = {
|
||||
{0},
|
||||
};
|
||||
@@ -165,54 +186,60 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest(
|
||||
|
||||
/* @@ parse request functions */
|
||||
|
||||
OEMCryptoResult ODK_ParseLicense(const uint8_t* message, size_t message_length,
|
||||
size_t core_message_length,
|
||||
bool initial_license_load,
|
||||
bool usage_entry_present,
|
||||
const uint8_t* request_hash,
|
||||
ODK_TimerLimits* timer_limits,
|
||||
ODK_ClockValues* clock_values,
|
||||
ODK_NonceValues* nonce_values,
|
||||
ODK_ParsedLicense* parsed_license) {
|
||||
|
||||
if (!nonce_values || !parsed_license) {
|
||||
OEMCryptoResult ODK_ParseLicense(
|
||||
const uint8_t* message, size_t message_length, size_t core_message_length,
|
||||
bool initial_license_load, bool usage_entry_present,
|
||||
const uint8_t* request_hash, ODK_TimerLimits* timer_limits,
|
||||
ODK_ClockValues* clock_values, ODK_NonceValues* nonce_values,
|
||||
ODK_ParsedLicense* parsed_license) {
|
||||
if (!message || !request_hash || !timer_limits || !clock_values ||
|
||||
!nonce_values || !parsed_license) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
ODK_LicenseResponse license_response = {{0}, parsed_license};
|
||||
OEMCryptoResult err = ODK_ParseResponse(
|
||||
message, message_length, ODK_License_Response_Type, NULL,
|
||||
&license_response.core_message);
|
||||
message, message_length, core_message_length, ODK_License_Response_Type,
|
||||
NULL, &license_response.core_message);
|
||||
|
||||
if (err != OEMCrypto_SUCCESS) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (license_response.core_message.nonce_values.api_version != 16) {
|
||||
/* This function should not be used for legacy licenses. */
|
||||
if (license_response.core_message.nonce_values.api_version !=
|
||||
OEC_API_VERSION) {
|
||||
return ODK_UNSUPPORTED_API;
|
||||
}
|
||||
|
||||
if (parsed_license->nonce_required) {
|
||||
if (initial_license_load) {
|
||||
if (nonce_values->nonce != license_response.core_message.nonce_values.nonce ||
|
||||
nonce_values->session_id != license_response.core_message.nonce_values.session_id) {
|
||||
if (nonce_values->nonce !=
|
||||
license_response.core_message.nonce_values.nonce ||
|
||||
nonce_values->session_id !=
|
||||
license_response.core_message.nonce_values.session_id) {
|
||||
return OEMCrypto_ERROR_INVALID_NONCE;
|
||||
}
|
||||
} else { /* !initial_license_load */
|
||||
nonce_values->nonce = license_response.core_message.nonce_values.nonce;
|
||||
nonce_values->session_id = license_response.core_message.nonce_values.session_id;
|
||||
nonce_values->session_id =
|
||||
license_response.core_message.nonce_values.session_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (initial_license_load &&
|
||||
memcmp(request_hash, parsed_license->request_hash, ODK_SHA256_HASH_SIZE)) {
|
||||
/* For v16, in order to be backwards compatible with a v15 license server,
|
||||
* OEMCrypto stores a hash of the core license request and only signs the
|
||||
* message body. Here, when we process the license response, we verify that
|
||||
* the server has the same hash of the core request. */
|
||||
if (initial_license_load && memcmp(request_hash, parsed_license->request_hash,
|
||||
ODK_SHA256_HASH_SIZE)) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
/* If the license has a provider session token (pst), then OEMCrypto should
|
||||
* have a usage entry loaded. */
|
||||
if (usage_entry_present && parsed_license->pst.length == 0) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
*timer_limits = parsed_license->timer_limits;
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -223,7 +250,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
|
||||
const ODK_TimerLimits* timer_limits,
|
||||
ODK_ClockValues* clock_values,
|
||||
uint64_t* timer_value) {
|
||||
if (!nonce_values || !timer_limits || !clock_values || !timer_value) {
|
||||
if (!message || !nonce_values || !timer_limits || !clock_values) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
@@ -231,8 +258,8 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
|
||||
{0},
|
||||
};
|
||||
OEMCryptoResult err = ODK_ParseResponse(
|
||||
message, message_length, ODK_Renewal_Response_Type, nonce_values,
|
||||
&renewal_response.core_message);
|
||||
message, message_length, core_message_length, ODK_Renewal_Response_Type,
|
||||
nonce_values, &renewal_response.core_message);
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
@@ -243,42 +270,37 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length,
|
||||
* Section: Renewal Message
|
||||
*/
|
||||
|
||||
uint64_t playback_timer = 0;
|
||||
if (odk_sub_overflow_u64(clock_values->time_when_timer_expires, system_time,
|
||||
&playback_timer)) {
|
||||
return ODK_TIMER_EXPIRED;
|
||||
/* If a renewal request is lost in transit, we should throw it out and create
|
||||
* a new one. We use the timestamp to make sure we have the latest request.
|
||||
*/
|
||||
if (clock_values->time_of_renewal_request < renewal_response.playback_time) {
|
||||
return ODK_STALE_RENEWAL;
|
||||
}
|
||||
|
||||
uint64_t time_since_playback_began = 0;
|
||||
uint64_t time_since_reset = 0;
|
||||
uint64_t time_since_message_signed = 0;
|
||||
/* ... or use clock_values->time_of_license_signed ? */
|
||||
if (odk_sub_overflow_u64(system_time, clock_values->time_of_first_decrypt,
|
||||
&time_since_playback_began) ||
|
||||
odk_sub_overflow_u64(timer_limits->renewal_playback_duration_seconds,
|
||||
playback_timer, &time_since_reset) ||
|
||||
odk_sub_overflow_u64(time_since_playback_began,
|
||||
renewal_response.playback_time,
|
||||
&time_since_message_signed) ||
|
||||
time_since_message_signed >= time_since_reset ||
|
||||
odk_add_overflow_u64(system_time,
|
||||
/* The timer value should be set to the renewal duration. */
|
||||
if (timer_value) {
|
||||
*timer_value = timer_limits->renewal_playback_duration_seconds;
|
||||
}
|
||||
|
||||
if (timer_limits->renewal_playback_duration_seconds == 0) {
|
||||
clock_values->time_when_timer_expires = 0;
|
||||
clock_values->timer_status = ODK_DISABLE_TIMER;
|
||||
return ODK_DISABLE_TIMER;
|
||||
}
|
||||
if (odk_add_overflow_u64(system_time,
|
||||
timer_limits->renewal_playback_duration_seconds,
|
||||
&clock_values->time_when_timer_expires)) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
/* todo: when to return ODK_DISABLE_TIMER */
|
||||
*timer_value = timer_limits->renewal_playback_duration_seconds;
|
||||
clock_values->timer_status = ODK_SET_TIMER;
|
||||
return ODK_SET_TIMER;
|
||||
}
|
||||
|
||||
OEMCryptoResult ODK_ParseProvisioning(
|
||||
const uint8_t* message, size_t message_length,
|
||||
size_t core_message_length,
|
||||
const ODK_NonceValues* nonce_values,
|
||||
const uint8_t* device_id,
|
||||
const uint8_t* message, size_t message_length, size_t core_message_length,
|
||||
const ODK_NonceValues* nonce_values, const uint8_t* device_id,
|
||||
size_t device_id_length, ODK_ParsedProvisioning* parsed_response) {
|
||||
if (!nonce_values || !device_id || !parsed_response) {
|
||||
if (!message || !nonce_values || !device_id || !parsed_response) {
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
@@ -290,9 +312,10 @@ OEMCryptoResult ODK_ParseProvisioning(
|
||||
return ODK_ERROR_CORE_MESSAGE;
|
||||
}
|
||||
|
||||
OEMCryptoResult err = ODK_ParseResponse(
|
||||
message, message_length, ODK_Provisioning_Response_Type,
|
||||
nonce_values, &provisioning_response.core_provisioning.core_message);
|
||||
const OEMCryptoResult err =
|
||||
ODK_ParseResponse(message, message_length, core_message_length,
|
||||
ODK_Provisioning_Response_Type, nonce_values,
|
||||
&provisioning_response.core_provisioning.core_message);
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
|
||||
Reference in New Issue
Block a user