| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/nacl/browser/nacl_validation_cache.h" |
| |
| #include "base/pickle.h" |
| #include "base/rand_util.h" |
| |
| namespace nacl { |
| |
| // For the moment, choose an arbitrary cache size. |
| const size_t kValidationCacheCacheSize = 200; |
| // Key size is equal to the block size (not the digest size) of SHA256. |
| const size_t kValidationCacheKeySize = 64; |
| // Entry size is equal to the digest size of SHA256. |
| const size_t kValidationCacheEntrySize = 32; |
| |
| const char kValidationCacheBeginMagic[] = "NaCl"; |
| const char kValidationCacheEndMagic[] = "Done"; |
| |
| NaClValidationCache::NaClValidationCache() |
| : validation_cache_(kValidationCacheCacheSize) { |
| // Make sure the cache key is unpredictable, even if the cache has not |
| // been loaded. |
| Reset(); |
| } |
| |
| NaClValidationCache::~NaClValidationCache() { |
| // Make clang's style checking happy by adding a destructor. |
| } |
| |
| bool NaClValidationCache::QueryKnownToValidate(const std::string& signature, |
| bool reorder) { |
| if (signature.length() == kValidationCacheEntrySize) { |
| ValidationCacheType::iterator iter; |
| if (reorder) { |
| iter = validation_cache_.Get(signature); |
| } else { |
| iter = validation_cache_.Peek(signature); |
| } |
| if (iter != validation_cache_.end()) { |
| return iter->second; |
| } |
| } |
| return false; |
| } |
| |
| void NaClValidationCache::SetKnownToValidate(const std::string& signature) { |
| if (signature.length() == kValidationCacheEntrySize) { |
| validation_cache_.Put(signature, true); |
| } |
| } |
| |
| void NaClValidationCache::Serialize(Pickle* pickle) const { |
| // Mark the beginning of the data stream. |
| pickle->WriteString(kValidationCacheBeginMagic); |
| pickle->WriteString(validation_cache_key_); |
| pickle->WriteInt(validation_cache_.size()); |
| |
| // Serialize the cache in reverse order so that deserializing it can easily |
| // preserve the MRU order. (Last item deserialized => most recently used.) |
| ValidationCacheType::const_reverse_iterator iter; |
| for (iter = validation_cache_.rbegin(); |
| iter != validation_cache_.rend(); |
| ++iter) { |
| pickle->WriteString(iter->first); |
| } |
| |
| // Mark the end of the data stream. |
| pickle->WriteString(kValidationCacheEndMagic); |
| } |
| |
| void NaClValidationCache::Reset() { |
| validation_cache_key_ = base::RandBytesAsString(kValidationCacheKeySize); |
| validation_cache_.Clear(); |
| } |
| |
| bool NaClValidationCache::Deserialize(const Pickle* pickle) { |
| bool success = DeserializeImpl(pickle); |
| if (!success) { |
| Reset(); |
| } |
| return success; |
| } |
| |
| bool NaClValidationCache::DeserializeImpl(const Pickle* pickle) { |
| PickleIterator iter(*pickle); |
| std::string buffer; |
| int count; |
| |
| // Magic |
| if (!iter.ReadString(&buffer)) |
| return false; |
| if (0 != buffer.compare(kValidationCacheBeginMagic)) |
| return false; |
| |
| // Key |
| if (!iter.ReadString(&buffer)) |
| return false; |
| if (buffer.size() != kValidationCacheKeySize) |
| return false; |
| |
| validation_cache_key_ = buffer; |
| validation_cache_.Clear(); |
| |
| // Cache entries |
| if (!iter.ReadInt(&count)) |
| return false; |
| for (int i = 0; i < count; ++i) { |
| if (!iter.ReadString(&buffer)) |
| return false; |
| if (buffer.size() != kValidationCacheEntrySize) |
| return false; |
| validation_cache_.Put(buffer, true); |
| } |
| |
| // Magic |
| if (!iter.ReadString(&buffer)) |
| return false; |
| if (0 != buffer.compare(kValidationCacheEndMagic)) |
| return false; |
| |
| // Success! |
| return true; |
| } |
| |
| } // namespace nacl |
| |