From 5bed1044eb89a2623369f21dd6c72ae40bc9f138 Mon Sep 17 00:00:00 2001 From: Karan Jain Date: Mon, 13 Mar 2023 14:00:55 +0530 Subject: [PATCH] Added crypto_session_fuzzer exec/s: 29 Test: ./crypto_session_fuzzer Bug: 265234582 Change-Id: Ia42bcae6ea2f6ec722b972f44256e8b8cb56d9d5 --- fuzzer/Android.bp | 6 + fuzzer/README.md | 26 ++ fuzzer/crypto_session_fuzzer.cpp | 505 +++++++++++++++++++++++++++++++ 3 files changed, 537 insertions(+) create mode 100644 fuzzer/crypto_session_fuzzer.cpp diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp index 44605b18..1282c37e 100644 --- a/fuzzer/Android.bp +++ b/fuzzer/Android.bp @@ -104,3 +104,9 @@ cc_fuzz { srcs: ["cdm_license_fuzzer.cpp"], defaults: ["libcdm_fuzzer_defaults"], } + +cc_fuzz { + name: "crypto_session_fuzzer", + srcs: ["crypto_session_fuzzer.cpp"], + defaults: ["libcdm_fuzzer_defaults"], +} diff --git a/fuzzer/README.md b/fuzzer/README.md index 4fecdd9c..ca8ac194 100644 --- a/fuzzer/README.md +++ b/fuzzer/README.md @@ -8,6 +8,7 @@ + [policy_timers_fuzzer](#PolicyTimers) + [privacy_crypto_fuzzer](#PrivacyCrypto) + [cdm_license_fuzzer](#CdmLicense) ++ [crypto_session_fuzzer](#CryptoSession) # Fuzzer for PolicyEngine @@ -181,3 +182,28 @@ CdmLicense supports the following parameters: $ adb sync data $ adb shell /data/fuzz/arm64/cdm_license_fuzzer/vendor/cdm_license_fuzzer ``` +# Fuzzer for CryptoSession + +CryptoSession supports the following parameters: +1. token (parameter name: "token") +2. signed_message (parameter name: "signed_message") +3. signature (parameter name: "signature") +4. provider_session_token (parameter name: "signature") + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`token`| `String` |Value obtained from FuzzedDataProvider| +|`signed_message`| `String` |Value obtained from FuzzedDataProvider| +|`signature`| `String` |Value obtained from FuzzedDataProvider| +|`provider_session_token`| `String` |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) crypto_session_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell LD_LIBRARY_PATH=/vendor/lib64 /data/fuzz/arm64/crypto_session_fuzzer/vendor/crypto_session_fuzzer +``` diff --git a/fuzzer/crypto_session_fuzzer.cpp b/fuzzer/crypto_session_fuzzer.cpp new file mode 100644 index 00000000..017d828b --- /dev/null +++ b/fuzzer/crypto_session_fuzzer.cpp @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache license, Version 2.0 (the "license"); + * you may not use this file except in compliance with the license. + * You may obtain a copy of the license at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the license is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the license for the specific language governing permissions and + * limitations under the license. + * + */ + +#include "crypto_session.h" +#include "entitlement_key_session.h" +#include "properties.h" +#include "string_conversions.h" +#include "wv_cdm_constants.h" +#include + +using namespace wvcdm; + +constexpr int32_t kStringLength = 20; +constexpr int32_t kMaxSamplesCount = 1000; +constexpr int32_t kMinSamplesCount = 1; +constexpr int32_t kMaxByte = 1000; +constexpr int32_t kMinByte = 0; +constexpr int32_t kIvSize = 16; +constexpr int32_t kDefaultSampleSize = 0; + +class CryptoSessionFuzzer { +public: + CryptoSessionFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) {}; + void process(); + void FillDecryptParams(CdmDecryptionParametersV16& params); + void SetKeyParams(CryptoKey& inputKey); + void setUp(CryptoSession* cryptoSession, const std::string& keyId, + std::string& message, std::string& signature, + std::string& coreMessage); + void initializeStripeBuffer(std::vector* buffer, size_t size); + +private: + FuzzedDataProvider mFdp; +}; + +void CryptoSessionFuzzer::initializeStripeBuffer(std::vector* buffer, + size_t size) { + buffer->assign(size, 0); + for (size_t i = 0; i < size; ++i) { + (*buffer)[i] = mFdp.ConsumeIntegral(); + } +} + +void CryptoSessionFuzzer::SetKeyParams(CryptoKey& inputKey) { + inputKey.set_key_data(mFdp.ConsumeRandomLengthString(kStringLength)); + inputKey.set_key_data_iv(mFdp.ConsumeRandomLengthString(kStringLength)); + inputKey.set_key_control(mFdp.ConsumeRandomLengthString(kStringLength)); + inputKey.set_key_control_iv(mFdp.ConsumeRandomLengthString(kStringLength)); + inputKey.set_cipher_mode(mFdp.ConsumeBool() ? kCipherModeCbc + : kCipherModeCtr); + inputKey.set_track_label(mFdp.ConsumeRandomLengthString(kStringLength)); + inputKey.set_entitlement_key_id( + mFdp.ConsumeRandomLengthString(kStringLength)); +} + +void CryptoSessionFuzzer::FillDecryptParams( + CdmDecryptionParametersV16& params) { + params.cipher_mode = mFdp.ConsumeBool() ? kCipherModeCbc : kCipherModeCtr; + params.observe_legacy_fields = mFdp.ConsumeBool(); + uint32_t noOfSamples = + mFdp.ConsumeIntegralInRange(kMinSamplesCount, kMaxSamplesCount); + + while (--noOfSamples) { + size_t sampleSize = 0; + uint32_t noOfSubSamples = mFdp.ConsumeIntegralInRange( + kMinSamplesCount, kMaxSamplesCount); + std::vector subSampleVector; + while (--noOfSubSamples) { + size_t clearBytes = + mFdp.ConsumeIntegralInRange(kMinByte, kMaxByte); + size_t protectedBytes = + mFdp.ConsumeIntegralInRange(kMinByte, kMaxByte); + CdmDecryptionSubsample subsample(clearBytes, protectedBytes); + sampleSize += clearBytes + protectedBytes; + subSampleVector.push_back(subsample); + } + std::vector iv; + iv = mFdp.ConsumeBytes(kIvSize); + if (iv.size() != kIvSize) { + iv.resize(kIvSize, 0); + } + void* decryptBuffer; + std::vector eBuffer; + for (int i = 0; i < sampleSize; ++i) { + eBuffer.push_back( + mFdp.ConsumeIntegralInRange(kMinByte, kMaxByte)); + } + size_t decryptBufferOffset = + mFdp.ConsumeIntegralInRange(kMinByte, kMaxByte); + CdmDecryptionSample sample(eBuffer.data(), decryptBuffer, + decryptBufferOffset, sampleSize, iv); + sample.subsamples = subSampleVector; + params.samples.push_back(sample); + } +} + +void CryptoSessionFuzzer::setUp(CryptoSession* cryptoSession, + const std::string& keyId, std::string& message, + std::string& signature, + std::string& coreMessage) { + bool shouldSpecifyAlgorithm; + OEMCrypto_SignatureHashAlgorithm algorithm; + CdmLicenseKeyType keyType1 = kLicenseKeyTypeEntitlement; + cryptoSession->PrepareAndSignProvisioningRequest( + message, &coreMessage, &signature, shouldSpecifyAlgorithm, algorithm); + cryptoSession->PrepareAndSignLicenseRequest( + message, &coreMessage, &signature, shouldSpecifyAlgorithm, algorithm); + cryptoSession->LoadLicense(message, coreMessage, signature, keyType1); + + CryptoKey inputKey; + inputKey.set_key_id(keyId); + CryptoSessionFuzzer::SetKeyParams(inputKey); + std::vector keys = { inputKey }; + cryptoSession->LoadEntitledContentKeys(keys); +} + +void CryptoSessionFuzzer::process() { + metrics::CryptoMetrics cryptoMetrics; + std::unique_ptr cryptoSession( + CryptoSession::MakeCryptoSession(&cryptoMetrics)); + + CdmLicenseKeyType keyType; + OEMCrypto_SignatureHashAlgorithm algorithm; + Properties::Init(); + + RequestedSecurityLevel requestedSecurityLevel = + mFdp.ConsumeBool() ? kLevelDefault : kLevel3; + cryptoSession->Open(requestedSecurityLevel); + + while (mFdp.remaining_bytes()) { + auto invokeCryptoSessionAPI = mFdp.PickValueInArray< + const std::function>({ + [&]() { + std::string token = mFdp.ConsumeRandomLengthString(kStringLength); + std::string additionalToken = + mFdp.ConsumeRandomLengthString(kStringLength); + cryptoSession->GetProvisioningToken( + mFdp.ConsumeBool() ? &token : nullptr, + mFdp.ConsumeBool() ? &additionalToken : nullptr); + }, + [&]() { + cryptoSession->SetSystemId( + mFdp.ConsumeIntegral() /*system_id*/); + }, + [&]() { + std::string provisioningId; + cryptoSession->GetProvisioningId(&provisioningId); + cryptoSession->GetExternalDeviceUniqueId(&provisioningId); + }, + [&]() { + cryptoSession->LoadLicense( + mFdp.ConsumeRandomLengthString(kStringLength) /*signed_message*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*coreMessage*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*signature*/, + keyType); + }, + [&]() { + std::string coreMessage = + mFdp.ConsumeRandomLengthString(kStringLength); + std::string signature = mFdp.ConsumeRandomLengthString(kStringLength); + cryptoSession->PrepareAndSignRenewalRequest( + mFdp.ConsumeRandomLengthString(kStringLength) /*message*/, + mFdp.ConsumeBool() ? &coreMessage : nullptr, + mFdp.ConsumeBool() ? &signature : nullptr); + }, + [&]() { + cryptoSession->LoadRenewal( + mFdp.ConsumeRandomLengthString(kStringLength) /*signed_message*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*coreMessage*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*signature*/); + }, + [&]() { + const std::string& message = + mFdp.ConsumeRandomLengthString(kStringLength); + std::string coreMessage = + mFdp.ConsumeRandomLengthString(kStringLength); + std::string signature = mFdp.ConsumeRandomLengthString(kStringLength); + OEMCrypto_SignatureHashAlgorithm algorithm; + bool shouldSpecifyAlgorithm = mFdp.ConsumeBool(); + cryptoSession->PrepareAndSignProvisioningRequest( + message, mFdp.ConsumeBool() ? &coreMessage : nullptr, + mFdp.ConsumeBool() ? &signature : nullptr, shouldSpecifyAlgorithm, + algorithm); + }, + [&]() { + if (mFdp.ConsumeBool()) { + const CryptoWrappedKey privateKey; + cryptoSession->LoadCertificatePrivateKey(privateKey); + } else { + CryptoWrappedKey::Type type = + (CryptoWrappedKey::Type)mFdp.ConsumeIntegral(); + std::string key = mFdp.ConsumeRandomLengthString(kStringLength); + const CryptoWrappedKey privateKey(type, key); + cryptoSession->LoadCertificatePrivateKey(privateKey); + } + }, + [&]() { + std::string publicKey; + std::string publicKeySignature; + std::string wrappedPrivateKey; + CryptoWrappedKey::Type keyType; + cryptoSession->GenerateCertificateKeyPair( + &publicKey, &publicKeySignature, &wrappedPrivateKey, &keyType); + }, + [&]() { + if (mFdp.ConsumeBool()) { + const CryptoWrappedKey privateKey; + cryptoSession->LoadOemCertificatePrivateKey(privateKey); + } else { + CryptoWrappedKey::Type type = + (CryptoWrappedKey::Type)mFdp.ConsumeIntegral(); + std::string key = mFdp.ConsumeRandomLengthString(kStringLength); + const CryptoWrappedKey privateKey(type, key); + cryptoSession->LoadOemCertificatePrivateKey(privateKey); + } + }, + [&]() { + size_t out; + RequestedSecurityLevel security_level = + (RequestedSecurityLevel)mFdp.ConsumeIntegral(); + cryptoSession->GetNumberOfOpenSessions(security_level, &out); + }, + [&]() { + std::string info = mFdp.ConsumeRandomLengthString(kStringLength); + cryptoSession->GetBuildInformation(&info); + }, + [&]() { + CdmWatermarkingSupport support = + (CdmWatermarkingSupport)mFdp.ConsumeIntegral(); + cryptoSession->GetWatermarkingSupport(&support); + }, + [&]() { + CdmProductionReadiness readiness = + (CdmProductionReadiness)mFdp.ConsumeIntegral(); + cryptoSession->GetProductionReadiness(&readiness); + }, + [&]() { + RequestedSecurityLevel security_level = + (RequestedSecurityLevel)mFdp.ConsumeIntegral(); + size_t number_of_entries = mFdp.ConsumeIntegral(); + cryptoSession->GetMaximumUsageTableEntries(security_level, + &number_of_entries); + }, + [&]() { + RequestedSecurityLevel security_level = + (RequestedSecurityLevel)mFdp.ConsumeIntegral(); + uint32_t decrypt_hash_support = mFdp.ConsumeIntegral(); + cryptoSession->GetDecryptHashSupport(security_level, + &decrypt_hash_support); + }, + [&]() { + bool hasSupport = mFdp.ConsumeBool(); + cryptoSession->HasUsageTableSupport(&hasSupport); + }, + [&]() { + cryptoSession->DeactivateUsageInformation( + mFdp.ConsumeRandomLengthString( + kStringLength) /*provider_session_token*/); + }, + [&]() { + std::string usageReport = + mFdp.ConsumeRandomLengthString(kStringLength); + CryptoSession::UsageDurationStatus usageDurationStatus; + int64_t secondsSinceStarted = mFdp.ConsumeIntegral(); + int64_t secondsSinceLastPlayed = mFdp.ConsumeIntegral(); + cryptoSession->GenerateUsageReport( + mFdp.ConsumeRandomLengthString( + kStringLength) /*provider_session_token*/, + &usageReport, &usageDurationStatus, &secondsSinceStarted, + &secondsSinceLastPlayed); + }, + [&]() { + uint32_t nonce = mFdp.ConsumeIntegral(); + cryptoSession->GenerateNonce(&nonce); + }, + [&]() { + std::string signedMessage, coreMessage, signature; + std::string wrappedPrivateKey; + cryptoSession->LoadProvisioning( + signedMessage, coreMessage, signature, + mFdp.ConsumeBool() ? &wrappedPrivateKey : nullptr); + }, + [&]() { + cryptoSession->SetDecryptHash( + mFdp.ConsumeIntegral() /*frame_number*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*hash*/); + }, + [&]() { + CdmEncryptionAlgorithm algorithm; + std::string outBuffer; + cryptoSession->GenericDecrypt( + mFdp.ConsumeRandomLengthString(kStringLength) /*in_buffer*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*key_id*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*iv*/, algorithm, + &outBuffer); + }, + [&]() { + CdmSigningAlgorithm algorithm = mFdp.ConsumeBool() + ? kSigningAlgorithmHmacSha256 + : kSigningAlgorithmUnknown; + std::string signature; + cryptoSession->GenericSign( + mFdp.ConsumeRandomLengthString(kStringLength) /*message*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*key_id*/, + algorithm, &signature); + }, + [&]() { + CdmSigningAlgorithm algorithm = kSigningAlgorithmHmacSha256; + const std::string signature; + cryptoSession->GenericVerify( + mFdp.ConsumeRandomLengthString(kStringLength) /*message*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*key_id*/, + algorithm, signature); + }, + [&]() { + UsageTableHeader usageTableHeader; + cryptoSession->CreateUsageTableHeader(requestedSecurityLevel, + &usageTableHeader); + + cryptoSession->LoadUsageTableHeader(requestedSecurityLevel, + usageTableHeader); + uint32_t newEntryCount; + cryptoSession->ShrinkUsageTableHeader( + requestedSecurityLevel, newEntryCount, &usageTableHeader); + }, + [&]() { + const UsageTableHeader usageTableHeader; + cryptoSession->LoadUsageTableHeader(requestedSecurityLevel, + usageTableHeader); + }, + [&]() { + uint32_t entryNumber; + cryptoSession->CreateUsageEntry(&entryNumber); + cryptoSession->MoveUsageEntry(entryNumber); + }, + [&]() { + const UsageEntry usageEntry; + cryptoSession->LoadUsageEntry( + mFdp.ConsumeIntegral() /*entry_number*/, usageEntry); + }, + [&]() { + UsageTableHeader usageTableHeader; + UsageEntry usageEntry; + cryptoSession->UpdateUsageEntry(&usageTableHeader, &usageEntry); + }, + [&]() { + bool canSupportOutput = mFdp.ConsumeBool(); + bool canDisableOutput = mFdp.ConsumeBool(); + bool canSupportCgmsA = mFdp.ConsumeBool(); + cryptoSession->GetAnalogOutputCapabilities( + &canSupportOutput, &canDisableOutput, &canSupportCgmsA); + }, + [&]() { + cryptoSession->SetDebugIgnoreKeyboxCount( + mFdp.ConsumeIntegral() /*count*/); + }, + [&]() { + cryptoSession->SetAllowTestKeybox(mFdp.ConsumeBool() /*allow*/); + }, + [&]() { cryptoSession->GetOkpFallbackPolicy(); }, + [&]() { + std::string request = mFdp.ConsumeRandomLengthString(kStringLength); + cryptoSession->PrepareOtaProvisioningRequest( + mFdp.ConsumeBool() /*use_test_key*/, &request); + }, + [&]() { + cryptoSession->LoadOtaProvisioning( + mFdp.ConsumeBool() /*use_test_key*/, + mFdp.ConsumeRandomLengthString(kStringLength) /*response*/); + }, + [&]() { + uint32_t tier = mFdp.ConsumeIntegral(); + cryptoSession->GetResourceRatingTier(&tier); + }, + [&]() { + size_t max; + cryptoSession->GetMaxNumberOfSessions(requestedSecurityLevel, &max); + }, + [&]() { + std::string keyData = mFdp.ConsumeRandomLengthString(kStringLength); + cryptoSession->GetTokenFromKeybox(requestedSecurityLevel, &keyData); + }, + [&]() { + std::string bcc = mFdp.ConsumeRandomLengthString(kStringLength); + std::string additionalSignature = + mFdp.ConsumeRandomLengthString(kStringLength); + cryptoSession->GetBootCertificateChain(&bcc, &additionalSignature); + }, + [&]() { + cryptoSession->GenerateDerivedKeys( + mFdp.ConsumeRandomLengthString(kStringLength) /*message*/); + }, + [&]() { + CdmDecryptionParametersV16 params2; + cryptoSession->Decrypt(params2); + }, + [&]() { + const std::string& message = + mFdp.ConsumeRandomLengthString(kStringLength); + std::string coreMessage, signature; + bool shouldSpecifyAlgorithm; + OEMCrypto_SignatureHashAlgorithm algorithm; + + cryptoSession->PrepareAndSignProvisioningRequest( + message, &coreMessage, &signature, shouldSpecifyAlgorithm, + algorithm); + cryptoSession->PrepareAndSignLicenseRequest( + message, &coreMessage, &signature, shouldSpecifyAlgorithm, + algorithm); + }, + [&]() { + std::string keyId = mFdp.ConsumeRandomLengthString(kStringLength); + std::string message = mFdp.ConsumeRandomLengthString(kStringLength); + std::string signature, coreMessage; + setUp(cryptoSession.get(), keyId, message, signature, coreMessage); + + std::vector inVector; + std::vector ivVector; + std::string inBuffer; + std::string iv; + CdmEncryptionAlgorithm algorithmEncrypt = + kEncryptionAlgorithmAesCbc128; + std::string outBuffer; + initializeStripeBuffer(&inVector, CONTENT_KEY_SIZE * 15); + inBuffer = std::string(inVector.begin(), inVector.end()); + initializeStripeBuffer(&ivVector, KEY_IV_SIZE); + iv = std::string(ivVector.begin(), ivVector.end()); + + cryptoSession->GenericEncrypt(inBuffer, keyId, iv, algorithmEncrypt, + &outBuffer); + }, + [&]() { + std::string keyId = mFdp.ConsumeRandomLengthString(kStringLength); + std::string message = mFdp.ConsumeRandomLengthString(kStringLength); + std::string signature, coreMessage; + setUp(cryptoSession.get(), keyId, message, signature, coreMessage); + + std::vector inVector; + std::vector ivVector; + std::string inBuffer; + std::string iv; + CdmEncryptionAlgorithm algorithmEncrypt = + kEncryptionAlgorithmAesCbc128; + std::string outBuffer; + initializeStripeBuffer(&inVector, CONTENT_KEY_SIZE * 15); + inBuffer = std::string(inVector.begin(), inVector.end()); + initializeStripeBuffer(&ivVector, KEY_IV_SIZE); + iv = std::string(ivVector.begin(), ivVector.end()); + + cryptoSession->GenericDecrypt(inBuffer, keyId, iv, algorithmEncrypt, + &outBuffer); + }, + [&]() { + std::string keyId = mFdp.ConsumeRandomLengthString(kStringLength); + std::string message = mFdp.ConsumeRandomLengthString(kStringLength); + std::string signature, coreMessage; + setUp(cryptoSession.get(), keyId, message, signature, coreMessage); + + CdmSigningAlgorithm algorithm2 = kSigningAlgorithmHmacSha256; + cryptoSession->GenericSign(message, keyId, algorithm2, &signature); + }, + [&]() { + std::string keyId = mFdp.ConsumeRandomLengthString(kStringLength); + std::string message = mFdp.ConsumeRandomLengthString(kStringLength); + std::string signature, coreMessage; + setUp(cryptoSession.get(), keyId, message, signature, coreMessage); + + CdmSigningAlgorithm algorithm2 = kSigningAlgorithmHmacSha256; + cryptoSession->GenericVerify(message, keyId, algorithm2, signature); + }, + [&]() { + const std::string keyId = + mFdp.ConsumeRandomLengthString(kStringLength); + std::string message = mFdp.ConsumeRandomLengthString(kStringLength); + std::string signature, coreMessage; + setUp(cryptoSession.get(), keyId, message, signature, coreMessage); + CdmDecryptionParametersV16 params(keyId); + CryptoSessionFuzzer::FillDecryptParams(params); + cryptoSession->Decrypt(params); + }, + }); + invokeCryptoSessionAPI(); + } + cryptoSession->Close(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t size) { + CryptoSessionFuzzer cryptoSessionFuzzer(data, size); + cryptoSessionFuzzer.process(); + return 0; +}