// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine Master // License Agreement. #ifndef CRYPTO_SESSION_H #define CRYPTO_SESSION_H #include #include #include #include #include "OEMCryptoCENC.h" #include "cas_status.h" #include "cas_types.h" #include "crypto_wrapped_key.h" #include "oemcrypto_interface.h" #include "rw_lock.h" namespace wvcas { struct KeySlot { std::vector key_id; std::vector entitlement_key_id; std::vector wrapped_key; std::vector wrapped_key_iv; std::vector content_iv; CryptoMode cipher_mode; }; struct SubSample { uint32_t num_bytes_of_clear; uint32_t num_bytes_of_encrypted; }; typedef OEMCrypto_HDCP_Capability HdcpCapability; class CryptoLock { public: CryptoLock() {}; // These methods should be used to take the various CryptoSession mutexes in // preference to taking the mutexes directly. // // A lock should be taken on the Static Field Mutex before accessing any of // CryptoSession's non-atomic static fields. It can be taken as a reader or as // a writer, depending on how you will be accessing the static fields. // // Before calling into OEMCrypto, code must take locks on the OEMCrypto Mutex // and/or the OEMCrypto Session Mutex. Which of them should be taken and how // depends on the OEMCrypto function being called; consult the OEMCrypto // specification's threading guarantees before making any calls. The OEMCrypto // specification defines several classes of functions for the purposes of // parallelism. The methods below lock the OEMCrypto Mutex and OEMCrypto // Session Mutex in the correct order and manner to fulfill the guarantees in // the specification. // // For this function class... | ...use this locking method // ------------------------------+--------------------------- // Initialization & Termination | WithOecWriteLock() // Property | WithOecReadLock() // Session Initialization | WithOecWriteLock() // Usage Table | WithOecWriteLock() // Session | WithOecSessionLock() // // Note that accessing |key_session_| often accesses the OEMCrypto session, so // WithOecSessionLock() should be used before accessing |key_session_| as // well. // // If a function needs to take a lock on both the Static Field Mutex and some // of the OEMCrypto mutexes simultaneously, it must *always* lock the Static // Field Mutex before the OEMCrypto mutexes. // // In general, all locks should only be held for the minimum time necessary // (e.g. a lock on the OEMCrypto mutexes should only be held for the duration // of a single call into OEMCrypto) unless there is a compelling argument // otherwise, such as making two calls into OEMCrypto immediately after each // other. template static auto WithStaticFieldWriteLock(const char* tag, Func body) -> decltype(body()); template static auto WithStaticFieldReadLock(const char* tag, Func body) -> decltype(body()); template static auto WithOecWriteLock(const char* tag, Func body) -> decltype(body()); template static auto WithOecReadLock(const char* tag, Func body) -> decltype(body()); template auto WithOecSessionLock(const char* tag, Func body) -> decltype(body()); private: // The locking methods above should be used in preference to taking these // mutexes directly. If code takes these manually and needs to take more // than one, it must *always* take them in the order they are defined here. static wvutil::shared_mutex static_field_mutex_; static wvutil::shared_mutex oem_crypto_mutex_; std::mutex oem_crypto_session_mutex_; }; class CryptoInterface { CryptoInterface(); public: virtual ~CryptoInterface(); virtual OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session); virtual OEMCryptoResult OEMCrypto_CloseSession(OEMCrypto_SESSION session); virtual OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(); virtual OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength); virtual uint32_t OEMCrypto_SupportedCertificates(); virtual OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, uint32_t* nonce); virtual OEMCryptoResult OEMCrypto_GenerateDerivedKeys( OEMCrypto_SESSION session, const uint8_t* mac_key_context, uint32_t mac_key_context_length, const uint8_t* enc_key_context, uint32_t enc_key_context_length); virtual OEMCryptoResult OEMCrypto_PrepAndSignLicenseRequest( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_size, uint8_t* signature, size_t* signature_length); virtual OEMCryptoResult OEMCrypto_PrepAndSignRenewalRequest( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_size, uint8_t* signature, size_t* signature_length); virtual OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( OEMCrypto_SESSION session, uint8_t* message, size_t message_length, size_t* core_message_size, uint8_t* signature, size_t* signature_length); virtual 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); virtual OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( OEMCrypto_SESSION session, uint8_t* public_cert, size_t* public_cert_length); virtual OEMCryptoResult OEMCrypto_LoadDRMPrivateKey( OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length); virtual OEMCryptoResult OEMCrypto_GenerateRSASignature( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme); virtual OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( 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, size_t enc_key_context_length); virtual 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); virtual OEMCryptoResult OEMCrypto_LoadRenewal(OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, size_t core_message_length, const uint8_t* signature, size_t signature_length); virtual OEMCryptoResult OEMCrypto_LoadCasECMKeys( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const OEMCrypto_EntitledContentKeyObject* even_key, const OEMCrypto_EntitledContentKeyObject* odd_key); virtual OEMCryptoResult OEMCrypto_GetHDCPCapability( OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* max); virtual OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength); virtual const char* OEMCrypto_SecurityLevel(); virtual OEMCryptoResult OEMCrypto_CreateEntitledKeySession( OEMCrypto_SESSION session, OEMCrypto_SESSION* entitled_key_session_id); virtual OEMCryptoResult OEMCrypto_RemoveEntitledKeySession( OEMCrypto_SESSION entitled_key_session_id); virtual OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession( OEMCrypto_SESSION key_sid, OEMCrypto_SESSION oec_sid); virtual uint32_t OEMCrypto_APIVersion(); virtual OEMCryptoResult OEMCrypto_GetOEMKeyToken( OEMCrypto_SESSION key_session, uint8_t* key_token, size_t* key_token_length); virtual OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm( OEMCrypto_SESSION session, OEMCrypto_SignatureHashAlgorithm* algorithm); virtual OEMCryptoResult OEMCrypto_GetBootCertificateChain( uint8_t* bcc, size_t* bcc_length, uint8_t* additional_signature, size_t* additional_signature_length); virtual OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair( OEMCrypto_SESSION session, uint8_t* public_key, size_t* public_key_length, uint8_t* public_key_signature, size_t* public_key_signature_length, uint8_t* wrapped_private_key, size_t* wrapped_private_key_length, OEMCrypto_PrivateKeyType* key_type); virtual OEMCryptoResult OEMCrypto_InstallOemPrivateKey( OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, const uint8_t* wrapped_private_key, size_t wrapped_private_key_length); virtual uint8_t OEMCrypto_Security_Patch_Level(); virtual OEMCryptoResult OEMCrypto_BuildInformation(char* buffer, size_t* buffer_length); // This is the factory method used to enable the oemcrypto interface. static OEMCryptoResult create(std::unique_ptr* init) { // This is *the* oemcrypto interface used in the normal running. There is // only one and there is not need to destroy it. static OEMCryptoInterface oemcrypto_interface; return create_internal(&oemcrypto_interface, init); } // This initializer factory method is templated to allow tests to pass in // a mocked OEMCryptoInterface. The caller retains ownership of // |oemcrypto_interface|. template static OEMCryptoResult create(std::unique_ptr* init, CI* oemcrypto_interface) { return create_internal(oemcrypto_interface, init); } CryptoInterface(const CryptoInterface&) = delete; CryptoInterface& operator=(const CryptoInterface&) = delete; private: static OEMCryptoResult create_internal( OEMCryptoInterface* oemcrypto_interface, std::unique_ptr* init); static bool initialized_; static int session_count_; static std::unique_ptr lock_; OEMCryptoInterface* oemcrypto_interface_; }; class SupportedCertificates { public: explicit SupportedCertificates(uint32_t supported) : supported_(supported) {} bool rsa_2048bit() { return OEMCrypto_Supports_RSA_2048bit & supported_; } bool rsa_3072bit() { return OEMCrypto_Supports_RSA_3072bit & supported_; } bool rsa_CASTbit() { return OEMCrypto_Supports_RSA_CAST & supported_; } private: uint32_t supported_; }; // CryptoSession implements the core methods need to interface with OEMCrypto. class CryptoSession { public: explicit CryptoSession(); virtual ~CryptoSession(); virtual CasStatus initialize(); virtual CasStatus reset(); virtual CasStatus close(); virtual CasProvisioningMethod provisioning_method(); virtual CasStatus GetKeyData(uint8_t* keyData, size_t* keyDataLength); virtual SupportedCertificates supported_certificates(); virtual CasStatus GenerateNonce(uint32_t* nonce); virtual CasStatus GenerateDerivedKeys(const uint8_t* mac_key_context, uint32_t mac_key_context_length, const uint8_t* enc_key_context, uint32_t enc_key_context_length); virtual CasStatus PrepareAndSignLicenseRequest( const std::string& message, std::string* core_message, std::string* signature, bool& should_specify_algorithm, OEMCrypto_SignatureHashAlgorithm& algorithm); virtual CasStatus PrepareAndSignRenewalRequest(const std::string& message, std::string* core_message, std::string* signature); virtual CasStatus PrepareAndSignProvisioningRequest( const std::string& message, std::string* core_message, std::string* signature, bool& should_specify_algorithm, OEMCrypto_SignatureHashAlgorithm& algorithm); virtual CasStatus LoadProvisioning(const std::string& signed_message, const std::string& core_message, const std::string& signature, std::string* wrapped_private_key); virtual CasStatus GetOEMPublicCertificate(uint8_t* public_cert, size_t* public_cert_length); virtual CasStatus GenerateRSASignature(const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme); virtual CasStatus DeriveKeysFromSessionKey(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, size_t enc_key_context_length); virtual CasStatus LoadLicense(const std::string& signed_message, const std::string& core_message, const std::string& signature); virtual CasStatus LoadRenewal(const std::string& signed_message, const std::string& core_message, const std::string& signature); // LoadCasECMKeys loads the ecm keys into the crypto library making them // available for use. // |odd_key| - if not null, contains control word data. // |even_key| - if not null, contains control word data. virtual CasStatus LoadCasECMKeys(OEMCrypto_SESSION session, const KeySlot* even_key, const KeySlot* odd_key); virtual bool GetHdcpCapabilities(HdcpCapability* current, HdcpCapability* max); virtual CasStatus GetDeviceID(std::string* buffer); virtual const char* SecurityLevel(); virtual CasStatus CreateEntitledKeySession( OEMCrypto_SESSION* entitled_key_session_id); virtual CasStatus RemoveEntitledKeySession( OEMCrypto_SESSION entitled_key_session_id); virtual CasStatus ReassociateEntitledKeySession( OEMCrypto_SESSION entitled_key_session_id); virtual CasStatus APIVersion(uint32_t* api_version); virtual CasStatus GetOEMKeyToken(OEMCrypto_SESSION entitled_key_session_id, std::vector& token); virtual CasStatus GetBootCertificateChain(std::string* bcc, std::string* additional_signature); virtual CasStatus GenerateCertificateKeyPair( std::string* public_key, std::string* public_key_signature, std::string* wrapped_private_key, CryptoWrappedKey::Type* key_type); virtual CasStatus LoadOemCertificatePrivateKey( const CryptoWrappedKey& private_key); virtual CasStatus LoadCertificatePrivateKey( const CryptoWrappedKey& private_key); virtual uint8_t GetSecurityPatchLevel(); virtual bool GetBuildInformation(std::string* info); CryptoSession(const CryptoSession&) = delete; CryptoSession& operator=(const CryptoSession&) = delete; private: virtual OEMCryptoResult getCryptoInterface( std::unique_ptr* interface); // TODO(jfore, widevine-eng): Merge CryptoInterface into CryptoSession and // drop this shared pointer. std::unique_ptr crypto_interface_; OEMCrypto_SESSION session_; }; } // namespace wvcas #endif // CRYPTO_SESSION_H