summaryrefslogtreecommitdiffstats
path: root/components/nacl/browser/nacl_validation_cache.cc
blob: e956cb1815dd1533c8e34131aea2cf90f0db9962 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// 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 = 500;
// 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(base::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 base::Pickle* pickle) {
  bool success = DeserializeImpl(pickle);
  if (!success) {
    Reset();
  }
  return success;
}

bool NaClValidationCache::DeserializeImpl(const base::Pickle* pickle) {
  base::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