diff --git a/libwvdrmengine/cdm/core/include/certificate_provisioning.h b/libwvdrmengine/cdm/core/include/certificate_provisioning.h index 5ca9e317..52d35fd6 100644 --- a/libwvdrmengine/cdm/core/include/certificate_provisioning.h +++ b/libwvdrmengine/cdm/core/include/certificate_provisioning.h @@ -125,6 +125,7 @@ class CertificateProvisioning { std::unique_ptr crypto_session_; CdmCertificateType cert_type_; std::unique_ptr service_certificate_; + std::string request_; // The wrapped private key in provisioning 4 generated by calling // GenerateCertificateKeyPair. It will be saved to file system if a valid // response is received. diff --git a/libwvdrmengine/cdm/core/include/content_key_session.h b/libwvdrmengine/cdm/core/include/content_key_session.h index e3681752..d63a4243 100644 --- a/libwvdrmengine/cdm/core/include/content_key_session.h +++ b/libwvdrmengine/cdm/core/include/content_key_session.h @@ -24,13 +24,6 @@ class ContentKeySession : public KeySession { KeySessionType Type() override { return kDefault; } - // Generate Derived Keys for ContentKeySession - OEMCryptoResult GenerateDerivedKeys(const std::string& message) override; - - // Generate Derived Keys (from session key) for ContentKeySession - OEMCryptoResult GenerateDerivedKeys(const std::string& message, - const std::string& session_key) override; - // Load Keys for ContentKeySession OEMCryptoResult LoadKeys(const std::string& message, const std::string& signature, diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index 58e7d2ff..446dd8b5 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -159,7 +159,9 @@ class CryptoSession { OEMCrypto_SignatureHashAlgorithm& algorithm); virtual CdmResponseType UseSecondaryKey(bool dual_key); // V16 licenses. - virtual CdmResponseType LoadLicense(const std::string& signed_message, + virtual CdmResponseType LoadLicense(const std::string& context, + const std::string& session_key, + const std::string& signed_message, const std::string& core_message, const std::string& signature, CdmLicenseKeyType key_type); @@ -178,17 +180,19 @@ class CryptoSession { const std::vector& key_array); // Provisioning request/responses - virtual CdmResponseType GenerateDerivedKeys(const std::string& message); - virtual CdmResponseType GenerateDerivedKeys(const std::string& message, - const std::string& session_key); virtual CdmResponseType PrepareAndSignProvisioningRequest( const std::string& message, std::string* core_message, std::string* signature, bool& should_specify_algorithm, OEMCrypto_SignatureHashAlgorithm& algorithm); - virtual CdmResponseType LoadProvisioning(const std::string& signed_message, + virtual CdmResponseType LoadProvisioning(const std::string& request, + const std::string& signed_message, const std::string& core_message, const std::string& signature, std::string* wrapped_private_key); + virtual CdmResponseType LoadProvisioningCast( + const std::string& derivation_key, const std::string& request, + const std::string& signed_message, const std::string& core_message, + const std::string& signature, std::string* wrapped_private_key); virtual CdmResponseType LoadCertificatePrivateKey( const CryptoWrappedKey& private_key); virtual CdmResponseType GetBootCertificateChain( diff --git a/libwvdrmengine/cdm/core/include/key_session.h b/libwvdrmengine/cdm/core/include/key_session.h index 36b641fc..a0465ca8 100644 --- a/libwvdrmengine/cdm/core/include/key_session.h +++ b/libwvdrmengine/cdm/core/include/key_session.h @@ -23,9 +23,6 @@ class KeySession { typedef enum { kDefault, kEntitlement } KeySessionType; virtual ~KeySession() {} virtual KeySessionType Type() = 0; - virtual OEMCryptoResult GenerateDerivedKeys(const std::string& message) = 0; - virtual OEMCryptoResult GenerateDerivedKeys( - const std::string& message, const std::string& session_key) = 0; virtual OEMCryptoResult LoadKeys(const std::string& message, const std::string& signature, const std::string& mac_key_iv, diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index 112e58d8..6737e161 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -105,16 +105,18 @@ class CdmLicense { video_widevine::LicenseRequest* license_request); CdmResponseType HandleContentKeyResponse( - bool is_restore, const std::string& msg, const std::string& core_message, - const std::string& signature, const std::vector& key_array, + bool is_restore, const std::string& session_key, const std::string& msg, + const std::string& core_message, const std::string& signature, + const std::vector& key_array, const video_widevine::License& license); // HandleEntitlementKeyResponse loads the entitlement keys in |key_array| into // the crypto session. In addition, it also extracts content keys from // |wrapped_keys_| and loads them for use. CdmResponseType HandleEntitlementKeyResponse( - bool is_restore, const std::string& msg, const std::string& core_message, - const std::string& signature, const std::vector& key_array, + bool is_restore, const std::string& session_key, const std::string& msg, + const std::string& core_message, const std::string& signature, + const std::vector& key_array, const video_widevine::License& license); // Prepare to reload a key update message. Some special code is needed to work diff --git a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp index 1168d5a3..a2ed7b10 100644 --- a/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp +++ b/libwvdrmengine/cdm/core/src/certificate_provisioning.cpp @@ -261,6 +261,7 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal( status = crypto_session_->PrepareAndSignProvisioningRequest( serialized_message, &core_message, &request_signature, should_specify_algorithm, oec_algorithm); + request_ = serialized_message; if (status != NO_ERROR) { LOGE("Failed to prepare provisioning request: status = %d", @@ -488,6 +489,7 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal( } else { *request = std::move(serialized_request); } + request_ = serialized_message; return CdmResponseType(NO_ERROR); } @@ -574,20 +576,14 @@ CdmResponseType CertificateProvisioning::HandleProvisioning40Response( return status; } - status = crypto_session_->GenerateDerivedKeys( - provisioning_request_message_, signed_response.session_key()); - if (status != NO_ERROR) { - LOGE("Failed to generate derived keys."); - return status; - } - // Get wrapped private key for cast cert CryptoWrappedKey cast_cert_private_key; const std::string& signature = signed_response.signature(); const std::string& core_message = signed_response.oemcrypto_core_message(); - status = crypto_session_->LoadProvisioning(response_message, core_message, - signature, - &cast_cert_private_key.key()); + status = crypto_session_->LoadProvisioningCast( + signed_response.session_key(), provisioning_request_message_, + response_message, core_message, signature, + &cast_cert_private_key.key()); if (status != NO_ERROR) { LOGE("Failed to generate wrapped key for cast cert."); return status; @@ -728,7 +724,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse( CryptoWrappedKey private_key; const CdmResponseType status = crypto_session_->LoadProvisioning( - signed_message, core_message, signature, &private_key.key()); + request_, signed_message, core_message, signature, &private_key.key()); if (status != NO_ERROR) { LOGE("LoadProvisioning failed: status = %d", static_cast(status)); diff --git a/libwvdrmengine/cdm/core/src/content_key_session.cpp b/libwvdrmengine/cdm/core/src/content_key_session.cpp index 1e391505..90a681fd 100644 --- a/libwvdrmengine/cdm/core/src/content_key_session.cpp +++ b/libwvdrmengine/cdm/core/src/content_key_session.cpp @@ -11,59 +11,6 @@ namespace wvcdm { -// Generate Derived Keys for ContentKeySession -OEMCryptoResult ContentKeySession::GenerateDerivedKeys( - const std::string& message) { - std::string mac_deriv_message; - std::string enc_deriv_message; - GenerateMacContext(message, &mac_deriv_message); - GenerateEncryptContext(message, &enc_deriv_message); - - LOGV("Generating derived keys: id = %u", oec_session_id_); - OEMCryptoResult sts; - M_TIME(sts = OEMCrypto_GenerateDerivedKeys( - oec_session_id_, - reinterpret_cast(mac_deriv_message.data()), - mac_deriv_message.size(), - reinterpret_cast(enc_deriv_message.data()), - enc_deriv_message.size()), - metrics_, oemcrypto_generate_derived_keys_, sts); - if (OEMCrypto_SUCCESS != sts) { - LOGE("OEMCrypto_GenerateDerivedKeys failed: status = %d", - static_cast(sts)); - } - - return sts; -} - -// Generate Derived Keys (from session key) for ContentKeySession -OEMCryptoResult ContentKeySession::GenerateDerivedKeys( - const std::string& message, const std::string& session_key) { - std::string mac_deriv_message; - std::string enc_deriv_message; - GenerateMacContext(message, &mac_deriv_message); - GenerateEncryptContext(message, &enc_deriv_message); - - LOGV("Generating derived keys from session key: id = %u", oec_session_id_); - OEMCryptoResult sts; - M_TIME( - sts = OEMCrypto_DeriveKeysFromSessionKey( - oec_session_id_, reinterpret_cast(session_key.data()), - session_key.size(), - reinterpret_cast(mac_deriv_message.data()), - mac_deriv_message.size(), - reinterpret_cast(enc_deriv_message.data()), - enc_deriv_message.size()), - metrics_, oemcrypto_derive_keys_from_session_key_, sts); - - if (OEMCrypto_SUCCESS != sts) { - LOGE("OEMCrypto_DeriveKeysFromSessionKey failed: status = %d", - static_cast(sts)); - } - - return sts; -} - // Load Keys for ContentKeySession OEMCryptoResult ContentKeySession::LoadKeys( const std::string& message, const std::string& signature, diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 609849e3..315225e6 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -257,38 +257,6 @@ OEMCrypto_Substring GetSubstring(const std::string& message, return substring; } -void GenerateMacContext(const std::string& input_context, - std::string* deriv_context) { - if (!deriv_context) { - LOGE("Output parameter |deriv_context| not provided"); - return; - } - - const std::string kSigningKeyLabel = "AUTHENTICATION"; - const size_t kSigningKeySizeBits = wvcdm::MAC_KEY_SIZE * 8; - - deriv_context->assign(kSigningKeyLabel); - deriv_context->append(1, '\0'); - deriv_context->append(input_context); - deriv_context->append(wvutil::EncodeUint32(kSigningKeySizeBits * 2)); -} - -void GenerateEncryptContext(const std::string& input_context, - std::string* deriv_context) { - if (!deriv_context) { - LOGE("Output parameter |deriv_context| not provided"); - return; - } - - const std::string kEncryptionKeyLabel = "ENCRYPTION"; - const size_t kEncryptionKeySizeBits = wvcdm::CONTENT_KEY_SIZE * 8; - - deriv_context->assign(kEncryptionKeyLabel); - deriv_context->append(1, '\0'); - deriv_context->append(input_context); - deriv_context->append(wvutil::EncodeUint32(kEncryptionKeySizeBits)); -} - OEMCryptoCipherMode ToOEMCryptoCipherMode(CdmCipherMode cipher_mode) { return cipher_mode == kCipherModeCtr ? OEMCrypto_CipherMode_CENC : OEMCrypto_CipherMode_CBCS; @@ -1122,7 +1090,9 @@ CdmResponseType CryptoSession::UseSecondaryKey(bool /* dual_key */) { } #endif -CdmResponseType CryptoSession::LoadLicense(const std::string& signed_message, +CdmResponseType CryptoSession::LoadLicense(const std::string& context, + const std::string& session_key, + const std::string& signed_message, const std::string& core_message, const std::string& signature, CdmLicenseKeyType key_type) { @@ -1138,6 +1108,9 @@ CdmResponseType CryptoSession::LoadLicense(const std::string& signed_message, M_TIME(sts = OEMCrypto_LoadLicense( oec_session_id_, + reinterpret_cast(context.data()), context.size(), + reinterpret_cast(session_key.data()), + session_key.size(), reinterpret_cast(combined_message.data()), combined_message.size(), core_message.size(), reinterpret_cast(signature.data()), @@ -1264,8 +1237,6 @@ CdmResponseType CryptoSession::PrepareAndSignProvisioningRequest( OEMCryptoResult sts; if (pre_provision_token_type_ == kClientTokenKeybox) { should_specify_algorithm = false; - const CdmResponseType status = GenerateDerivedKeys(message); - if (status != NO_ERROR) return status; } else if (pre_provision_token_type_ == kClientTokenOemCert) { should_specify_algorithm = true; WithOecSessionLock("LoadOEMPrivateKey", [&] { @@ -1708,26 +1679,6 @@ CdmResponseType CryptoSession::SelectKey(const std::string& key_id, } } -CdmResponseType CryptoSession::GenerateDerivedKeys(const std::string& message) { - OEMCryptoResult sts; - WithOecSessionLock("GenerateDerivedKeys without session_key", - [&] { sts = key_session_->GenerateDerivedKeys(message); }); - - return MapOEMCryptoResult(sts, GENERATE_DERIVED_KEYS_ERROR_2, - "GenerateDerivedKeys"); -} - -CdmResponseType CryptoSession::GenerateDerivedKeys( - const std::string& message, const std::string& session_key) { - OEMCryptoResult sts; - WithOecSessionLock("GenerateDerivedKeys with session_key", [&] { - sts = key_session_->GenerateDerivedKeys(message, session_key); - }); - - return MapOEMCryptoResult(sts, GENERATE_DERIVED_KEYS_ERROR, - "GenerateDerivedKeys"); -} - CdmResponseType CryptoSession::GenerateRsaSignature(const std::string& message, std::string* signature, RSA_Padding_Scheme scheme) { @@ -2209,8 +2160,9 @@ bool CryptoSession::SetDestinationBufferType() { } CdmResponseType CryptoSession::LoadProvisioning( - const std::string& signed_message, const std::string& core_message, - const std::string& signature, std::string* wrapped_private_key) { + const std::string& request, const std::string& signed_message, + const std::string& core_message, const std::string& signature, + std::string* wrapped_private_key) { LOGV("Loading provisioning certificate: id = %u", oec_session_id_); if (wrapped_private_key == nullptr) { LOGE("Missing wrapped |wrapped_private_key|"); @@ -2224,6 +2176,7 @@ CdmResponseType CryptoSession::LoadProvisioning( WithOecSessionLock("LoadProvisioning Attempt 1", [&] { M_TIME(status = OEMCrypto_LoadProvisioning( oec_session_id_, + reinterpret_cast(request.data()), request.size(), reinterpret_cast(combined_message.data()), combined_message.size(), core_message.size(), reinterpret_cast(signature.data()), @@ -2241,6 +2194,7 @@ CdmResponseType CryptoSession::LoadProvisioning( WithOecSessionLock("LoadProvisioning Attempt 2", [&] { M_TIME(status = OEMCrypto_LoadProvisioning( oec_session_id_, + reinterpret_cast(request.data()), request.size(), reinterpret_cast(combined_message.data()), combined_message.size(), core_message.size(), reinterpret_cast(signature.data()), @@ -2259,6 +2213,64 @@ CdmResponseType CryptoSession::LoadProvisioning( "LoadProvisioning"); } +CdmResponseType CryptoSession::LoadProvisioningCast( + const std::string& derivation_key, const std::string& request, + const std::string& signed_message, const std::string& core_message, + const std::string& signature, std::string* wrapped_private_key) { + LOGV("Loading provisioning certificate: id = %u", oec_session_id_); + if (wrapped_private_key == nullptr) { + LOGE("Missing wrapped |wrapped_private_key|"); + return CdmResponseType(PARAMETER_NULL); + } + + const std::string combined_message = core_message + signed_message; + // Round 1, get the size of the wrapped private key buffer. + size_t wrapped_private_key_length = 0; + OEMCryptoResult status; + WithOecSessionLock("LoadProvisioningCast Attempt 1", [&] { + M_TIME(status = OEMCrypto_LoadProvisioningCast( + oec_session_id_, + reinterpret_cast(derivation_key.data()), + derivation_key.size(), + reinterpret_cast(request.data()), request.size(), + reinterpret_cast(combined_message.data()), + combined_message.size(), core_message.size(), + reinterpret_cast(signature.data()), + signature.size(), nullptr, &wrapped_private_key_length), + metrics_, oemcrypto_load_provisioning_, status); + }); + + if (status != OEMCrypto_ERROR_SHORT_BUFFER) { + return MapOEMCryptoResult(status, LOAD_PROVISIONING_ERROR, + "LoadProvisioningCast"); + } + + wrapped_private_key->resize(wrapped_private_key_length); + + WithOecSessionLock("LoadProvisioningCast Attempt 2", [&] { + M_TIME(status = OEMCrypto_LoadProvisioningCast( + oec_session_id_, + reinterpret_cast(derivation_key.data()), + derivation_key.size(), + reinterpret_cast(request.data()), request.size(), + reinterpret_cast(combined_message.data()), + combined_message.size(), core_message.size(), + reinterpret_cast(signature.data()), + signature.size(), + reinterpret_cast(&wrapped_private_key->front()), + &wrapped_private_key_length), + metrics_, oemcrypto_load_provisioning_, status); + }); + + if (status == OEMCrypto_SUCCESS) { + wrapped_private_key->resize(wrapped_private_key_length); + return CdmResponseType(NO_ERROR); + } + wrapped_private_key->clear(); + return MapOEMCryptoResult(status, LOAD_PROVISIONING_ERROR, + "LoadProvisioningCast"); +} + CdmResponseType CryptoSession::GetHdcpCapabilities(HdcpCapability* current, HdcpCapability* max) { LOGV("Getting HDCP capabilities: id = %u", oec_session_id_); diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index ceeb21d3..6e6e54a3 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -585,10 +585,6 @@ CdmResponseType CdmLicense::HandleKeyResponse( LOGE("Signed response has no session keys present"); return CdmResponseType(SESSION_KEYS_NOT_FOUND); } - CdmResponseType status = crypto_session_->GenerateDerivedKeys( - key_request_, signed_response.session_key()); - - if (status != NO_ERROR) return status; // Extract mac key std::string mac_key_iv; @@ -655,18 +651,19 @@ CdmResponseType CdmLicense::HandleKeyResponse( } // If the field is not set, it will default to false. - status = + CdmResponseType status = crypto_session_->UseSecondaryKey(signed_response.using_secondary_key()); if (status != NO_ERROR) return status; CdmResponseType resp(NO_CONTENT_KEY); if (kLicenseKeyTypeEntitlement == key_type) { - resp = - HandleEntitlementKeyResponse(is_restore, signed_message, core_message, - signature, key_array, license); + resp = HandleEntitlementKeyResponse( + is_restore, signed_response.session_key(), signed_message, core_message, + signature, key_array, license); } else if (kLicenseKeyTypeContent == key_type) { - resp = HandleContentKeyResponse(is_restore, signed_message, core_message, - signature, key_array, license); + resp = HandleContentKeyResponse(is_restore, signed_response.session_key(), + signed_message, core_message, signature, + key_array, license); } return resp; } @@ -1086,15 +1083,17 @@ CdmResponseType CdmLicense::PrepareContentId( } CdmResponseType CdmLicense::HandleContentKeyResponse( - bool is_restore, const std::string& msg, const std::string& core_message, - const std::string& signature, const std::vector& key_array, + bool is_restore, const std::string& session_key, const std::string& msg, + const std::string& core_message, const std::string& signature, + const std::vector& key_array, const video_widevine::License& license) { if (key_array.empty()) { LOGE("No content keys provided"); return CdmResponseType(NO_CONTENT_KEY); } - const CdmResponseType resp = crypto_session_->LoadLicense( - msg, core_message, signature, kLicenseKeyTypeContent); + const CdmResponseType resp = + crypto_session_->LoadLicense(key_request_, session_key, msg, core_message, + signature, kLicenseKeyTypeContent); if (KEY_ADDED == resp) { loaded_keys_.clear(); for (const CryptoKey& key : key_array) { @@ -1106,15 +1105,17 @@ CdmResponseType CdmLicense::HandleContentKeyResponse( } CdmResponseType CdmLicense::HandleEntitlementKeyResponse( - bool is_restore, const std::string& msg, const std::string& core_message, - const std::string& signature, const std::vector& key_array, + bool is_restore, const std::string& session_key, const std::string& msg, + const std::string& core_message, const std::string& signature, + const std::vector& key_array, const video_widevine::License& license) { if (key_array.empty()) { LOGE("No entitlement keys provided"); return CdmResponseType(NO_CONTENT_KEY); } - const CdmResponseType resp = crypto_session_->LoadLicense( - msg, core_message, signature, kLicenseKeyTypeEntitlement); + const CdmResponseType resp = + crypto_session_->LoadLicense(key_request_, session_key, msg, core_message, + signature, kLicenseKeyTypeEntitlement); if (KEY_ADDED != resp) { return resp; diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 7966a39a..3b5f7ead 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -35,6 +35,7 @@ #include "log.h" #include "metrics_collections.h" #include "odk_structs.h" +#include "platform.h" #include "properties.h" #include "wv_cdm_constants.h" #include "wv_cdm_types.h" @@ -56,7 +57,7 @@ typedef OEMCryptoResult (*L1_SetMaxAPIVersion_t)(uint32_t max_version); typedef OEMCryptoResult (*L1_Terminate_t)(void); typedef OEMCryptoResult (*L1_OpenSession_t)(OEMCrypto_SESSION* session); typedef OEMCryptoResult (*L1_CloseSession_t)(OEMCrypto_SESSION session); -typedef OEMCryptoResult (*L1_GenerateDerivedKeys_t)( +typedef OEMCryptoResult (*L1_GenerateDerivedKeys_V18_t)( OEMCrypto_SESSION session, const uint8_t* mac_key_context, size_t mac_key_context_length, const uint8_t* enc_key_context, size_t enc_key_context_length); @@ -76,12 +77,17 @@ typedef OEMCryptoResult (*L1_PrepAndSignRenewalRequest_t)( typedef OEMCryptoResult (*L1_PrepAndSignProvisioningRequest_t)( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_length, uint8_t* signature, size_t* signature_length); -typedef OEMCryptoResult (*L1_LoadLicense_t)(OEMCrypto_SESSION session, - const uint8_t* message, - size_t message_length, - size_t core_message_length, - const uint8_t* signature, - size_t signature_length); +typedef OEMCryptoResult (*L1_LoadLicense_t)( + 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); +typedef OEMCryptoResult (*L1_LoadLicense_V18_t)(OEMCrypto_SESSION session, + const uint8_t* message, + size_t message_length, + size_t core_message_length, + const uint8_t* signature, + size_t signature_length); typedef OEMCryptoResult (*L1_LoadEntitledContentKeys_t)( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, size_t key_array_length, @@ -144,7 +150,7 @@ typedef OEMCryptoResult (*L1_GenerateRSASignature_t)( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme); -typedef OEMCryptoResult (*L1_DeriveKeysFromSessionKey_t)( +typedef OEMCryptoResult (*L1_DeriveKeysFromSessionKey_V18_t)( OEMCrypto_SESSION session, const uint8_t* enc_session_key, size_t enc_session_key_length, const uint8_t* mac_key_context, size_t mac_key_context_length, const uint8_t* enc_key_context, @@ -226,6 +232,17 @@ typedef OEMCryptoResult (*L1_FreeSecureBuffer_t)( int secure_fd); typedef size_t (*L1_MaximumUsageTableHeaderSize_t)(); typedef OEMCryptoResult (*L1_LoadProvisioning_t)( + OEMCrypto_SESSION session, const uint8_t* request, size_t 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); +typedef OEMCryptoResult (*L1_LoadProvisioningCast_t)( + OEMCrypto_SESSION session, const uint8_t* derivation_key, + size_t derivation_key_length, const uint8_t* request, size_t 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); +typedef OEMCryptoResult (*L1_LoadProvisioning_V18_t)( 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, @@ -328,13 +345,14 @@ struct FunctionPointers { L1_Terminate_t Terminate; L1_OpenSession_t OpenSession; L1_CloseSession_t CloseSession; - L1_GenerateDerivedKeys_t GenerateDerivedKeys; + L1_GenerateDerivedKeys_V18_t GenerateDerivedKeys_V18; L1_GenerateNonce_t GenerateNonce; L1_GenerateSignature_t GenerateSignature; L1_PrepAndSignLicenseRequest_t PrepAndSignLicenseRequest; L1_PrepAndSignRenewalRequest_t PrepAndSignRenewalRequest; L1_PrepAndSignProvisioningRequest_t PrepAndSignProvisioningRequest; L1_LoadLicense_t LoadLicense; + L1_LoadLicense_V18_t LoadLicense_V18; L1_LoadEntitledContentKeys_t LoadEntitledContentKeys; L1_LoadEntitledContentKeys_V16_t LoadEntitledContentKeys_V16; L1_LoadRenewal_t LoadRenewal; @@ -354,7 +372,7 @@ struct FunctionPointers { L1_LoadDRMPrivateKey_t LoadDRMPrivateKey; L1_LoadTestRSAKey_t LoadTestRSAKey; L1_GenerateRSASignature_t GenerateRSASignature; - L1_DeriveKeysFromSessionKey_t DeriveKeysFromSessionKey; + L1_DeriveKeysFromSessionKey_V18_t DeriveKeysFromSessionKey_V18; L1_APIVersion_t APIVersion; L1_SecurityPatchLevel_t SecurityPatchLevel; L1_SecurityLevel_V16_t SecurityLevel_V16; @@ -392,6 +410,8 @@ struct FunctionPointers { L1_FreeSecureBuffer_t FreeSecureBuffer; L1_MaximumUsageTableHeaderSize_t MaximumUsageTableHeaderSize; L1_LoadProvisioning_t LoadProvisioning; + L1_LoadProvisioningCast_t LoadProvisioningCast; + L1_LoadProvisioning_V18_t LoadProvisioning_V18; L1_MinorAPIVersion_t MinorAPIVersion; L1_OPK_SerializationVersion_t OPK_SerializationVersion; L1_CreateEntitledKeySession_t CreateEntitledKeySession; @@ -950,8 +970,8 @@ class Adapter { LOOKUP_ALL(13, CreateUsageTableHeader, OEMCrypto_CreateUsageTableHeader); LOOKUP_ALL(13, DeactivateUsageEntry, OEMCrypto_DeactivateUsageEntry); LOOKUP_ALL(16, DecryptCENC_V17, OEMCrypto_DecryptCENC_V17); - LOOKUP_ALL( 8, DeriveKeysFromSessionKey, OEMCrypto_DeriveKeysFromSessionKey); - LOOKUP_ALL(16, GenerateDerivedKeys, OEMCrypto_GenerateDerivedKeys); + LOOKUP_ALL( 8, DeriveKeysFromSessionKey_V18, OEMCrypto_DeriveKeysFromSessionKey_V18); + LOOKUP_ALL(16, GenerateDerivedKeys_V18, OEMCrypto_GenerateDerivedKeys_V18); LOOKUP_ALL( 8, GenerateNonce, OEMCrypto_GenerateNonce); LOOKUP_ALL( 9, GenerateRSASignature, OEMCrypto_GenerateRSASignature); LOOKUP( 8, 15, GenerateSignature, OEMCrypto_GenerateSignature); @@ -981,7 +1001,8 @@ class Adapter { LOOKUP_ALL( 8, IsKeyboxOrOEMCertValid, OEMCrypto_IsKeyboxOrOEMCertValid); LOOKUP( 8, 15, LoadDeviceRSAKey, OEMCrypto_LoadDeviceRSAKey); LOOKUP_ALL(16, LoadDRMPrivateKey, OEMCrypto_LoadDRMPrivateKey); - LOOKUP_ALL(16, LoadLicense, OEMCrypto_LoadLicense); + LOOKUP_ALL(19, LoadLicense, OEMCrypto_LoadLicense); + LOOKUP_ALL(16, LoadLicense_V18, OEMCrypto_LoadLicense_V18); LOOKUP(15, 16, LoadEntitledContentKeys_V16,OEMCrypto_LoadEntitledContentKeys_V16); LOOKUP_ALL(17, LoadEntitledContentKeys, OEMCrypto_LoadEntitledContentKeys); LOOKUP_ALL(14, LoadTestKeybox, OEMCrypto_LoadTestKeybox); @@ -1008,7 +1029,9 @@ class Adapter { LOOKUP_ALL(16, AllocateSecureBuffer, OEMCrypto_AllocateSecureBuffer); LOOKUP_ALL(16, FreeSecureBuffer, OEMCrypto_FreeSecureBuffer); LOOKUP_ALL(16, MaximumUsageTableHeaderSize, OEMCrypto_MaximumUsageTableHeaderSize); - LOOKUP_ALL(16, LoadProvisioning, OEMCrypto_LoadProvisioning); + LOOKUP_ALL(16, LoadProvisioning_V18, OEMCrypto_LoadProvisioning_V18); + LOOKUP_ALL(19, LoadProvisioning, OEMCrypto_LoadProvisioning); + LOOKUP_ALL(19, LoadProvisioningCast, OEMCrypto_LoadProvisioningCast); LOOKUP_ALL(16, MinorAPIVersion, OEMCrypto_MinorAPIVersion); LOOKUP_ALL(16, OPK_SerializationVersion, OEMCrypto_OPK_SerializationVersion); LOOKUP_ALL(17, CreateEntitledKeySession, OEMCrypto_CreateEntitledKeySession); @@ -1077,9 +1100,9 @@ class Adapter { level3_.Terminate = Level3_Terminate; level3_.OpenSession = Level3_OpenSession; level3_.CloseSession = Level3_CloseSession; - level3_.GenerateDerivedKeys = Level3_GenerateDerivedKeys; + level3_.GenerateDerivedKeys_V18 = Level3_GenerateDerivedKeys; level3_.GenerateNonce = Level3_GenerateNonce; - level3_.LoadLicense = Level3_LoadLicense; + level3_.LoadLicense_V18 = Level3_LoadLicense; level3_.LoadEntitledContentKeys = Level3_LoadEntitledContentKeys; level3_.LoadRenewal = Level3_LoadRenewal; level3_.QueryKeyControl = Level3_QueryKeyControl; @@ -1097,7 +1120,7 @@ class Adapter { level3_.LoadOEMPrivateKey = Level3_LoadOEMPrivateKey; level3_.LoadTestRSAKey = Level3_LoadTestRSAKey; level3_.GenerateRSASignature = Level3_GenerateRSASignature; - level3_.DeriveKeysFromSessionKey = Level3_DeriveKeysFromSessionKey; + level3_.DeriveKeysFromSessionKey_V18 = Level3_DeriveKeysFromSessionKey; level3_.APIVersion = Level3_APIVersion; level3_.MinorAPIVersion = Level3_MinorAPIVersion; level3_.SecurityPatchLevel = Level3_SecurityPatchLevel; @@ -1130,7 +1153,7 @@ class Adapter { level3_.SupportsDecryptHash = Level3_SupportsDecryptHash; level3_.SetDecryptHash = Level3_SetDecryptHash; level3_.GetHashErrorCode = Level3_GetHashErrorCode; - level3_.LoadProvisioning = Level3_LoadProvisioning; + level3_.LoadProvisioning_V18 = Level3_LoadProvisioning; level3_.PrepAndSignProvisioningRequest = Level3_PrepAndSignProvisioningRequest; level3_.PrepAndSignLicenseRequest = Level3_PrepAndSignLicenseRequest; level3_.PrepAndSignRenewalRequest = Level3_PrepAndSignRenewalRequest; @@ -1160,6 +1183,9 @@ class Adapter { level3_.Generic_Verify = Level3_Generic_Verify; level3_.GetSignatureHashAlgorithm = nullptr; level3_.EnterTestMode = nullptr; + level3_.LoadLicense = nullptr; + level3_.LoadProvisioning = nullptr; + level3_.LoadProvisioningCast = nullptr; // clang-format on level3_.version = Level3_APIVersion(); @@ -1992,19 +2018,19 @@ extern "C" OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session) { return gAdapter->CloseSession(session); } -extern "C" OEMCryptoResult OEMCrypto_GenerateDerivedKeys( +extern "C" OEMCryptoResult OEMCrypto_GenerateDerivedKeys_V18( OEMCrypto_SESSION session, const uint8_t* mac_key_context, size_t mac_key_context_length, const uint8_t* enc_key_context, size_t enc_key_context_length) { if (!gAdapter.get()) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = gAdapter->GetSession(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; - if (pair.fcn->GenerateDerivedKeys == nullptr) { + if (pair.fcn->GenerateDerivedKeys_V18 == nullptr) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - return pair.fcn->GenerateDerivedKeys(pair.session, mac_key_context, - mac_key_context_length, enc_key_context, - enc_key_context_length); + return pair.fcn->GenerateDerivedKeys_V18( + pair.session, mac_key_context, mac_key_context_length, enc_key_context, + enc_key_context_length); } extern "C" OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, @@ -2087,20 +2113,49 @@ const uint8_t* PointerOrNull(const uint8_t* pointer, size_t length) { return length ? pointer : nullptr; } -extern "C" 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) { +template +std::vector MakeContext(const char (&key_label)[N], + const uint8_t* context, size_t context_length, + uint32_t suffix) { + // TODO(b/299343035): Use ODK methods. + std::vector ret; + ret.insert(ret.end(), key_label, key_label + N); + ret.insert(ret.end(), context, context + context_length); + const uint32_t suffix_net = htonl(suffix); + auto* ptr = reinterpret_cast(&suffix_net); + ret.insert(ret.end(), ptr, ptr + sizeof(suffix_net)); + return ret; +} + +extern "C" 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) { if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = gAdapter->GetSession(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; if (pair.fcn->LoadLicense == nullptr) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + if (pair.fcn->LoadLicense_V18 == nullptr || + pair.fcn->DeriveKeysFromSessionKey_V18 == nullptr) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + + const std::vector mac_context = + MakeContext("AUTHENTICATION", context, context_length, 0x200); + const std::vector enc_context = + MakeContext("ENCRYPTION", context, context_length, 0x80); + const OEMCryptoResult result = pair.fcn->DeriveKeysFromSessionKey_V18( + session, derivation_key, derivation_key_length, mac_context.data(), + mac_context.size(), enc_context.data(), enc_context.size()); + if (result != OEMCrypto_SUCCESS) return result; + return pair.fcn->LoadLicense_V18(session, message, message_length, + core_message_length, signature, + signature_length); } - return pair.fcn->LoadLicense(pair.session, message, message_length, - core_message_length, signature, + return pair.fcn->LoadLicense(pair.session, context, context_length, + derivation_key, derivation_key_length, message, + message_length, core_message_length, signature, signature_length); } @@ -2144,7 +2199,7 @@ extern "C" OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session, if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = gAdapter->GetSession(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; - if (pair.fcn->LoadLicense == nullptr) { + if (pair.fcn->LoadRenewal == nullptr) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } return pair.fcn->LoadRenewal(pair.session, message, message_length, @@ -2334,15 +2389,66 @@ extern "C" OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, } extern "C" OEMCryptoResult OEMCrypto_LoadProvisioning( - 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) { + OEMCrypto_SESSION session, const uint8_t* request, size_t 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) { if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = gAdapter->GetSession(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; if (pair.fcn->LoadProvisioning != nullptr) { return pair.fcn->LoadProvisioning( + pair.session, request, request_length, message, message_length, + core_message_length, signature, signature_length, wrapped_private_key, + wrapped_private_key_length); + } + if (pair.fcn->LoadProvisioning_V18 != nullptr && + pair.fcn->GenerateDerivedKeys_V18 != nullptr) { + const std::vector mac_context = + MakeContext("AUTHENTICATION", request, request_length, 0x200); + const std::vector enc_context = + MakeContext("ENCRYPTION", request, request_length, 0x80); + const OEMCryptoResult result = pair.fcn->GenerateDerivedKeys_V18( + pair.session, mac_context.data(), mac_context.size(), + enc_context.data(), enc_context.size()); + if (result != OEMCrypto_SUCCESS) return result; + + return pair.fcn->LoadProvisioning_V18( + pair.session, message, message_length, core_message_length, signature, + signature_length, wrapped_private_key, wrapped_private_key_length); + } + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +extern "C" 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) { + if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + LevelSession pair = gAdapter->GetSession(session); + if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; + if (pair.fcn->LoadProvisioningCast != nullptr) { + return pair.fcn->LoadProvisioningCast( + pair.session, derivation_key, derivation_key_length, provision_request, + provision_request_length, message, message_length, core_message_length, + signature, signature_length, wrapped_private_key, + wrapped_private_key_length); + } + if (pair.fcn->LoadProvisioning_V18 != nullptr && + pair.fcn->DeriveKeysFromSessionKey_V18 != nullptr) { + const std::vector mac_context = MakeContext( + "AUTHENTICATION", provision_request, provision_request_length, 0x200); + const std::vector enc_context = MakeContext( + "ENCRYPTION", provision_request, provision_request_length, 0x80); + const OEMCryptoResult result = pair.fcn->DeriveKeysFromSessionKey_V18( + pair.session, derivation_key, derivation_key_length, mac_context.data(), + mac_context.size(), enc_context.data(), enc_context.size()); + if (result != OEMCrypto_SUCCESS) return result; + + return pair.fcn->LoadProvisioning_V18( pair.session, message, message_length, core_message_length, signature, signature_length, wrapped_private_key, wrapped_private_key_length); } @@ -2393,7 +2499,7 @@ extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature( padding_scheme); } -extern "C" OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( +extern "C" OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey_V18( OEMCrypto_SESSION session, const uint8_t* enc_session_key, size_t enc_session_key_length, const uint8_t* mac_key_context, size_t mac_key_context_length, const uint8_t* enc_key_context, @@ -2401,9 +2507,9 @@ extern "C" OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = gAdapter->GetSession(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; - if (pair.fcn->DeriveKeysFromSessionKey == nullptr) + if (pair.fcn->DeriveKeysFromSessionKey_V18 == nullptr) return OEMCrypto_ERROR_NOT_IMPLEMENTED; - return pair.fcn->DeriveKeysFromSessionKey( + return pair.fcn->DeriveKeysFromSessionKey_V18( pair.session, enc_session_key, enc_session_key_length, mac_key_context, mac_key_context_length, enc_key_context, enc_key_context_length); } diff --git a/libwvdrmengine/cdm/core/test/fake_provisioning_server.cpp b/libwvdrmengine/cdm/core/test/fake_provisioning_server.cpp index 359307e3..defe8229 100644 --- a/libwvdrmengine/cdm/core/test/fake_provisioning_server.cpp +++ b/libwvdrmengine/cdm/core/test/fake_provisioning_server.cpp @@ -275,18 +275,14 @@ bool FakeProvisioningServer::MakeResponse( // Next, we derive the keys from the keybox device key. This is Provisioning // 2.0 specific. // TODO(b/141438127): Add support for provisioing 3.0. - std::string mac_context; - GenerateMacContext(serialized_message, &mac_context); - std::vector mac_context_v(mac_context.begin(), mac_context.end()); - std::string enc_context; - GenerateEncryptContext(serialized_message, &enc_context); - std::vector enc_context_v(enc_context.begin(), enc_context.end()); wvoec::KeyDeriver key_deriver; + std::vector serialized_message_v(serialized_message.begin(), + serialized_message.end()); // Not only is this Prov 2.0 specific, it assumes the device is using the // standard test keybox. key_deriver.DeriveKeys(wvoec::kTestKeybox.device_key_, - sizeof(wvoec::kTestKeybox.device_key_), mac_context_v, - enc_context_v); + sizeof(wvoec::kTestKeybox.device_key_), + serialized_message_v); // Create a structure to hold the RSA private key. This is used by the key // deriver to encrypt the key. diff --git a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h index 2652e943..a3097ee8 100644 --- a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h +++ b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h @@ -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); + /****************************************************************************/ /****************************************************************************/ diff --git a/libwvdrmengine/oemcrypto/test/oec_key_deriver.cpp b/libwvdrmengine/oemcrypto/test/oec_key_deriver.cpp index 21d50781..fcca9449 100644 --- a/libwvdrmengine/oemcrypto/test/oec_key_deriver.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_key_deriver.cpp @@ -37,6 +37,23 @@ using namespace std; namespace wvoec { +namespace { + +std::vector CreateContext(const char* prefix, + const std::vector& context, + uint32_t suffix) { + std::vector 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(&suffix_net); + ret.insert(ret.end(), ptr, ptr + sizeof(suffix_net)); + return ret; +} + +} // namespace + void Encryptor::set_enc_key(const std::vector& 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& mac_key_context, - const vector& enc_key_context) { + const vector& 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& context, + const char* mac_label, const char* enc_label) { + // TODO: Use ODK constants instead + const std::vector mac_key_context = + CreateContext(mac_label, context, 0x200); + const std::vector enc_key_context = + CreateContext(enc_label, context, 0x80); + // Generate derived key for mac key std::vector mac_key_part2; DeriveKey(master_key, master_key_size, mac_key_context, 1, &mac_key_server_); diff --git a/libwvdrmengine/oemcrypto/test/oec_key_deriver.h b/libwvdrmengine/oemcrypto/test/oec_key_deriver.h index 57d8fc1d..9da7e635 100644 --- a/libwvdrmengine/oemcrypto/test/oec_key_deriver.h +++ b/libwvdrmengine/oemcrypto/test/oec_key_deriver.h @@ -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& mac_key_context, - const std::vector& enc_key_context); + const std::vector& context); + void DeriveKeys(const uint8_t* master_key, size_t master_key_size, + const std::vector& 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* signature) const; diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp index 95b6c461..31265aaa 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.cpp @@ -234,7 +234,8 @@ RoundTrip:: // 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 context = session()->GetDefaultContext(); + const size_t small_size = context.size(); // arbitrary. if (RequestHasNonce()) { session()->GenerateNonce(); } @@ -252,7 +253,10 @@ RoundTrip:: size_t message_size = std::max(required_message_size_, core_message_length + small_size); vector 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(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& data, const vector& 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 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 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(&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 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 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(&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* mac_context, - vector* enc_context) { - /* Context strings - * These context strings are normally created by the CDM layer +vector 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 mac_context; - vector 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& context) { key_deriver_.DeriveKeys(keybox.device_key_, sizeof(keybox.device_key_), - mac_context, enc_context); + context); } void Session::GenerateDerivedKeysFromSessionKey() { - // Uses test certificate. - vector session_key; - vector 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 mac_context; - vector 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& 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& message, FAIL() << "No public RSA or ECC key loaded in test code"; } -bool Session::GenerateRsaSessionKey(vector* session_key, - vector* 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* session_key, - vector* 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* 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* session_key, - vector* 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; diff --git a/libwvdrmengine/oemcrypto/test/oec_session_util.h b/libwvdrmengine/oemcrypto/test/oec_session_util.h index 64af9f45..f5764911 100644 --- a/libwvdrmengine/oemcrypto/test/oec_session_util.h +++ b/libwvdrmengine/oemcrypto/test/oec_session_util.h @@ -276,7 +276,7 @@ class ProvisioningRoundTrip const std::vector& 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 request_; + const wvoec::WidevineKeybox* keybox_; // The message key used for Prov 3.0. - std::vector message_key_; - std::vector encrypted_message_key_; std::vector encoded_rsa_key_; std::vector 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* mac_context, - vector* enc_context); + // Fill the vector with test context which generate known mac and enc keys. + std::vector 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& 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& 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* session_key, - vector* 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* session_key, - vector* ecdh_public_key_data); + bool GenerateEccSessionKey(); // Based on the key type installed, call GenerateRsaSessionKey or // GenerateEccSessionKey. - bool GenerateSessionKey(vector* session_key, - vector* 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& key_handle() { return key_handle_; } + const std::vector& session_key() const { return session_key_; } + const std::vector& 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 pst_report_buffer_; MessageData license_ = {}; vector key_handle_; + std::vector session_key_; + std::vector enc_session_key_; vector encrypted_usage_entry_; uint32_t usage_entry_number_ = 0; diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp index abdc28eb..a604b030 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.cpp @@ -49,7 +49,6 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, ForbidUseAsDRMCert) { if (key_loaded_) { // The other padding scheme should fail. DisallowForbiddenPaddingDRMKey(kSign_RSASSA_PSS, 83); - DisallowDeriveKeys(); } } diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.h b/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.h index 6c9c7269..3317fb7b 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.h +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_cast_test.h @@ -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 session_key; - vector 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 mac_context; - vector 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) { diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_license_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_license_test.cpp index d586501a..e089b96c 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_license_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_license_test.cpp @@ -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 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(), diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp index 379ec306..69b17fd8 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_provisioning_test.cpp @@ -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 mac_context(max_size); - vector 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 session_key; - vector 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 mac_context; - vector 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 session_key; - vector enc_session_key; - ASSERT_TRUE(session_.GenerateSessionKey(&session_key, &enc_session_key)); - const size_t max_size = GetResourceValue(kLargeMessageSize); - vector mac_context(max_size); - vector 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 diff --git a/libwvdrmengine/oemcrypto/test/ota_keybox_test.cpp b/libwvdrmengine/oemcrypto/test/ota_keybox_test.cpp index d1a94641..464e30d0 100644 --- a/libwvdrmengine/oemcrypto/test/ota_keybox_test.cpp +++ b/libwvdrmengine/oemcrypto/test/ota_keybox_test.cpp @@ -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 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 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 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 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 message( request.data(), request.data() + request.size() - HMAC_SHA256_SIGNATURE_SIZE);