blob: 0c4b9c7c96b746f42fdc336c224814f8f88c9a8e [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/preferences/tracked/pref_hash_store_impl.h"
#include <stddef.h>
#include <string_view>
#include <utility>
#include "base/check.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "services/preferences/tracked/device_id.h"
#include "services/preferences/tracked/hash_store_contents.h"
namespace {
using ValidationResult = PrefHashCalculator::ValidationResult;
using ValueState =
prefs::mojom::TrackedPreferenceValidationDelegate::ValueState;
// Suffix used to distinguish encrypted hash keys from MAC keys in storage.
const char kEncryptedHashKeySuffix[] = "_encrypted_hash";
// Keys expected in the dictionary passed to ImportHash if it contains
// structured data.
const char kImportMacKey[] = "mac";
const char kImportEncryptedHashKey[] = "encrypted_hash";
// Helper to create the key used for storing encrypted hashes.
std::string GetEncryptedHashKey(const std::string& path) {
return path + kEncryptedHashKeySuffix;
}
// Returns a deterministic ID for this machine.
std::string GenerateDeviceId() {
static base::NoDestructor<std::string> cached_device_id;
if (!cached_device_id->empty())
return *cached_device_id;
std::string device_id;
MachineIdStatus status = GetDeterministicMachineSpecificId(&device_id);
DCHECK(status == MachineIdStatus::NOT_IMPLEMENTED ||
status == MachineIdStatus::SUCCESS);
if (status == MachineIdStatus::SUCCESS) {
*cached_device_id = device_id;
return device_id;
}
return std::string();
}
} // namespace
class PrefHashStoreImpl::PrefHashStoreTransactionImpl
: public PrefHashStoreTransaction {
public:
// Constructs a PrefHashStoreTransactionImpl which can use the private
// members of its |outer| PrefHashStoreImpl.
PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer,
HashStoreContents* storage,
const os_crypt_async::Encryptor* encryptor);
PrefHashStoreTransactionImpl(const PrefHashStoreTransactionImpl&) = delete;
PrefHashStoreTransactionImpl& operator=(const PrefHashStoreTransactionImpl&) =
delete;
~PrefHashStoreTransactionImpl() override;
// PrefHashStoreTransaction implementation.
std::string_view GetStoreUMASuffix() const override;
ValueState CheckValue(const std::string& path,
const base::Value* value) const override;
void StoreHash(const std::string& path, const base::Value* value) override;
ValueState CheckSplitValue(
const std::string& path,
const base::Value::Dict* initial_split_value,
std::vector<std::string>* invalid_keys) const override;
void StoreSplitHash(const std::string& path,
const base::Value::Dict* split_value) override;
bool HasHash(const std::string& path) const override;
void ImportHash(const std::string& path, const base::Value* hash) override;
void ClearHash(const std::string& path) override;
bool IsSuperMACValid() const override;
bool StampSuperMac() override;
void StoreEncryptedHash(const std::string& path,
const base::Value* value) override;
std::optional<std::string> GetEncryptedHash(
const std::string& path) const override;
std::optional<std::string> GetMac(const std::string& path) const override;
bool HasEncryptedHash(const std::string& path) const override;
// Stores the new split Encrypted Hashes. Requires the encryptor.
void StoreSplitEncryptedHash(const std::string& path,
const base::Value::Dict* split_value) override;
// Clears only the Encrypted Hash for the path.
void ClearEncryptedHash(const std::string& path) override;
// Gets the stored split encrypted hashes if they exist. Returns false
// otherwise.
bool GetSplitEncryptedHashes(
const std::string& path,
std::map<std::string, std::string>* split_encrypted_hashes) const;
private:
// Helper for CheckValue to handle validation logic.
ValueState CheckValueInternal(
const std::string& path,
const base::Value* value,
const std::optional<std::string>& stored_encrypted_hash,
const std::optional<std::string>& stored_mac) const;
// Helper for CheckSplitValue to handle validation logic.
ValueState CheckSplitValueInternal(
const std::string& path,
const base::Value::Dict* initial_split_value,
bool has_encrypted_hashes,
const std::map<std::string, std::string>& split_encrypted_hashes,
bool has_mac_hashes,
const std::map<std::string, std::string>& split_macs,
std::vector<std::string>* invalid_keys) const;
private:
raw_ptr<PrefHashStoreImpl> outer_;
raw_ptr<HashStoreContents> contents_;
raw_ptr<const os_crypt_async::Encryptor> encryptor_;
bool super_mac_valid_;
bool super_mac_dirty_;
};
PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed,
bool use_super_mac)
: pref_hash_calculator_(seed, GenerateDeviceId()),
use_super_mac_(use_super_mac) {}
PrefHashStoreImpl::~PrefHashStoreImpl() {}
std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction(
HashStoreContents* storage,
const os_crypt_async::Encryptor* encryptor) {
return std::make_unique<PrefHashStoreTransactionImpl>(this, storage,
encryptor);
}
// Computes the legacy MAC.
std::string PrefHashStoreImpl::ComputeMac(const std::string& path,
const base::Value* value) {
return pref_hash_calculator_.Calculate(path, value);
}
// Computes the legacy MAC for a dictionary.
std::string PrefHashStoreImpl::ComputeMac(const std::string& path,
const base::Value::Dict* dict) {
return pref_hash_calculator_.Calculate(path, dict);
}
// Computes the split legacy MACs.
base::Value::Dict PrefHashStoreImpl::ComputeSplitMacs(
const std::string& path,
const base::Value::Dict* split_values) {
if (!split_values)
return base::Value::Dict();
std::string keyed_path(path);
keyed_path.push_back('.');
const size_t common_part_length = keyed_path.length();
base::Value::Dict split_macs;
for (const auto item : *split_values) {
// Keep the common part from the old |keyed_path| and replace the key to
// get the new |keyed_path|.
keyed_path.replace(common_part_length, std::string::npos, item.first);
split_macs.Set(item.first, ComputeMac(keyed_path, &item.second));
}
return split_macs;
}
// Computes the encrypted hash.
std::string PrefHashStoreImpl::ComputeEncryptedHash(
const std::string& path,
const base::Value* value,
const os_crypt_async::Encryptor* encryptor) {
DCHECK(encryptor);
std::optional<std::string> result_opt =
pref_hash_calculator_.CalculateEncryptedHash(path, value, encryptor);
return result_opt.value_or(std::string());
}
// Computes the encrypted hash for a dictionary.
std::string PrefHashStoreImpl::ComputeEncryptedHash(
const std::string& path,
const base::Value::Dict* dict,
const os_crypt_async::Encryptor* encryptor) {
DCHECK(encryptor);
std::optional<std::string> result_opt =
pref_hash_calculator_.CalculateEncryptedHash(path, dict, encryptor);
return result_opt.value_or(std::string());
}
// Computes split encrypted hashes.
base::Value::Dict PrefHashStoreImpl::ComputeSplitEncryptedHashes(
const std::string& path,
const base::Value::Dict* split_values,
const os_crypt_async::Encryptor* encryptor) {
if (!encryptor) {
return base::Value::Dict();
}
if (!split_values || split_values->empty()) {
return base::Value::Dict();
}
std::string keyed_path(path);
keyed_path.push_back('.');
const size_t common_part_length = keyed_path.length();
base::Value::Dict split_encrypted_hashes;
for (const auto item : *split_values) {
keyed_path.replace(common_part_length, std::string::npos, item.first);
std::optional<std::string> result_opt =
pref_hash_calculator_.CalculateEncryptedHash(keyed_path, &item.second,
encryptor);
if (result_opt.has_value()) {
split_encrypted_hashes.Set(item.first, std::move(*result_opt));
}
}
return split_encrypted_hashes;
}
PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
PrefHashStoreImpl* outer,
HashStoreContents* storage,
const os_crypt_async::Encryptor* encryptor_ptr)
: outer_(outer),
contents_(storage),
encryptor_(encryptor_ptr),
super_mac_valid_(false),
super_mac_dirty_(false) {
if (!outer_->use_super_mac_)
return;
// The store must have a valid super MAC to be trusted.
std::string super_mac = contents_->GetSuperMac();
if (super_mac.empty())
return;
super_mac_valid_ =
outer_->pref_hash_calculator_.Validate(
"", contents_->GetContents(), super_mac) == PrefHashCalculator::VALID;
}
PrefHashStoreImpl::PrefHashStoreTransactionImpl::
~PrefHashStoreTransactionImpl() {
if (super_mac_dirty_ && outer_->use_super_mac_) {
// Get the dictionary of hashes (or NULL if it doesn't exist).
const base::Value::Dict* hashes_dict = contents_->GetContents();
contents_->SetSuperMac(outer_->ComputeMac("", hashes_dict));
}
}
std::string_view
PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetStoreUMASuffix() const {
return contents_->GetUMASuffix();
}
std::optional<std::string>
PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetEncryptedHash(
const std::string& path) const {
std::string encrypted_hash;
if (contents_->GetMac(GetEncryptedHashKey(path), &encrypted_hash)) {
return encrypted_hash;
}
return std::nullopt;
}
std::optional<std::string>
PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetMac(
const std::string& path) const {
std::string mac_str;
// Get the MAC string from the HashStoreContents.
if (contents_->GetMac(path, &mac_str)) {
return mac_str;
}
return std::nullopt;
}
bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetSplitEncryptedHashes(
const std::string& path,
std::map<std::string, std::string>* split_encrypted_hashes) const {
DCHECK(split_encrypted_hashes);
split_encrypted_hashes->clear();
// Use the suffixed key to retrieve split encrypted hashes
return contents_->GetSplitMacs(GetEncryptedHashKey(path),
split_encrypted_hashes);
}
ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValueInternal(
const std::string& path,
const base::Value* value,
const std::optional<std::string>& stored_encrypted_hash,
const std::optional<std::string>& stored_mac) const {
if (encryptor_) {
// Priority 1: Check encrypted hash.
if (stored_encrypted_hash.has_value()) {
ValidationResult result =
outer_->pref_hash_calculator_.ValidateEncrypted(
path, value, *stored_encrypted_hash, encryptor_);
if (result == ValidationResult::VALID_ENCRYPTED) {
return ValueState::UNCHANGED_ENCRYPTED;
}
return value ? ValueState::CHANGED_ENCRYPTED
: ValueState::CLEARED_ENCRYPTED;
}
// Priority 2: Fallback to legacy MAC for healing.
if (stored_mac.has_value()) {
ValidationResult result =
outer_->pref_hash_calculator_.Validate(path, value, *stored_mac);
if (result == ValidationResult::VALID) {
return ValueState::UNCHANGED_VIA_HMAC_FALLBACK;
}
return value ? ValueState::CHANGED_VIA_HMAC_FALLBACK
: ValueState::CLEARED_VIA_HMAC_FALLBACK;
}
} else {
// ---- Encryptor is NOT available: Legacy path ----
if (stored_mac.has_value()) {
ValidationResult mac_validation_result =
outer_->pref_hash_calculator_.Validate(path, value, *stored_mac);
if (mac_validation_result == ValidationResult::VALID) {
// If we fell through from encrypted (which was unusable), a valid MAC
// still means the value is UNCHANGED.
return ValueState::UNCHANGED;
}
return value ? ValueState::CHANGED : ValueState::CLEARED;
}
}
// --- No Usable Hashes Found ---
// Arrive here if:
// 1. No hashes stored at all.
// 2. ONLY encrypted hash stored, but no encryptor (fell through above).
if (!value) {
// Null value is always trusted if no usable hash is present
return ValueState::TRUSTED_NULL_VALUE;
}
// If we got here ONLY because an encrypted hash was present but unusable
// (due to missing encryptor), treat the value as untrusted regardless of
// the (potentially stale) super_mac_valid_ flag.
if (stored_encrypted_hash.has_value() && !stored_mac.has_value() &&
!encryptor_) {
return ValueState::UNTRUSTED_UNKNOWN_VALUE;
}
// Otherwise (genuinely no hashes stored), base trust on the SuperMAC validity
// state *cached at the start of the transaction*.
if (super_mac_valid_) {
return ValueState::TRUSTED_UNKNOWN_VALUE;
} else {
return ValueState::UNTRUSTED_UNKNOWN_VALUE;
}
}
ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue(
const std::string& path,
const base::Value* initial_value) const {
// Attempt to retrieve both types of hashes.
std::optional<std::string> encrypted_hash = GetEncryptedHash(path);
std::optional<std::string> mac;
std::string mac_str;
if (contents_->GetMac(path, &mac_str)) {
mac = mac_str;
}
// Delegate to the internal helper.
return CheckValueInternal(path, initial_value, encrypted_hash, mac);
}
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash(
const std::string& path,
const base::Value* new_value) {
const std::string mac = outer_->ComputeMac(path, new_value);
contents_->SetMac(path, mac);
super_mac_dirty_ = true;
}
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreEncryptedHash(
const std::string& path,
const base::Value* value) {
if (!encryptor_) {
return;
}
const std::string encrypted_hash_str =
outer_->ComputeEncryptedHash(path, value, encryptor_);
std::string enc_key = GetEncryptedHashKey(path);
// ComputeEncryptedHash from PrefHashStoreImpl returns "" on failure.
if (!encrypted_hash_str.empty()) {
// Calculation and encryption were successful, store it.
contents_->SetMac(enc_key, encrypted_hash_str);
super_mac_dirty_ = true;
} else {
// Computation failed, ensure no (potentially old or empty) hash is stored.
if (contents_->RemoveEntry(enc_key)) {
super_mac_dirty_ = true;
}
}
}
ValueState
PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValueInternal(
const std::string& path,
const base::Value::Dict* initial_split_value,
bool has_encrypted_hashes,
const std::map<std::string, std::string>& split_encrypted_hashes,
bool has_mac_hashes,
const std::map<std::string, std::string>& split_macs,
std::vector<std::string>* invalid_keys) const {
DCHECK(invalid_keys && invalid_keys->empty());
const bool is_initial_value_empty =
(!initial_split_value || initial_split_value->empty());
bool only_unusable_encrypted_present = false;
if (encryptor_) {
// --- Encryptor is available ---
if (has_encrypted_hashes) {
// --- Priority 1: Check split encrypted hashes ---
std::map<std::string, std::string> current_encrypted =
split_encrypted_hashes;
if (initial_split_value) {
for (const auto item : *initial_split_value) {
const std::string keyed_path = path + "." + item.first;
auto it = current_encrypted.find(item.first);
if (it == current_encrypted.end() ||
outer_->pref_hash_calculator_.ValidateEncrypted(
keyed_path, &item.second, it->second, encryptor_) !=
ValidationResult::VALID_ENCRYPTED) {
invalid_keys->push_back(item.first);
}
if (it != current_encrypted.end()) {
current_encrypted.erase(it);
}
}
}
for (const auto& pair : current_encrypted) {
invalid_keys->push_back(pair.first);
}
if (invalid_keys->empty()) {
return ValueState::UNCHANGED_ENCRYPTED;
}
return is_initial_value_empty ? ValueState::CLEARED_ENCRYPTED
: ValueState::CHANGED_ENCRYPTED;
}
// --- Priority 2: Fallback to legacy MACs for healing.
if (has_mac_hashes) {
std::map<std::string, std::string> current_macs = split_macs;
if (initial_split_value) {
for (const auto item : *initial_split_value) {
const std::string keyed_path = path + "." + item.first;
auto it = current_macs.find(item.first);
if (it == current_macs.end() ||
outer_->pref_hash_calculator_.Validate(keyed_path, &item.second,
it->second) !=
ValidationResult::VALID) {
invalid_keys->push_back(item.first);
}
if (it != current_macs.end()) {
current_macs.erase(it);
}
}
}
for (const auto& pair : current_macs) {
invalid_keys->push_back(pair.first);
}
if (invalid_keys->empty()) {
return ValueState::UNCHANGED_VIA_HMAC_FALLBACK;
}
return is_initial_value_empty ? ValueState::CLEARED_VIA_HMAC_FALLBACK
: ValueState::CHANGED_VIA_HMAC_FALLBACK;
}
} else {
// --- No encryptor, legacy-only path ---
if (has_mac_hashes) {
std::map<std::string, std::string> current_macs = split_macs;
if (initial_split_value) {
for (const auto item : *initial_split_value) {
const std::string keyed_path = path + "." + item.first;
auto it = current_macs.find(item.first);
if (it == current_macs.end() ||
outer_->pref_hash_calculator_.Validate(keyed_path, &item.second,
it->second) !=
ValidationResult::VALID) {
invalid_keys->push_back(item.first);
}
if (it != current_macs.end()) {
current_macs.erase(it);
}
}
}
for (const auto& pair : current_macs) {
invalid_keys->push_back(pair.first);
}
if (invalid_keys->empty()) {
return ValueState::UNCHANGED;
}
return is_initial_value_empty ? ValueState::CLEARED
: ValueState::CHANGED;
}
}
// --- No Usable Hashes Found ---
// Arrive here if:
// 1. No hashes stored at all.
// 2. ONLY encrypted hashes stored, but no encryptor (fell through).
if (is_initial_value_empty) {
return ValueState::UNCHANGED;
}
if (only_unusable_encrypted_present) {
return ValueState::UNTRUSTED_UNKNOWN_VALUE;
}
// Otherwise (genuinely no hashes at all, or MACs were checked and failed),
// base trust on SuperMAC validity *cached at the start of the transaction*.
if (super_mac_valid_) {
return ValueState::TRUSTED_UNKNOWN_VALUE;
} else {
return ValueState::UNTRUSTED_UNKNOWN_VALUE;
}
}
ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue(
const std::string& path,
const base::Value::Dict* initial_split_value,
std::vector<std::string>* invalid_keys) const {
// Attempt to retrieve both types of split hashes.
std::map<std::string, std::string> split_encrypted_hashes;
bool has_encrypted = GetSplitEncryptedHashes(path, &split_encrypted_hashes);
std::map<std::string, std::string> split_macs;
bool has_macs = contents_->GetSplitMacs(path, &split_macs);
return CheckSplitValueInternal(path, initial_split_value, has_encrypted,
split_encrypted_hashes, has_macs, split_macs,
invalid_keys);
}
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash(
const std::string& path,
const base::Value::Dict* split_value) {
contents_->RemoveEntry(path);
if (split_value) {
base::Value::Dict split_macs = outer_->ComputeSplitMacs(path, split_value);
for (const auto item : split_macs) {
DCHECK(item.second.is_string());
contents_->SetSplitMac(path, item.first, item.second.GetString());
}
}
super_mac_dirty_ = true;
}
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitEncryptedHash(
const std::string& path,
const base::Value::Dict* split_value) {
// Encrypted hash requires the encryptor.
if (!encryptor_) {
return;
}
// Also remove any existing single *encrypted hash* entry for the base path
contents_->RemoveEntry(GetEncryptedHashKey(path));
// Use the derived key for storing split encrypted hashes.
const std::string encrypted_hash_base_key = GetEncryptedHashKey(path);
if (split_value) {
base::Value::Dict split_encrypted_hashes =
outer_->ComputeSplitEncryptedHashes(path, split_value, encryptor_);
for (const auto item : split_encrypted_hashes) {
DCHECK(item.second.is_string());
// Store using the derived base key.
contents_->SetSplitMac(encrypted_hash_base_key, item.first,
item.second.GetString());
}
}
super_mac_dirty_ = true;
}
bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::HasHash(
const std::string& path) const {
std::string out_value;
std::map<std::string, std::string> out_values;
return HasEncryptedHash(path) || contents_->GetMac(path, &out_value) ||
contents_->GetSplitMacs(path, &out_values);
}
bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::HasEncryptedHash(
const std::string& path) const {
std::string out_value;
const std::string encrypted_key = GetEncryptedHashKey(path);
std::map<std::string, std::string> out_values;
return contents_->GetMac(encrypted_key, &out_value) ||
contents_->GetSplitMacs(encrypted_key, &out_values);
}
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash(
const std::string& path,
const base::Value* hash) {
DCHECK(hash);
bool changed = false;
if (hash->is_string()) {
// --- Case 1: Input is a string ---
// Legacy MAC. Import it and clear any existing encrypted
// hash.
contents_->ImportEntry(path, hash);
if (contents_->RemoveEntry(GetEncryptedHashKey(path))) {
changed = true;
}
// ImportEntry itself implies a change, so mark dirty regardless of
// RemoveEntry result.
changed = true;
} else if (hash->is_dict()) {
// --- Case 2: Input is a dict ---
const base::Value::Dict& dict = hash->GetDict();
// Handle MAC part
const std::string* mac_str_ptr = dict.FindString(kImportMacKey);
if (mac_str_ptr) {
// Import the MAC if found in the dictionary
base::Value mac_value(*mac_str_ptr);
contents_->ImportEntry(path, &mac_value);
changed = true;
} else {
// If "mac" key is NOT in the dictionary, clear any existing MAC for this
// path.
if (contents_->RemoveEntry(path)) {
changed = true;
}
}
// Handle Encrypted Hash part
const std::string* encrypted_hash_str_ptr =
dict.FindString(kImportEncryptedHashKey);
if (encrypted_hash_str_ptr) {
// Import the encrypted hash if found in the dictionary, using the derived
// key.
base::Value encrypted_hash_value(*encrypted_hash_str_ptr);
contents_->ImportEntry(GetEncryptedHashKey(path), &encrypted_hash_value);
changed = true;
} else {
// If "encrypted_hash" key is NOT in the dictionary, clear any existing
// encrypted hash for this path (using the derived key).
if (contents_->RemoveEntry(GetEncryptedHashKey(path))) {
changed = true;
}
}
} else {
return;
}
// If any import or removal happened and the store was considered valid, mark
// super MAC as dirty.
if (changed && super_mac_valid_) {
super_mac_dirty_ = true;
} else if (hash->is_string() || hash->is_dict()) {
if (super_mac_valid_) {
super_mac_dirty_ = true;
}
}
}
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash(
const std::string& path) {
bool changed = false;
std::string enc_key = GetEncryptedHashKey(path); // Get derived key once
// Remove atomic MAC entry OR split MAC dictionary at 'path'
if (contents_->RemoveEntry(path)) {
changed = true;
}
// Remove atomic Encrypted Hash entry OR split encrypted hash dictionary at
// derived key
if (contents_->RemoveEntry(enc_key)) {
changed = true;
}
// Mark SuperMAC dirty only if something was actually removed AND if the
// SuperMAC was considered valid at the start of the transaction.
if (changed && super_mac_valid_) {
super_mac_dirty_ = true;
}
}
void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearEncryptedHash(
const std::string& path) {
// Clear only the Encrypted Hash (atomic and split) using the derived key.
if (contents_->RemoveEntry(GetEncryptedHashKey(path)) && super_mac_valid_) {
super_mac_dirty_ = true;
}
}
bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::IsSuperMACValid() const {
return super_mac_valid_;
}
bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() {
if (!outer_->use_super_mac_) {
return false;
}
super_mac_dirty_ = true;
super_mac_valid_ = true;
return true;
}