Document OEMCrypto_LoadProvisioningCast
Bug: 314222872 Change-Id: I05031d1eacefceb73931b979ef69e69fdba871a7
This commit is contained in:
committed by
Robert Shih
parent
ce2af4e96a
commit
34ac11b187
@@ -723,14 +723,26 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
}
|
||||
|
||||
CryptoWrappedKey private_key;
|
||||
const CdmResponseType status = crypto_session_->LoadProvisioning(
|
||||
request_, signed_message, core_message, signature, &private_key.key());
|
||||
// TODO(b/316053127): clean this up a bit.
|
||||
if (cert_type_ == kCertificateX509) {
|
||||
const std::string dummy_key;
|
||||
const CdmResponseType status = crypto_session_->LoadProvisioningCast(
|
||||
dummy_key, request_, signed_message, core_message, signature,
|
||||
&private_key.key());
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("LoadProvisioning failed: status = %d", static_cast<int>(status));
|
||||
return status;
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("LoadProvisioning failed: status = %d", static_cast<int>(status));
|
||||
return status;
|
||||
}
|
||||
} else {
|
||||
const CdmResponseType status = crypto_session_->LoadProvisioning(
|
||||
request_, signed_message, core_message, signature, &private_key.key());
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("LoadProvisioning failed: status = %d", static_cast<int>(status));
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
const CdmSecurityLevel security_level = crypto_session_->GetSecurityLevel();
|
||||
CloseSession();
|
||||
|
||||
|
||||
@@ -462,9 +462,11 @@ typedef enum OEMCrypto_Clock_Security_Level {
|
||||
} OEMCrypto_Clock_Security_Level;
|
||||
|
||||
typedef uint8_t RSA_Padding_Scheme;
|
||||
// RSASSA-PSS with SHA1.
|
||||
// RSASSA-PSS with SHA1. Scheme used for DRM certificates for signing a license
|
||||
// request.
|
||||
#define kSign_RSASSA_PSS ((RSA_Padding_Scheme)0x1)
|
||||
// PKCS1 with block type 1 padding (only).
|
||||
// PKCS1 with block type 1 padding (only). Keys used with x509 Cast Receiver
|
||||
// certificates.
|
||||
#define kSign_PKCS1_Block1 ((RSA_Padding_Scheme)0x2)
|
||||
|
||||
/// @}
|
||||
@@ -3971,22 +3973,10 @@ OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm(
|
||||
* Below, all fields are found in the struct ODK_ParsedLicense parsed_license
|
||||
* returned by ODK_ParsedProvisioning.
|
||||
*
|
||||
* After decrypting `parsed_response->enc_private_key`, If the first four bytes
|
||||
* of the buffer are the string "SIGN", then the actual RSA key begins on the
|
||||
* 9th byte of the buffer. The second four bytes of the buffer is the 32 bit
|
||||
* field "allowed_schemes" of type RSA_Padding_Scheme, which is used in
|
||||
* OEMCrypto_GenerateRSASignature(). The value of allowed_schemes must also be
|
||||
* wrapped with RSA key. We recommend storing the magic string "SIGN" with
|
||||
* the key to distinguish keys that have a value for allowed_schemes from
|
||||
* those that should use the default allowed_schemes. Devices that do not
|
||||
* support the alternative signing algorithms may refuse to load these keys
|
||||
* and return an error of OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case
|
||||
* for these alternative signing algorithms is to support devices that use
|
||||
* X509 certificates for authentication when acting as a ChromeCast receiver.
|
||||
* This is not needed for devices that wish to send data to a ChromeCast.
|
||||
*
|
||||
* If the first four bytes of the buffer `enc_private_key` are not the string
|
||||
* "SIGN", then this key may not be used with OEMCrypto_GenerateRSASignature().
|
||||
* After decrypting `parsed_response->enc_private_key`, OEMCrypto shall verify
|
||||
* that the first four bytes of the buffer are *not* the string "SIGN". Keys
|
||||
* loaded with this function are DRM certificate private keys and may not be
|
||||
* used with OEMCrypto_GenerateRSASignature().
|
||||
*
|
||||
* Verification and Algorithm:
|
||||
* The following checks should be performed. If any check fails, an error is
|
||||
@@ -4002,34 +3992,21 @@ OEMCryptoResult OEMCrypto_GetSignatureHashAlgorithm(
|
||||
* derived encryption key (enc_key). Use enc_private_key_iv as the initial
|
||||
* vector for AES_128-CBC mode, with PKCS#5 padding. The private_key should
|
||||
* be kept in secure memory and protected from the user.
|
||||
* 6. If the first four bytes of the buffer private_key are the string "SIGN",
|
||||
* then the actual RSA key begins on the 9th byte of the buffer. The
|
||||
* second four bytes of the buffer is the 32 bit field
|
||||
* "allowed_schemes", of type RSA_Padding_Scheme, which is used in
|
||||
* OEMCrypto_GenerateRSASignature(). The value of allowed_schemes must
|
||||
* also be wrapped with RSA key. We recommend storing the magic string
|
||||
* "SIGN" with the key to distinguish keys that have a value for
|
||||
* allowed_schemes from those that should use the default
|
||||
* allowed_schemes. Devices that do not support the alternative signing
|
||||
* algorithms may refuse to load these keys and return an error of
|
||||
* OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these
|
||||
* alternative signing algorithms is to support devices that use X.509
|
||||
* certificates for authentication when acting as a ChromeCast receiver.
|
||||
* This is not needed for devices that wish to send data to a ChromeCast.
|
||||
* 7. If the first four bytes of the buffer private_key are not the string
|
||||
* "SIGN", this key may not be used with OEMCrypto_GenerateRSASignature().
|
||||
* 8. After possibly skipping past the first 8 bytes signifying the allowed
|
||||
* 6. Verify that the first four bytes of the buffer private_key are not the
|
||||
* string "SIGN". This key may not be used with
|
||||
* OEMCrypto_GenerateRSASignature().
|
||||
* 7. After possibly skipping past the first 8 bytes signifying the allowed
|
||||
* signing algorithm, the rest of the buffer private_key contains an ECC
|
||||
* private key or an RSA private key in PKCS#8 binary DER encoded
|
||||
* format. The OEMCrypto library shall verify that this private key is
|
||||
* valid.
|
||||
* 9. Re-encrypt the device private key with an internal key (such as one
|
||||
* 8. Re-encrypt the device private key with an internal key (such as one
|
||||
* derived by the OEM key or Widevine Keybox key) and the generated IV
|
||||
* using AES-128-CBC with PKCS#5 padding. The data should also be
|
||||
* signed. This algorithm is just a suggestion. The implementer may use any
|
||||
* suitable encrypting and validation algorithm with a key that ties it to
|
||||
* the device.
|
||||
* 10. Copy the rewrapped key to the buffer specified by wrapped_private_key
|
||||
* 9. Copy the rewrapped key to the buffer specified by wrapped_private_key
|
||||
* and the size of the wrapped key to wrapped_private_key_length.
|
||||
*
|
||||
* @param[in] session: crypto session identifier.
|
||||
@@ -4087,12 +4064,103 @@ OEMCryptoResult OEMCrypto_LoadProvisioning(
|
||||
* 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.
|
||||
* Devices that do not support the alternative signing algorithms used by Cast
|
||||
* Receiver certificates may refuse to load these keys and return an error of
|
||||
* OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these alternative
|
||||
* signing algorithms is to support devices that use X509 certificates for
|
||||
* authentication when acting as a ChromeCast receiver. This is not needed for
|
||||
* devices that wish to send data to a ChromeCast. Keys loaded from this
|
||||
* function may not be used with OEMCrypto_PrepAndSignLicenseRequest().
|
||||
*
|
||||
* 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. This is the same
|
||||
* process as used in `OEMCrypto_LoadLicense()`. For devices that support
|
||||
* Provisioning 2.0, the derivation_key is ignored and the device key from the
|
||||
* keybox is used to derive the three keys. For devices that support
|
||||
* Provisioning 4.0, the derivation_key is used to derive the three keys, using
|
||||
* the same algorithm as in OEMCrypto_LoadLicense().
|
||||
*
|
||||
* 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
|
||||
* 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. Otherwise, add the keys to the session
|
||||
* context.
|
||||
*
|
||||
* Refer to the Verification of Messages from a Server section above for more
|
||||
* details.
|
||||
*
|
||||
* After the signature is verified,
|
||||
* the function ODK_ParseProvisioning is called to parse the message. If it
|
||||
* returns an error, OEMCrypto shall return that error to the CDM layer. The
|
||||
* function ODK_ParseProvisioning is described in the document "Widevine Core
|
||||
* Message Serialization".
|
||||
*
|
||||
* Below, all fields are found in the struct ODK_ParsedLicense parsed_license
|
||||
* returned by ODK_ParsedProvisioning.
|
||||
*
|
||||
* After decrypting `parsed_response->enc_private_key`, OEMCryto should verify
|
||||
* that the first four bytes of the buffer are the string "SIGN". The actual RSA
|
||||
* key begins on the 9th byte of the buffer. The second four bytes of the buffer
|
||||
* is the 32 bit field "allowed_schemes" of type RSA_Padding_Scheme, which is
|
||||
* used in OEMCrypto_GenerateRSASignature(). The only supported scheme for keys
|
||||
* loaded with this function is kSign_PKCS1_Block1. The value of allowed_schemes
|
||||
* must also be wrapped with RSA key. We recommend storing the magic string
|
||||
* "SIGN" with the key to distinguish keys that have a value for allowed_schemes
|
||||
* from those that should use the default allowed_schemes.
|
||||
*
|
||||
* If the first four bytes of the buffer `enc_private_key` are not the string
|
||||
* "SIGN", then this key may not be loaded. The error
|
||||
* OEMCrypto_ERROR_INVALID_KEY is returned.
|
||||
*
|
||||
* Verification and Algorithm:
|
||||
* The following checks should be performed. If any check fails, an error is
|
||||
* returned, and the key is not loaded.
|
||||
* 1. Check that all the pointer values passed into it are within the
|
||||
* buffer specified by message and message_length.
|
||||
* 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]).
|
||||
* 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
|
||||
* vector for AES_128-CBC mode, with PKCS#5 padding. The private_key should
|
||||
* be kept in secure memory and protected from the user.
|
||||
* 6. Verify that the first four bytes of the buffer private_key are the
|
||||
* string "SIGN". The actual RSA key begins on the 9th byte of the
|
||||
* buffer. The second four bytes of the buffer is the 32 bit field
|
||||
* "allowed_schemes", of type RSA_Padding_Scheme, which is used in
|
||||
* OEMCrypto_GenerateRSASignature(). The value of allowed_schemes must
|
||||
* also be wrapped with RSA key. We recommend storing the magic string
|
||||
* "SIGN" with the key to distinguish keys that have a value for
|
||||
* allowed_schemes from those that should use the default
|
||||
* allowed_schemes. Devices that do not support the alternative signing
|
||||
* algorithms may refuse to load these keys and return an error of
|
||||
* OEMCrypto_ERROR_NOT_IMPLEMENTED. The main use case for these
|
||||
* alternative signing algorithms is to support devices that use X.509
|
||||
* certificates for authentication when acting as a ChromeCast receiver.
|
||||
* This is not needed for devices that wish to send data to a ChromeCast.
|
||||
* 7. After possibly skipping past the first 8 bytes signifying the allowed
|
||||
* signing algorithm, the rest of the buffer private_key contains an ECC
|
||||
* private key or an RSA private key in PKCS#8 binary DER encoded
|
||||
* format. The OEMCrypto library shall verify that this private key is
|
||||
* valid.
|
||||
* 8. Re-encrypt the device private key with an internal key (such as one
|
||||
* derived by the OEM key or Widevine Keybox key) and the generated IV
|
||||
* using AES-128-CBC with PKCS#5 padding. The data should also be
|
||||
* signed. This algorithm is just a suggestion. The implementer may use any
|
||||
* suitable encrypting and validation algorithm with a key that ties it to
|
||||
* the device.
|
||||
* 9. Copy the rewrapped key to the buffer specified by wrapped_private_key
|
||||
* and the size of the wrapped key to wrapped_private_key_length.
|
||||
*
|
||||
* @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] derivation_key: pointer to memory containing derivation key.
|
||||
* @param[in] derivation_key_length: length of the 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.
|
||||
|
||||
@@ -540,11 +540,24 @@ OEMCryptoResult ProvisioningRoundTrip::LoadResponseNoRetry(
|
||||
Session* session, size_t* wrapped_key_length) {
|
||||
EXPECT_NE(session, nullptr);
|
||||
VerifyEncryptAndSignResponseLengths();
|
||||
return OEMCrypto_LoadProvisioning(
|
||||
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);
|
||||
if (allowed_schemes_ == kSign_RSASSA_PSS) {
|
||||
return OEMCrypto_LoadProvisioning(
|
||||
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);
|
||||
} else {
|
||||
// TODO(b/316053127): Clean this up a lot.
|
||||
const uint8_t* derivation_key = nullptr;
|
||||
const size_t derivation_key_length = 0;
|
||||
return OEMCrypto_LoadProvisioningCast(
|
||||
session->session_id(), derivation_key, derivation_key_length,
|
||||
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() {
|
||||
|
||||
Reference in New Issue
Block a user