#include "chrome/browser/extensions/api/enterprise_reporting_private/chrome_desktop_report_request_helper.h"
#include "base/base64.h"
#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/path_service.h"
#include "base/rand_util.h"
#include "build/build_config.h"
#include "components/enterprise/browser/controller/browser_dm_token_storage.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include <dpapi.h>
#include "base/win/registry.h"
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "base/environment.h"
#include "base/nix/xdg_util.h"
#endif
#if BUILDFLAG(IS_MAC)
#include "base/apple/foundation_util.h"
#include "chrome/browser/extensions/api/enterprise_reporting_private/keychain_data_helper_mac.h"
#include "crypto/apple_keychain.h"
#endif
namespace extensions {
namespace {
#if BUILDFLAG(IS_WIN)
const wchar_t kDefaultRegistryPath[] =
L"SOFTWARE\\Google\\Endpoint Verification";
const wchar_t kValueName[] = L"Safe Storage";
LONG ReadEncryptedSecret(std::string* encrypted_secret) {
base::win::RegKey key;
constexpr DWORD kMaxRawSize = 1024;
char raw_data[kMaxRawSize];
DWORD raw_data_size = kMaxRawSize;
DWORD raw_type;
encrypted_secret->clear();
LONG result = key.Open(HKEY_CURRENT_USER, kDefaultRegistryPath, KEY_READ);
if (result != ERROR_SUCCESS)
return result;
result = key.ReadValue(kValueName, raw_data, &raw_data_size, &raw_type);
if (result != ERROR_SUCCESS)
return result;
if (raw_type != REG_BINARY) {
key.DeleteValue(kValueName);
return ERROR_INVALID_DATATYPE;
}
encrypted_secret->insert(0, raw_data, raw_data_size);
return ERROR_SUCCESS;
}
LONG EncryptString(const std::string& plaintext, std::string* ciphertext) {
DATA_BLOB input;
input.pbData =
const_cast<BYTE*>(reinterpret_cast<const BYTE*>(plaintext.data()));
input.cbData = static_cast<DWORD>(plaintext.length());
ciphertext->clear();
DATA_BLOB output;
BOOL result = ::CryptProtectData(&input, nullptr, nullptr, nullptr, nullptr,
0, &output);
if (!result)
return ::GetLastError();
ciphertext->assign(reinterpret_cast<std::string::value_type*>(output.pbData),
output.cbData);
LocalFree(output.pbData);
return ERROR_SUCCESS;
}
LONG DecryptString(const std::string& ciphertext, std::string* plaintext) {
DATA_BLOB input;
input.pbData =
const_cast<BYTE*>(reinterpret_cast<const BYTE*>(ciphertext.data()));
input.cbData = static_cast<DWORD>(ciphertext.length());
plaintext->clear();
DATA_BLOB output;
BOOL result =
::CryptUnprotectData(&input, nullptr, nullptr, nullptr, nullptr, 0,
&output);
if (!result)
return ::GetLastError();
plaintext->assign(reinterpret_cast<char*>(output.pbData), output.cbData);
LocalFree(output.pbData);
return ERROR_SUCCESS;
}
LONG CreateRandomSecret(std::string* secret) {
const int kBytes = 128 / 8;
std::string generated_secret =
base::Base64Encode(base::RandBytesAsVector(kBytes));
std::string encrypted_secret;
LONG result = EncryptString(generated_secret, &encrypted_secret);
if (result != ERROR_SUCCESS)
return result;
base::win::RegKey key;
result = key.Create(HKEY_CURRENT_USER, kDefaultRegistryPath, KEY_WRITE);
if (result != ERROR_SUCCESS)
return result;
result = key.WriteValue(kValueName, encrypted_secret.data(),
encrypted_secret.size(), REG_BINARY);
if (result == ERROR_SUCCESS)
*secret = generated_secret;
return result;
}
#elif BUILDFLAG(IS_MAC)
constexpr char kServiceName[] = "Endpoint Verification Safe Storage";
constexpr char kAccountName[] = "Endpoint Verification";
constexpr int32_t kKeychainLocked = 125000;
bool IsAuthFailedError(OSStatus status) {
return status == errSecAuthFailed;
}
OSStatus AddRandomPasswordToKeychain(const crypto::AppleKeychain& keychain,
std::string* secret) {
const int kBytes = 128 / 8;
std::string password = base::Base64Encode(base::RandBytesAsVector(kBytes));
OSStatus status = WriteKeychainItem(kServiceName, kAccountName, password);
if (status == noErr)
*secret = password;
else
secret->clear();
return status;
}
int32_t ReadEncryptedSecret(std::string* password, bool force_recreate) {
password->clear();
OSStatus status;
crypto::ScopedKeychainUserInteractionAllowed user_interaction_allowed(
FALSE, &status);
if (status != noErr)
return status;
crypto::AppleKeychain keychain;
UInt32 password_length = 0;
void* password_data = nullptr;
base::apple::ScopedCFTypeRef<SecKeychainItemRef> item_ref;
status = keychain.FindGenericPassword(
strlen(kServiceName), kServiceName, strlen(kAccountName), kAccountName,
&password_length, &password_data, item_ref.InitializeInto());
if (status == noErr) {
*password = std::string(static_cast<char*>(password_data), password_length);
keychain.ItemFreeContent(password_data);
return status;
}
bool was_auth_error = IsAuthFailedError(status);
bool was_item_not_found = status == errSecItemNotFound;
if ((was_auth_error || force_recreate) && !was_item_not_found) {
item_ref.reset();
OSStatus exists_status = keychain.FindGenericPassword(
strlen(kServiceName), kServiceName, strlen(kAccountName), kAccountName,
nullptr, nullptr, item_ref.InitializeInto());
if (exists_status != noErr) {
return exists_status;
}
if (was_auth_error) {
bool unlocked;
OSStatus keychain_status =
VerifyKeychainForItemUnlocked(item_ref.get(), &unlocked);
if (keychain_status != noErr) {
return keychain_status;
}
if (!unlocked) {
return kKeychainLocked;
}
}
if (force_recreate) {
status = keychain.ItemDelete(item_ref.get());
if (status != noErr) {
return status;
}
}
}
if (was_item_not_found || force_recreate) {
status = AddRandomPasswordToKeychain(keychain, password);
if (IsAuthFailedError(status)) {
bool unlocked;
OSStatus keychain_status = VerifyDefaultKeychainUnlocked(&unlocked);
if (keychain_status != noErr) {
return keychain_status;
}
if (!unlocked) {
return kKeychainLocked;
}
}
}
return status;
}
#endif
base::FilePath* GetEndpointVerificationDirOverride() { … }
base::FilePath GetEndpointVerificationDir() { … }
}
void OverrideEndpointVerificationDirForTesting(const base::FilePath& path) { … }
void StoreDeviceData(const std::string& id,
const std::optional<std::vector<uint8_t>> data,
base::OnceCallback<void(bool)> callback) { … }
void RetrieveDeviceData(
const std::string& id,
base::OnceCallback<void(const std::string&, RetrieveDeviceDataStatus)>
callback) { … }
void RetrieveDeviceSecret(
bool force_recreate,
base::OnceCallback<void(const std::string&, int32_t)> callback) { … }
}