Document OEMCrypto_LoadProvisioningCast

Bug: 314222872
Change-Id: I05031d1eacefceb73931b979ef69e69fdba871a7
This commit is contained in:
Fred Gylys-Colwell
2023-12-11 21:04:43 -08:00
committed by Robert Shih
parent ce2af4e96a
commit 34ac11b187
3 changed files with 145 additions and 52 deletions

View File

@@ -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();

View File

@@ -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.

View File

@@ -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() {