1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/nacl/browser/nacl_validation_cache.h"
6 
7 #include "base/pickle.h"
8 #include "base/rand_util.h"
9 
10 namespace nacl {
11 
12 // For the moment, choose an arbitrary cache size.
13 const size_t kValidationCacheCacheSize = 500;
14 // Key size is equal to the block size (not the digest size) of SHA256.
15 const size_t kValidationCacheKeySize = 64;
16 // Entry size is equal to the digest size of SHA256.
17 const size_t kValidationCacheEntrySize = 32;
18 
19 const char kValidationCacheBeginMagic[] = "NaCl";
20 const char kValidationCacheEndMagic[] = "Done";
21 
NaClValidationCache()22 NaClValidationCache::NaClValidationCache()
23     : validation_cache_(kValidationCacheCacheSize) {
24   // Make sure the cache key is unpredictable, even if the cache has not
25   // been loaded.
26   Reset();
27 }
28 
~NaClValidationCache()29 NaClValidationCache::~NaClValidationCache() {
30   // Make clang's style checking happy by adding a destructor.
31 }
32 
QueryKnownToValidate(const std::string & signature,bool reorder)33 bool NaClValidationCache::QueryKnownToValidate(const std::string& signature,
34                                                bool reorder) {
35   if (signature.length() == kValidationCacheEntrySize) {
36     ValidationCacheType::iterator iter;
37     if (reorder) {
38       iter = validation_cache_.Get(signature);
39     } else {
40       iter = validation_cache_.Peek(signature);
41     }
42     if (iter != validation_cache_.end()) {
43       return iter->second;
44     }
45   }
46   return false;
47 }
48 
SetKnownToValidate(const std::string & signature)49 void NaClValidationCache::SetKnownToValidate(const std::string& signature) {
50   if (signature.length() == kValidationCacheEntrySize) {
51     validation_cache_.Put(signature, true);
52   }
53 }
54 
Serialize(base::Pickle * pickle) const55 void NaClValidationCache::Serialize(base::Pickle* pickle) const {
56   // Mark the beginning of the data stream.
57   pickle->WriteString(kValidationCacheBeginMagic);
58   pickle->WriteString(validation_cache_key_);
59   pickle->WriteInt(validation_cache_.size());
60 
61   // Serialize the cache in reverse order so that deserializing it can easily
62   // preserve the MRU order.  (Last item deserialized => most recently used.)
63   ValidationCacheType::const_reverse_iterator iter;
64   for (iter = validation_cache_.rbegin();
65        iter != validation_cache_.rend();
66        ++iter) {
67     pickle->WriteString(iter->first);
68   }
69 
70   // Mark the end of the data stream.
71   pickle->WriteString(kValidationCacheEndMagic);
72 }
73 
Reset()74 void NaClValidationCache::Reset() {
75   validation_cache_key_ = base::RandBytesAsString(kValidationCacheKeySize);
76   validation_cache_.Clear();
77 }
78 
Deserialize(const base::Pickle * pickle)79 bool NaClValidationCache::Deserialize(const base::Pickle* pickle) {
80   bool success = DeserializeImpl(pickle);
81   if (!success) {
82     Reset();
83   }
84   return success;
85 }
86 
DeserializeImpl(const base::Pickle * pickle)87 bool NaClValidationCache::DeserializeImpl(const base::Pickle* pickle) {
88   base::PickleIterator iter(*pickle);
89   std::string buffer;
90   int count;
91 
92   // Magic
93   if (!iter.ReadString(&buffer))
94     return false;
95   if (0 != buffer.compare(kValidationCacheBeginMagic))
96     return false;
97 
98   // Key
99   if (!iter.ReadString(&buffer))
100     return false;
101   if (buffer.size() != kValidationCacheKeySize)
102     return false;
103 
104   validation_cache_key_ = buffer;
105   validation_cache_.Clear();
106 
107   // Cache entries
108   if (!iter.ReadInt(&count))
109     return false;
110   for (int i = 0; i < count; ++i) {
111     if (!iter.ReadString(&buffer))
112       return false;
113     if (buffer.size() != kValidationCacheEntrySize)
114       return false;
115     validation_cache_.Put(buffer, true);
116   }
117 
118   // Magic
119   if (!iter.ReadString(&buffer))
120     return false;
121   if (0 != buffer.compare(kValidationCacheEndMagic))
122     return false;
123 
124   // Success!
125   return true;
126 }
127 
128 } // namespace nacl
129 
130