diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 08f52835..92eccc63 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -313,6 +313,9 @@ typedef OEMCryptoResult (*L1_Generic_Verify_t)( typedef OEMCryptoResult (*L1_GetSignatureHashAlgorithm_t)( OEMCrypto_SESSION session, OEMCrypto_SignatureHashAlgorithm* algorithm); typedef OEMCryptoResult (*L1_EnterTestMode_t)(void); +typedef OEMCryptoResult (*L1_WrapClearPrivateKey_t)( + const uint8_t* clear_private_key_bytes, size_t clear_private_key_length, + uint8_t* wrapped_private_key, size_t* wrapped_private_key_length); struct FunctionPointers { wvcdm::CdmSecurityLevel security_level; @@ -417,6 +420,7 @@ struct FunctionPointers { L1_Generic_Verify_t Generic_Verify; L1_GetSignatureHashAlgorithm_t GetSignatureHashAlgorithm; L1_EnterTestMode_t EnterTestMode; + L1_WrapClearPrivateKey_t WrapClearPrivateKey; }; // The WatchDog looks after a worker thread that is trying to initialize L3. @@ -1028,6 +1032,7 @@ class Adapter { LOOKUP_ALL(18, Generic_Verify, OEMCrypto_Generic_Verify); LOOKUP_ALL(18, GetSignatureHashAlgorithm, OEMCrypto_GetSignatureHashAlgorithm); LOOKUP_ALL(18, EnterTestMode, OEMCrypto_EnterTestMode); + LOOKUP_ALL(18, WrapClearPrivateKey, OEMCrypto_WrapClearPrivateKey); // clang-format on @@ -2940,3 +2945,16 @@ extern "C" OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport( extern "C" OEMCryptoResult OEMCrypto_ProductionReady(void) { return wvcdm::OEMCrypto_ProductionReady(kLevelDefault); } + +extern "C" OEMCryptoResult OEMCrypto_WrapClearPrivateKey( + const uint8_t* clear_private_key_bytes, size_t clear_private_key_length, + uint8_t* wrapped_private_key, size_t* wrapped_private_key_length) { + if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; + const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault); + if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; + if (fcn->WrapClearPrivateKey == nullptr) + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + return fcn->WrapClearPrivateKey(clear_private_key_bytes, + clear_private_key_length, wrapped_private_key, + wrapped_private_key_length); +} diff --git a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h index 752f536c..3af90407 100644 --- a/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h +++ b/libwvdrmengine/oemcrypto/include/OEMCryptoCENC.h @@ -714,6 +714,7 @@ typedef enum OEMCrypto_SignatureHashAlgorithm { #define OEMCrypto_EnterTestMode _oecc140 #define OEMCrypto_GetDeviceSignedCsrPayload _oecc141 #define OEMCrypto_FactoryInstallBCCSignature _oecc142 +#define OEMCrypto_WrapClearPrivateKey _oecc154 // clang-format on /// @addtogroup initcontrol @@ -3145,6 +3146,51 @@ OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void); OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id, size_t* device_id_length); +/** + * Encrypts a clear device RSA/ECC key with an internal key (such as the OEM + * key or Widevine Keybox key) and a generated IV using AES-128-CBC with PKCS#5 + * padding. + * + * Copies the wrapped key to the buffer specified by |wrapped_private_key| and + * sets the size of the wrapped key to |wrapped_private_key_length|. + * + * The clear private key is encoded in PKCS#8 binary DER format. The OEMCrypto + * library shall verify that this RSA key is valid. + * + * The clear key should be encrypted using the same device specific key used in + * OEMCrypto_LoadProvisioning. The wrapped private key will be unwrapped in the + * function OEMCrypto_LoadDRMPrivateKey. + * + * This function should only be implemented for factory builds. + * + * @param[in] clear_private_key_bytes: pointer to memory containing the + * unencrypted private key data. + * @param[in] clear_private_key_length: the length of the private key data. + * @param[out] wrapped_private_key: pointer to buffer in which the encrypted + * 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, + * or required length if provided length is too small. + * + * @retval OEMCrypto_SUCCESS on success + * @retval OEMCrypto_ERROR_INVALID_CONTEXT clear_private_key_bytes is NULL, or + * clear private key fails to parse as PKCS#8 + * @retval OEMCrypto_ERROR_SHORT_BUFFER wrapped_private_key_length is too small, + * or wrapped_private_key is NULL + * + * @threading + * This is an "Initialization and Termination Function" and will not be + * called simultaneously with any other function, as if the CDM holds a write + * lock on the OEMCrypto system. + * + * @version + * This method is new in API version 18.6. + */ +OEMCryptoResult OEMCrypto_WrapClearPrivateKey( + const uint8_t* clear_private_key_bytes, size_t clear_private_key_length, + uint8_t* wrapped_private_key, size_t* wrapped_private_key_length); + /// @} /// @addtogroup keybox diff --git a/libwvdrmengine/oemcrypto/test/GEN_api_lock_file.c b/libwvdrmengine/oemcrypto/test/GEN_api_lock_file.c index 9305120a..91473cce 100644 --- a/libwvdrmengine/oemcrypto/test/GEN_api_lock_file.c +++ b/libwvdrmengine/oemcrypto/test/GEN_api_lock_file.c @@ -369,3 +369,9 @@ OEMCryptoResult _oecc140(void); // OEMCrypto_FactoryInstallBCCSignature defined in v18.3 OEMCryptoResult _oecc142(const uint8_t* signature, size_t signature_length); + +// OEMCrypto_WrapClearPrivateKey defined in v18.6 +OEMCryptoResult _oecc154(const uint8_t* clear_private_key_bytes, + size_t clear_private_key_length, + uint8_t* wrapped_private_key, + size_t* wrapped_private_key_length);