odk: core serialization structs & functions

odk directory copied from wvgerrit.
branch oemcrypto-v16
commit 0c9a7dc

Bug: 140758896
Test: odk_test
Change-Id: I0c631f771b794468a63e4395f6b9c3b60a1dfd4f
This commit is contained in:
Robert Shih
2019-09-12 23:31:31 -07:00
parent 9ea47dc64a
commit 2443fe807a
22 changed files with 4642 additions and 0 deletions

View File

@@ -0,0 +1,229 @@
/*
* 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 <stdint.h>
#include <string.h>
#include "odk.h"
OEMCryptoResult ODK_InitializeSessionValues(ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values,
ODK_NonceValues* nonce_values,
uint32_t api_version,
uint32_t session_id) {
if (clock_values == NULL || clock_values == NULL || nonce_values == NULL)
return OEMCrypto_ERROR_INVALID_CONTEXT;
timer_limits->soft_expiry = false;
timer_limits->earliest_playback_start_seconds = 0;
timer_limits->latest_playback_start_seconds = 0;
timer_limits->initial_playback_duration_seconds = 0;
timer_limits->renewal_playback_duration_seconds = 0;
timer_limits->license_duration_seconds = 0;
clock_values->time_of_license_signed = 0;
clock_values->time_of_first_decrypt = 0;
clock_values->time_of_last_decrypt = 0;
clock_values->time_when_timer_expires = 0;
clock_values->timer_status = 0;
clock_values->status = kUnused;
nonce_values->api_version = api_version;
nonce_values->nonce = 0;
nonce_values->session_id = session_id;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult ODK_SetNonceValues(ODK_NonceValues* nonce_values,
uint32_t nonce) {
nonce_values->nonce = nonce;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult ODK_InitializeClockValues(ODK_ClockValues* clock_values,
uint64_t system_time_seconds) {
if (clock_values == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
clock_values->time_of_license_signed = system_time_seconds;
clock_values->time_of_first_decrypt = 0;
clock_values->time_of_last_decrypt = 0;
clock_values->time_when_timer_expires = 0;
/* TODO(b/142415188): document this. */
clock_values->timer_status = 0;
clock_values->status = kUnused;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult ODK_ReloadClockValues(ODK_ClockValues* clock_values,
uint64_t time_of_license_signed,
uint64_t time_of_first_decrypt,
uint64_t time_of_last_decrypt,
enum OEMCrypto_Usage_Entry_Status status,
uint64_t system_time_seconds) {
if (clock_values == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT;
clock_values->time_of_license_signed = time_of_license_signed;
clock_values->time_of_first_decrypt = time_of_first_decrypt;
clock_values->time_of_last_decrypt = time_of_last_decrypt;
clock_values->time_when_timer_expires = 0;
clock_values->timer_status = 0;
clock_values->status = status;
return OEMCrypto_SUCCESS;
}
/* This is called on the first playback for a session. */
uint32_t ODK_AttemptFirstPlayback(uint64_t system_time_seconds,
const ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values,
uint64_t* timer_value) {
if (clock_values == NULL || timer_limits == NULL)
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
/* All times are relative to when the license was signed. */
const uint64_t rental_time =
system_time_seconds - clock_values->time_of_license_signed;
if (rental_time < timer_limits->earliest_playback_start_seconds) {
clock_values->timer_status = ODK_TIMER_EXPIRED;
return ODK_TIMER_EXPIRED;
}
/* If the clock status is already marked as inactive, then playback is
* not allowed. */
/* TODO(b/142415188): add helper function. */
if (clock_values->status > kActive) {
clock_values->timer_status = ODK_TIMER_EXPIRED;
return ODK_TIMER_EXPIRED;
}
/* If this license is still inactive (never used) then we just look at the
* rental window. This is the first playback for the license, not just this
* session. */
if (clock_values->status == kUnused) {
/* If the rental clock has expired, the license has expired. */
if (rental_time > timer_limits->latest_playback_start_seconds) {
clock_values->timer_status = ODK_TIMER_EXPIRED;
return ODK_TIMER_EXPIRED;
}
/* The timer should be limited by the playback duration. */
uint64_t time_left = timer_limits->initial_playback_duration_seconds;
/* If there is a license duration, it also limits the timer. Remeber, a
* limit of 0 means no limit, or infinite. */
if (timer_limits->license_duration_seconds > 0) {
if (timer_limits->license_duration_seconds < rental_time) {
/* If the license duration has expired. This is unusual, because this
* can only happen if the license duration is less than the rental
* window. */
clock_values->timer_status = ODK_TIMER_EXPIRED;
return ODK_TIMER_EXPIRED;
}
if (timer_limits->license_duration_seconds - rental_time < time_left ||
time_left == 0) {
time_left = timer_limits->license_duration_seconds - rental_time;
}
}
/* This is a new license, and we can start playback. */
clock_values->status = kActive;
clock_values->time_of_first_decrypt = system_time_seconds;
clock_values->time_of_last_decrypt = system_time_seconds;
if (time_left == 0 || timer_limits->soft_expiry) { /* Unlimited. */
clock_values->time_when_timer_expires = 0;
clock_values->timer_status = ODK_DISABLE_TIMER;
return ODK_DISABLE_TIMER;
}
/* Set timer to limit playback. */
if (timer_value) *timer_value = time_left;
clock_values->time_when_timer_expires = system_time_seconds + time_left;
clock_values->timer_status = ODK_SET_TIMER;
return ODK_SET_TIMER;
}
/* Otherwise, this is the second loading of a persistent license. In this
* case, we ignore the rental window. */
const uint64_t time_since_first_decrypt =
system_time_seconds - clock_values->time_of_first_decrypt;
uint64_t time_left = 0;
/* If there is an initial playback duration, the we use that as a limit.
* This ignores any license renewals. If renewals are allowed, then the last
* one can be reloaded to reset the timer. */
if (timer_limits->initial_playback_duration_seconds > 0) {
if (timer_limits->initial_playback_duration_seconds <=
time_since_first_decrypt) {
clock_values->timer_status = ODK_TIMER_EXPIRED;
return ODK_TIMER_EXPIRED;
}
time_left = timer_limits->initial_playback_duration_seconds -
time_since_first_decrypt;
}
/* If there is a license duration, it also limits the timer. */
if (timer_limits->license_duration_seconds > 0) {
if (timer_limits->license_duration_seconds < rental_time) {
/* The license duration has expired. */
clock_values->timer_status = ODK_TIMER_EXPIRED;
return ODK_TIMER_EXPIRED;
}
if (timer_limits->license_duration_seconds - rental_time < time_left ||
time_left == 0) {
time_left = timer_limits->license_duration_seconds - rental_time;
}
}
/* We can restart playback for this license. Update last playback time. */
clock_values->time_of_last_decrypt = system_time_seconds;
if (time_left == 0 || timer_limits->soft_expiry) { /* Unlimited. */
clock_values->time_when_timer_expires = 0;
clock_values->timer_status = ODK_DISABLE_TIMER;
return ODK_DISABLE_TIMER;
}
/* Set timer. */
if (timer_value) *timer_value = time_left;
clock_values->time_when_timer_expires = system_time_seconds + time_left;
clock_values->timer_status = ODK_SET_TIMER;
return ODK_SET_TIMER;
}
/* This is called regularly during playback if OEMCrypto does not implement its
* own timer. */
OEMCryptoResult ODK_UpdateLastPlaybackTime(uint64_t system_time_seconds,
const ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values) {
if (clock_values == NULL || timer_limits == NULL)
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (clock_values->timer_status == ODK_TIMER_EXPIRED) {
return ODK_TIMER_EXPIRED;
}
if (clock_values->time_when_timer_expires > 0 &&
system_time_seconds > clock_values->time_when_timer_expires) {
clock_values->timer_status = ODK_TIMER_EXPIRED;
return ODK_TIMER_EXPIRED;
}
clock_values->time_of_last_decrypt = system_time_seconds;
return OEMCrypto_SUCCESS;
}
OEMCryptoResult ODK_DeactivateUsageEntry(ODK_ClockValues* clock_values) {
if (clock_values == NULL) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
if (clock_values->status == kUnused) {
clock_values->status = kInactiveUnused;
} else {
clock_values->status = kInactiveUsed;
}
return OEMCrypto_SUCCESS;
}
OEMCryptoResult ODK_InitializeV15Values(ODK_TimerLimits* timer_limits,
ODK_ClockValues* clock_values,
ODK_NonceValues* nonce_values,
uint32_t key_duration,
uint64_t system_time_seconds) {
if (clock_values == NULL || clock_values == NULL || nonce_values == NULL)
return OEMCrypto_ERROR_INVALID_CONTEXT;
timer_limits->soft_expiry = false;
timer_limits->earliest_playback_start_seconds = 0;
timer_limits->latest_playback_start_seconds = 0;
timer_limits->initial_playback_duration_seconds = key_duration;
timer_limits->renewal_playback_duration_seconds = key_duration;
timer_limits->license_duration_seconds = 0;
nonce_values->api_version = 15;
if (key_duration > 0) {
clock_values->time_when_timer_expires = system_time_seconds + key_duration;
} else {
clock_values->time_when_timer_expires = 0;
}
return OEMCrypto_SUCCESS;
}