content_hash_reader.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright 2014 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 "extensions/browser/content_hash_reader.h"
6
7#include "base/base64.h"
8#include "base/file_util.h"
9#include "base/json/json_reader.h"
10#include "base/metrics/histogram.h"
11#include "base/strings/string_util.h"
12#include "base/timer/elapsed_timer.h"
13#include "base/values.h"
14#include "crypto/sha2.h"
15#include "extensions/browser/computed_hashes.h"
16#include "extensions/browser/content_hash_tree.h"
17#include "extensions/browser/verified_contents.h"
18#include "extensions/common/extension.h"
19#include "extensions/common/file_util.h"
20
21using base::DictionaryValue;
22using base::ListValue;
23using base::Value;
24
25namespace extensions {
26
27ContentHashReader::ContentHashReader(const std::string& extension_id,
28                                     const base::Version& extension_version,
29                                     const base::FilePath& extension_root,
30                                     const base::FilePath& relative_path,
31                                     const ContentVerifierKey& key)
32    : extension_id_(extension_id),
33      extension_version_(extension_version.GetString()),
34      extension_root_(extension_root),
35      relative_path_(relative_path),
36      key_(key),
37      status_(NOT_INITIALIZED),
38      have_verified_contents_(false),
39      have_computed_hashes_(false),
40      block_size_(0) {
41}
42
43ContentHashReader::~ContentHashReader() {
44}
45
46bool ContentHashReader::Init() {
47  base::ElapsedTimer timer;
48  DCHECK_EQ(status_, NOT_INITIALIZED);
49  status_ = FAILURE;
50  base::FilePath verified_contents_path =
51      file_util::GetVerifiedContentsPath(extension_root_);
52
53  if (!base::PathExists(verified_contents_path))
54    return false;
55
56  verified_contents_.reset(new VerifiedContents(key_.data, key_.size));
57  if (!verified_contents_->InitFrom(verified_contents_path, false) ||
58      !verified_contents_->valid_signature() ||
59      !verified_contents_->version().Equals(extension_version_) ||
60      verified_contents_->extension_id() != extension_id_)
61    return false;
62
63  have_verified_contents_ = true;
64
65  base::FilePath computed_hashes_path =
66      file_util::GetComputedHashesPath(extension_root_);
67  if (!base::PathExists(computed_hashes_path))
68    return false;
69
70  ComputedHashes::Reader reader;
71  if (!reader.InitFromFile(computed_hashes_path))
72    return false;
73
74  have_computed_hashes_ = true;
75
76  if (!reader.GetHashes(relative_path_, &block_size_, &hashes_) ||
77      block_size_ % crypto::kSHA256Length != 0)
78    return false;
79
80  const std::string* expected_root =
81      verified_contents_->GetTreeHashRoot(relative_path_);
82  if (!expected_root)
83    return false;
84
85  std::string root =
86      ComputeTreeHashRoot(hashes_, block_size_ / crypto::kSHA256Length);
87  if (*expected_root != root)
88    return false;
89
90  status_ = SUCCESS;
91  UMA_HISTOGRAM_TIMES("ExtensionContentHashReader.InitLatency",
92                      timer.Elapsed());
93  return true;
94}
95
96int ContentHashReader::block_count() const {
97  DCHECK(status_ != NOT_INITIALIZED);
98  return hashes_.size();
99}
100
101int ContentHashReader::block_size() const {
102  DCHECK(status_ != NOT_INITIALIZED);
103  return block_size_;
104}
105
106bool ContentHashReader::GetHashForBlock(int block_index,
107                                        const std::string** result) const {
108  if (status_ != SUCCESS)
109    return false;
110  DCHECK(block_index >= 0);
111
112  if (static_cast<unsigned>(block_index) >= hashes_.size())
113    return false;
114  *result = &hashes_[block_index];
115
116  return true;
117}
118
119}  // namespace extensions
120