From 8dc1d7a11d1f66a807967a5924ee9c1de09acb52 Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Fri, 29 May 2020 11:13:20 -0700 Subject: [PATCH] ODK: forward compatibility and nonce-free offline license support Merge of http://go/wvgerrit/101183 This is a combination of multiple commits from google3: * http://cl/313814938 ODK Version String * http://cl/313962712 ODK: accept messages with future API version numbers * http://cl/312219187 Ignore hash if initial load of license, and the nonce not required (squashed into http://cl/313962712) Test: OEMCryptoLicenseTest.LoadKeyWithNoRequest Bug: 157822248 Bug: 156853321 Change-Id: I735d355241876bddb0c52440b0049efb72a4b26f --- .../oemcrypto/odk/include/odk_structs.h | 6 ++++ .../odk/src/core_message_deserialize.cpp | 15 ++++------ .../odk/src/core_message_serialize.cpp | 6 ++++ libwvdrmengine/oemcrypto/odk/src/odk.c | 28 +++++++++++++++---- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/libwvdrmengine/oemcrypto/odk/include/odk_structs.h b/libwvdrmengine/oemcrypto/odk/include/odk_structs.h index b24f7d9d..8fcbfff2 100644 --- a/libwvdrmengine/oemcrypto/odk/include/odk_structs.h +++ b/libwvdrmengine/oemcrypto/odk/include/odk_structs.h @@ -14,6 +14,12 @@ #define ODK_MAJOR_VERSION 16 #define ODK_MINOR_VERSION 2 +/* ODK Version string. Date changed automatically on each release. */ +#define ODK_RELEASE_DATE "ODK v16.2 2020-05-30" + +/* The lowest version number for an ODK message. */ +#define ODK_FIRST_VERSION 16 + /* Some useful constants. */ #define ODK_DEVICE_ID_LEN_MAX 64 #define ODK_SHA256_HASH_SIZE 32 diff --git a/libwvdrmengine/oemcrypto/odk/src/core_message_deserialize.cpp b/libwvdrmengine/oemcrypto/odk/src/core_message_deserialize.cpp index f2e909b5..f00591d5 100644 --- a/libwvdrmengine/oemcrypto/odk/src/core_message_deserialize.cpp +++ b/libwvdrmengine/oemcrypto/odk/src/core_message_deserialize.cpp @@ -19,9 +19,6 @@ namespace oemcrypto_core_message { namespace deserialize { namespace { -constexpr int EARLIEST_OEMCRYPTO_VERSION_WITH_ODK = 16; -constexpr int LATEST_OEMCRYPTO_VERSION = 16; - /** * Template for parsing requests * @@ -59,21 +56,19 @@ bool ParseRequest(uint32_t message_type, core_request->session_id = core_message.nonce_values.session_id; // Verify that the minor version matches the released version for the given // major version. - if ((core_request->api_major_version < EARLIEST_OEMCRYPTO_VERSION_WITH_ODK) || - (core_request->api_major_version > LATEST_OEMCRYPTO_VERSION)) { - // Non existing and future versions are not supported. + if (core_request->api_major_version < ODK_FIRST_VERSION) { + // Non existing versions are not supported. return false; } else if (core_request->api_major_version == 16) { // For version 16, we demand a minor version of at least 2. + // We accept 16.2, 16.3, or higher. if (core_request->api_major_version < 2) return false; } else { // Other versions do not (yet) have a restriction on minor number. + // In particular, future versions are accepted for forward compatibility. } return core_message.message_type == message_type && - core_message.message_length == GetOffset(msg) && - core_request->api_major_version >= - EARLIEST_OEMCRYPTO_VERSION_WITH_ODK && - core_request->api_major_version <= LATEST_OEMCRYPTO_VERSION; + core_message.message_length == GetOffset(msg); } } // namespace diff --git a/libwvdrmengine/oemcrypto/odk/src/core_message_serialize.cpp b/libwvdrmengine/oemcrypto/odk/src/core_message_serialize.cpp index cdd97447..45464607 100644 --- a/libwvdrmengine/oemcrypto/odk/src/core_message_serialize.cpp +++ b/libwvdrmengine/oemcrypto/odk/src/core_message_serialize.cpp @@ -41,6 +41,12 @@ bool CreateResponse(uint32_t message_type, const S& core_request, header->nonce_values.api_minor_version = core_request.api_minor_version; header->nonce_values.nonce = core_request.nonce; header->nonce_values.session_id = core_request.session_id; + // The message API version for the response is the minimum of our version and + // the request's version. + if (core_request.api_major_version > ODK_MAJOR_VERSION) { + header->nonce_values.api_major_version = ODK_MAJOR_VERSION; + header->nonce_values.api_minor_version = ODK_MINOR_VERSION; + } static constexpr size_t BUF_CAPACITY = 2048; std::vector buf(BUF_CAPACITY, 0); diff --git a/libwvdrmengine/oemcrypto/odk/src/odk.c b/libwvdrmengine/oemcrypto/odk/src/odk.c index be34f879..42e82d5e 100644 --- a/libwvdrmengine/oemcrypto/odk/src/odk.c +++ b/libwvdrmengine/oemcrypto/odk/src/odk.c @@ -190,9 +190,9 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, * renewal. All releases use v15. */ if (clock_values->timer_status == ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED || clock_values->timer_status == ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE) { - nonce_values->api_major_version = 15; + nonce_values->api_major_version = ODK_FIRST_VERSION - 1; } - if (nonce_values->api_major_version < 16) { + if (nonce_values->api_major_version < ODK_FIRST_VERSION) { *core_message_size = 0; return OEMCrypto_SUCCESS; } @@ -270,12 +270,28 @@ OEMCryptoResult ODK_ParseLicense( return err; } - /* This function should not be used for legacy licenses. */ - if (license_response.request.core_message.nonce_values.api_major_version != - ODK_MAJOR_VERSION) { + /* We do not support future API version. Also, this function should not be + * used for legacy licenses. */ + if (license_response.request.core_message.nonce_values.api_major_version > + ODK_MAJOR_VERSION || + license_response.request.core_message.nonce_values.api_major_version < + ODK_FIRST_VERSION) { return ODK_UNSUPPORTED_API; } + /* If the server sent us an older format, record the license's API version. */ + if (nonce_values->api_major_version > + license_response.request.core_message.nonce_values.api_major_version) { + nonce_values->api_major_version = + license_response.request.core_message.nonce_values.api_major_version; + nonce_values->api_minor_version = + license_response.request.core_message.nonce_values.api_minor_version; + } else if (nonce_values->api_minor_version > + license_response.request.core_message.nonce_values + .api_minor_version) { + nonce_values->api_minor_version = + license_response.request.core_message.nonce_values.api_minor_version; + } /* If the license has a provider session token (pst), then OEMCrypto should * have a usage entry loaded. The opposite is also an error. */ if ((usage_entry_present && parsed_license->pst.length == 0) || @@ -302,7 +318,7 @@ OEMCryptoResult ODK_ParseLicense( * 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 && + if (initial_license_load && parsed_license->nonce_required && crypto_memcmp(request_hash, license_response.request_hash, ODK_SHA256_HASH_SIZE)) { return ODK_ERROR_CORE_MESSAGE;