diff --git a/libwvdrmengine/oemcrypto/odk/include/odk.h b/libwvdrmengine/oemcrypto/odk/include/odk.h index ab0a88b9..1011f684 100644 --- a/libwvdrmengine/oemcrypto/odk/include/odk.h +++ b/libwvdrmengine/oemcrypto/odk/include/odk.h @@ -55,6 +55,9 @@ * * @defgroup common_types Common Types * Enumerations and structures that are used by several OEMCrypto and ODK + * + * @defgroup odk_derivation Key Derivation Utils + * Utilities and constants relating to key derivation. * functions. *********************************************************************/ @@ -784,6 +787,83 @@ bool CheckApiVersionAtMost(const ODK_NonceValues* nonce_values, /// @} +/// @addtogroup odk_derivation +/// @{ + +/** + * Contains the key label for the Mac key derivation. This contains + * |ODK_MacKeyLabelWithZeroLength| number of bytes. + */ +extern const uint8_t ODK_MacKeyLabelWithZero[]; + +/** Contains the number of bytes in |ODK_MacKeyLabelWithZero|. */ +extern const size_t ODK_MacKeyLabelWithZeroLength; + +/** + * Contains the key label for the Encryption key derivation. This contains + * |ODK_EncKeyLabelWithZeroLength| number of bytes. + */ +extern const uint8_t ODK_EncKeyLabelWithZero[]; + +/** Contains the number of bytes in |ODK_EncKeyLabelWithZero|. */ +extern const size_t ODK_EncKeyLabelWithZeroLength; + +/** + * Contains the suffix bytes (NIST 800-108 key length) for Mac key derivation. + * This value is appended after the context string. This contains + * ODK_MacKeySuffixLength number of bytes. + */ +extern const uint8_t ODK_MacKeySuffix[]; + +/** Contains the number of bytes in |ODK_MacKeySuffix|. */ +extern const size_t ODK_MacKeySuffixLength; + +/** + * Contains the suffix bytes (NIST 800-108 key length) for Encryption key + * derivation. This value is appended after the context string. This contains + * ODK_EncKeySuffixLength number of bytes. + */ +extern const uint8_t ODK_EncKeySuffix[]; + +/** Contains the number of bytes in |ODK_EncKeySuffix|. */ +extern const size_t ODK_EncKeySuffixLength; + +/** + * Generates the key-derivation contexts for the license exchange based on the + * given context value. + * + * NOTE: if the mac_key_context/enc_key_context pointer are null and/or input + * mac_key_context_length/enc_key_context_length is zero, this function returns + * OEMCrypto_ERROR_SHORT_BUFFER and sets output + * mac_key_context_length/enc_key_context_length to the size needed. + * + * @param[in] context: pointer to the context buffer. + * @param[in] context_length: the length of the context buffer. + * @param[out] mac_key_context: an output buffer to contain the MAC key context. + * @param[in,out] mac_key_context_length: on input, contains the number of bytes + * in |mac_key_context|; on return, will contain the context length. + * @param[out] enc_key_context: an output buffer to contain the encryption key + * context. + * @param[in,out] enc_key_context_length: on input, contains the number of bytes + * in |enc_key_context|; on return, will contain the context length. + * + * @retval OEMCrypto_SUCCESS + * @retval OEMCrypto_ERROR_SHORT_BUFFER: mac_key_context_length or + * enc_key_context_length is too small + * @retval OEMCrypto_ERROR_INVALID_CONTEXT + * + * @version + * This method is new in version 19 of the API. + */ +OEMCryptoResult ODK_GenerateKeyContexts(const uint8_t* context, + size_t context_length, + uint8_t* mac_key_context, + size_t* mac_key_context_length, + uint8_t* enc_key_context, + size_t* enc_key_context_length); + +/// @} + #ifdef __cplusplus } #endif diff --git a/libwvdrmengine/oemcrypto/odk/include/odk_structs.h b/libwvdrmengine/oemcrypto/odk/include/odk_structs.h index 63b5cbe6..257f3ad2 100644 --- a/libwvdrmengine/oemcrypto/odk/include/odk_structs.h +++ b/libwvdrmengine/oemcrypto/odk/include/odk_structs.h @@ -19,7 +19,7 @@ extern "C" { #define ODK_MINOR_VERSION 0 /* ODK Version string. Date changed automatically on each release. */ -#define ODK_RELEASE_DATE "ODK v19.0 2023-10-09" +#define ODK_RELEASE_DATE "ODK v19.0 2023-10-11" /* The lowest version number for an ODK message. */ #define ODK_FIRST_VERSION 16 diff --git a/libwvdrmengine/oemcrypto/odk/src/odk.c b/libwvdrmengine/oemcrypto/odk/src/odk.c index 854cf613..ffcef963 100644 --- a/libwvdrmengine/oemcrypto/odk/src/odk.c +++ b/libwvdrmengine/oemcrypto/odk/src/odk.c @@ -9,6 +9,7 @@ #include #include +#include "OEMCryptoCENCCommon.h" #include "odk_message.h" #include "odk_overflow.h" #include "odk_serialize.h" @@ -589,3 +590,69 @@ bool CheckApiVersionAtMost(const ODK_NonceValues* nonce_values, (nonce_values->api_major_version == major_version && nonce_values->api_minor_version <= minor_version); } + +const uint8_t ODK_MacKeyLabelWithZero[] = "AUTHENTICATION"; +const size_t ODK_MacKeyLabelWithZeroLength = sizeof(ODK_MacKeyLabelWithZero); +// This is the key size (512) in network byte order. +const uint8_t ODK_MacKeySuffix[] = {0x00, 0x00, 0x02, 0x00}; +const size_t ODK_MacKeySuffixLength = sizeof(ODK_MacKeySuffix); + +const uint8_t ODK_EncKeyLabelWithZero[] = "ENCRYPTION"; +const size_t ODK_EncKeyLabelWithZeroLength = sizeof(ODK_EncKeyLabelWithZero); +// This is the key size (128) in network byte order. +const uint8_t ODK_EncKeySuffix[] = {0x00, 0x00, 0x00, 0x80}; +const size_t ODK_EncKeySuffixLength = sizeof(ODK_EncKeySuffix); + +OEMCryptoResult ODK_GenerateKeyContexts(const uint8_t* context, + size_t context_length, + uint8_t* mac_key_context, + size_t* mac_key_context_length, + uint8_t* enc_key_context, + size_t* enc_key_context_length) { + size_t real_mac_length; + size_t real_enc_length; + if (odk_add_overflow_ux( + context_length, + ODK_MacKeyLabelWithZeroLength + ODK_MacKeySuffixLength, + &real_mac_length) || + real_mac_length > 0xffffffff || + odk_add_overflow_ux( + context_length, + ODK_EncKeyLabelWithZeroLength + ODK_EncKeySuffixLength, + &real_enc_length) || + real_enc_length > 0xffffffff) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + bool short_buffer = false; + if (mac_key_context_length) { + short_buffer = real_mac_length > *mac_key_context_length; + *mac_key_context_length = real_mac_length; + } + if (enc_key_context_length) { + short_buffer = short_buffer || real_enc_length > *enc_key_context_length; + *enc_key_context_length = real_enc_length; + } + if (short_buffer || !mac_key_context || !enc_key_context) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + if (!context || !mac_key_context_length || !enc_key_context_length) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + memcpy(mac_key_context, ODK_MacKeyLabelWithZero, + ODK_MacKeyLabelWithZeroLength); + memcpy(mac_key_context + ODK_MacKeyLabelWithZeroLength, context, + context_length); + memcpy(mac_key_context + ODK_MacKeyLabelWithZeroLength + context_length, + ODK_MacKeySuffix, ODK_MacKeySuffixLength); + + memcpy(enc_key_context, ODK_EncKeyLabelWithZero, + ODK_EncKeyLabelWithZeroLength); + memcpy(enc_key_context + ODK_EncKeyLabelWithZeroLength, context, + context_length); + memcpy(enc_key_context + ODK_EncKeyLabelWithZeroLength + context_length, + ODK_EncKeySuffix, ODK_EncKeySuffixLength); + + return OEMCrypto_SUCCESS; +} diff --git a/libwvdrmengine/oemcrypto/odk/test/odk_test.cpp b/libwvdrmengine/oemcrypto/odk/test/odk_test.cpp index dae32aa0..3ebc4f65 100644 --- a/libwvdrmengine/oemcrypto/odk/test/odk_test.cpp +++ b/libwvdrmengine/oemcrypto/odk/test/odk_test.cpp @@ -1376,6 +1376,130 @@ TEST(OdkOverflowTest, MultiplyUX) { EXPECT_TRUE(odk_mul_overflow_ux(4, SIZE_MAX >> 1, &result)); } +TEST(OdkTest, GenerateKeyContexts_Success) { + const uint8_t kContext[] = { + 0x0a, 0x4c, 0x08, 0x00, 0x12, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x10, 0x19, 0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1, 0x22, 0x67, + 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd, 0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, + 0xc2, 0xd8, 0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64, 0x6e, 0x58, + 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8, 0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, + 0x14, 0xa8, 0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64, 0x0b, 0xd2, + 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39, 0x12, 0x25, 0x0a, 0x23, 0x0a, 0x14, + 0x08, 0x01, 0x12, 0x10, 0x09, 0x15, 0x00, 0x7c, 0xaa, 0x9b, 0x59, 0x31, + 0xb7, 0x6a, 0x3a, 0x85, 0xf0, 0x46, 0x52, 0x3e, 0x10, 0x01, 0x1a, 0x09, + 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x18, 0x01, 0x20, + 0x00, 0x2a, 0x0c, 0x31, 0x38, 0x38, 0x36, 0x37, 0x38, 0x37, 0x34, 0x30, + 0x35, 0x00, 0x00, + }; + const uint8_t kMacKey[] = { + 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x00, 0x0a, 0x4c, 0x08, 0x00, 0x12, 0x48, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x10, 0x19, 0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, + 0xc1, 0x22, 0x67, 0x80, 0x53, 0x36, 0x21, 0x36, 0xbd, 0xf8, 0x40, 0x8f, + 0x82, 0x76, 0xe4, 0xc2, 0xd8, 0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, + 0x64, 0x6e, 0x58, 0x73, 0x49, 0x30, 0xac, 0xeb, 0xe8, 0x99, 0xb3, 0xe4, + 0x64, 0x18, 0x9a, 0x14, 0xa8, 0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, + 0x64, 0x0b, 0xd2, 0x2e, 0xf4, 0x4b, 0x2d, 0x7e, 0x39, 0x12, 0x25, 0x0a, + 0x23, 0x0a, 0x14, 0x08, 0x01, 0x12, 0x10, 0x09, 0x15, 0x00, 0x7c, 0xaa, + 0x9b, 0x59, 0x31, 0xb7, 0x6a, 0x3a, 0x85, 0xf0, 0x46, 0x52, 0x3e, 0x10, + 0x01, 0x1a, 0x09, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, + 0x18, 0x01, 0x20, 0x00, 0x2a, 0x0c, 0x31, 0x38, 0x38, 0x36, 0x37, 0x38, + 0x37, 0x34, 0x30, 0x35, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + }; + const uint8_t kEncKey[] = { + 0x45, 0x4e, 0x43, 0x52, 0x59, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x00, 0x0a, + 0x4c, 0x08, 0x00, 0x12, 0x48, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x10, + 0x19, 0x07, 0xd9, 0xff, 0xde, 0x13, 0xaa, 0x95, 0xc1, 0x22, 0x67, 0x80, + 0x53, 0x36, 0x21, 0x36, 0xbd, 0xf8, 0x40, 0x8f, 0x82, 0x76, 0xe4, 0xc2, + 0xd8, 0x7e, 0xc5, 0x2b, 0x61, 0xaa, 0x1b, 0x9f, 0x64, 0x6e, 0x58, 0x73, + 0x49, 0x30, 0xac, 0xeb, 0xe8, 0x99, 0xb3, 0xe4, 0x64, 0x18, 0x9a, 0x14, + 0xa8, 0x72, 0x02, 0xfb, 0x02, 0x57, 0x4e, 0x70, 0x64, 0x0b, 0xd2, 0x2e, + 0xf4, 0x4b, 0x2d, 0x7e, 0x39, 0x12, 0x25, 0x0a, 0x23, 0x0a, 0x14, 0x08, + 0x01, 0x12, 0x10, 0x09, 0x15, 0x00, 0x7c, 0xaa, 0x9b, 0x59, 0x31, 0xb7, + 0x6a, 0x3a, 0x85, 0xf0, 0x46, 0x52, 0x3e, 0x10, 0x01, 0x1a, 0x09, 0x39, + 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x18, 0x01, 0x20, 0x00, + 0x2a, 0x0c, 0x31, 0x38, 0x38, 0x36, 0x37, 0x38, 0x37, 0x34, 0x30, 0x35, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + }; + + std::vector mac_key(sizeof(kMacKey) + 24); + std::vector enc_key(sizeof(kEncKey) + 24); + size_t mac_key_size = mac_key.size(); + size_t enc_key_size = enc_key.size(); + ASSERT_EQ(OEMCrypto_SUCCESS, + ODK_GenerateKeyContexts(kContext, sizeof(kContext), &mac_key[0], + &mac_key_size, &enc_key[0], &enc_key_size)); + ASSERT_EQ(mac_key_size, sizeof(kMacKey)); + ASSERT_EQ(enc_key_size, sizeof(kEncKey)); + mac_key.resize(mac_key_size); + enc_key.resize(enc_key_size); + + EXPECT_EQ(std::vector(kMacKey, kMacKey + sizeof(kMacKey)), mac_key); + EXPECT_EQ(std::vector(kEncKey, kEncKey + sizeof(kEncKey)), enc_key); +} + +TEST(OdkTest, GenerateKeyContexts_ShortBuffer) { + const uint8_t kContext[] = {1, 2, 3}; + size_t mac_key_size = 0; + size_t enc_key_size = 0; + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + ODK_GenerateKeyContexts(kContext, sizeof(kContext), nullptr, + &mac_key_size, nullptr, &enc_key_size)); + EXPECT_EQ(mac_key_size, sizeof(kContext) + 19); + EXPECT_EQ(enc_key_size, sizeof(kContext) + 15); +} + +TEST(OdkTest, GenerateKeyContexts_ShortBufferMacOnly) { + const uint8_t kContext[] = {1, 2, 3}; + uint8_t buffer[128]; + size_t mac_key_size = 0; + size_t enc_key_size = sizeof(buffer); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + ODK_GenerateKeyContexts(kContext, sizeof(kContext), nullptr, + &mac_key_size, buffer, &enc_key_size)); + EXPECT_EQ(mac_key_size, sizeof(kContext) + 19); + EXPECT_EQ(enc_key_size, sizeof(kContext) + 15); +} + +TEST(OdkTest, GenerateKeyContexts_ShortBufferEncOnly) { + const uint8_t kContext[] = {1, 2, 3}; + uint8_t buffer[128]; + size_t mac_key_size = sizeof(buffer); + size_t enc_key_size = 0; + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + ODK_GenerateKeyContexts(kContext, sizeof(kContext), buffer, + &mac_key_size, buffer, &enc_key_size)); + EXPECT_EQ(mac_key_size, sizeof(kContext) + 19); + EXPECT_EQ(enc_key_size, sizeof(kContext) + 15); +} + +TEST(OdkTest, GenerateKeyContexts_NullArgs) { + const uint8_t kContext[] = {1, 2, 3}; + uint8_t buffer[24]; + size_t buffer_size = sizeof(buffer); + size_t buffer_size2 = sizeof(buffer); + + EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + ODK_GenerateKeyContexts(nullptr, sizeof(kContext), buffer, + &buffer_size, buffer, &buffer_size2)); + buffer_size = buffer_size2 = sizeof(buffer); // Update to avoid short buffer. + EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + ODK_GenerateKeyContexts(kContext, sizeof(kContext), nullptr, + &buffer_size, buffer, &buffer_size2)); + buffer_size = buffer_size2 = sizeof(buffer); // Update to avoid short buffer. + EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + ODK_GenerateKeyContexts(kContext, sizeof(kContext), buffer, nullptr, + buffer, &buffer_size2)); + buffer_size = buffer_size2 = sizeof(buffer); // Update to avoid short buffer. + EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + ODK_GenerateKeyContexts(kContext, sizeof(kContext), buffer, + &buffer_size, nullptr, &buffer_size2)); + buffer_size = buffer_size2 = sizeof(buffer); // Update to avoid short buffer. + EXPECT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + ODK_GenerateKeyContexts(kContext, sizeof(kContext), buffer, + &buffer_size, buffer, nullptr)); +} + } // namespace } // namespace wvodk_test