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 "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
6
7#include "base/base64.h"
8#include "base/callback.h"
9#include "base/values.h"
10#include "chrome/browser/chromeos/platform_keys/platform_keys.h"
11#include "content/public/browser/browser_thread.h"
12#include "extensions/browser/state_store.h"
13
14using content::BrowserThread;
15
16namespace chromeos {
17
18namespace {
19
20const char kErrorInternal[] = "Internal Error.";
21const char kErrorKeyNotAllowedForSigning[] =
22    "This key is not allowed for signing. Either it was used for signing "
23    "before or it was not correctly generated.";
24const char kStateStorePlatformKeys[] = "PlatformKeys";
25
26scoped_ptr<base::StringValue> GetPublicKeyValue(
27    const std::string& public_key_spki_der) {
28  std::string public_key_spki_der_b64;
29  base::Base64Encode(public_key_spki_der, &public_key_spki_der_b64);
30  return make_scoped_ptr(new base::StringValue(public_key_spki_der_b64));
31}
32
33// Wraps |callback| into a void(bool) callback which forwards
34// |public_key_spki_der| if |true| is passed to it.
35void WrapGenerateKeyCallback(
36    const PlatformKeysService::GenerateKeyCallback& callback,
37    const std::string& public_key_spki_der,
38    bool success) {
39  if (success)
40    callback.Run(public_key_spki_der, std::string() /* no error */);
41  else
42    callback.Run(std::string() /* no public key */, kErrorInternal);
43}
44
45// Callback used by |PlatformKeysService::Sign|.
46// Is called with the old validity of |public_key_spki_der| (or false if an
47// error occurred during reading the StateStore). If allowed, starts the actual
48// signing operation which will call back |callback|. If not allowed, calls
49// |callback| with an error.
50void CheckValidityAndSign(const std::string& token_id,
51                          const std::string& public_key_spki_der,
52                          platform_keys::HashAlgorithm hash_algorithm,
53                          const std::string& data,
54                          const PlatformKeysService::SignCallback& callback,
55                          content::BrowserContext* browser_context,
56                          bool key_is_valid) {
57  if (!key_is_valid) {
58    callback.Run(std::string() /* no signature */,
59                 kErrorKeyNotAllowedForSigning);
60    return;
61  }
62  platform_keys::subtle::Sign(token_id,
63                              public_key_spki_der,
64                              hash_algorithm,
65                              data,
66                              callback,
67                              browser_context);
68}
69
70}  // namespace
71
72PlatformKeysService::PlatformKeysService(
73    content::BrowserContext* browser_context,
74    extensions::StateStore* state_store)
75    : browser_context_(browser_context),
76      state_store_(state_store),
77      weak_factory_(this) {
78  DCHECK(state_store);
79}
80
81PlatformKeysService::~PlatformKeysService() {
82}
83
84void PlatformKeysService::GenerateRSAKey(const std::string& token_id,
85                                         unsigned int modulus_length,
86                                         const std::string& extension_id,
87                                         const GenerateKeyCallback& callback) {
88  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89
90  platform_keys::subtle::GenerateRSAKey(
91      token_id,
92      modulus_length,
93      base::Bind(&PlatformKeysService::GenerateRSAKeyCallback,
94                 weak_factory_.GetWeakPtr(),
95                 extension_id,
96                 callback),
97      browser_context_);
98}
99
100void PlatformKeysService::Sign(const std::string& token_id,
101                               const std::string& public_key_spki_der,
102                               platform_keys::HashAlgorithm hash_algorithm,
103                               const std::string& data,
104                               const std::string& extension_id,
105                               const SignCallback& callback) {
106  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
107  ReadValidityAndInvalidateKey(extension_id,
108                               public_key_spki_der,
109                               base::Bind(&CheckValidityAndSign,
110                                          token_id,
111                                          public_key_spki_der,
112                                          hash_algorithm,
113                                          data,
114                                          callback,
115                                          browser_context_));
116}
117
118void PlatformKeysService::RegisterPublicKey(
119    const std::string& extension_id,
120    const std::string& public_key_spki_der,
121    const base::Callback<void(bool)>& callback) {
122  GetPlatformKeysOfExtension(
123      extension_id,
124      base::Bind(&PlatformKeysService::RegisterPublicKeyGotPlatformKeys,
125                 weak_factory_.GetWeakPtr(),
126                 extension_id,
127                 public_key_spki_der,
128                 callback));
129}
130
131void PlatformKeysService::ReadValidityAndInvalidateKey(
132    const std::string& extension_id,
133    const std::string& public_key_spki_der,
134    const base::Callback<void(bool)>& callback) {
135  GetPlatformKeysOfExtension(extension_id,
136                             base::Bind(&PlatformKeysService::InvalidateKey,
137                                        weak_factory_.GetWeakPtr(),
138                                        extension_id,
139                                        public_key_spki_der,
140                                        callback));
141}
142
143void PlatformKeysService::GetPlatformKeysOfExtension(
144    const std::string& extension_id,
145    const GetPlatformKeysCallback& callback) {
146  state_store_->GetExtensionValue(
147      extension_id,
148      kStateStorePlatformKeys,
149      base::Bind(&PlatformKeysService::GotPlatformKeysOfExtension,
150                 weak_factory_.GetWeakPtr(),
151                 extension_id,
152                 callback));
153}
154
155void PlatformKeysService::GenerateRSAKeyCallback(
156    const std::string& extension_id,
157    const GenerateKeyCallback& callback,
158    const std::string& public_key_spki_der,
159    const std::string& error_message) {
160  if (!error_message.empty()) {
161    callback.Run(std::string() /* no public key */, error_message);
162    return;
163  }
164  base::Callback<void(bool)> wrapped_callback(
165      base::Bind(&WrapGenerateKeyCallback, callback, public_key_spki_der));
166  RegisterPublicKey(extension_id, public_key_spki_der, wrapped_callback);
167}
168
169void PlatformKeysService::RegisterPublicKeyGotPlatformKeys(
170    const std::string& extension_id,
171    const std::string& public_key_spki_der,
172    const base::Callback<void(bool)>& callback,
173    scoped_ptr<base::ListValue> platform_keys) {
174  if (!platform_keys) {
175    LOG(ERROR) << "Error while reading the platform keys.";
176    callback.Run(false);
177    return;
178  }
179
180  scoped_ptr<base::StringValue> key_value(
181      GetPublicKeyValue(public_key_spki_der));
182
183  DCHECK(platform_keys->end() == platform_keys->Find(*key_value))
184      << "Keys are assumed to be generated and not to be registered multiple "
185         "times.";
186  platform_keys->Append(key_value.release());
187
188  state_store_->SetExtensionValue(extension_id,
189                                  kStateStorePlatformKeys,
190                                  platform_keys.PassAs<base::Value>());
191  callback.Run(true);
192}
193
194void PlatformKeysService::InvalidateKey(
195    const std::string& extension_id,
196    const std::string& public_key_spki_der,
197    const base::Callback<void(bool)>& callback,
198    scoped_ptr<base::ListValue> platform_keys) {
199  scoped_ptr<base::StringValue> key_value(
200      GetPublicKeyValue(public_key_spki_der));
201
202  size_t index = 0;
203  if (!platform_keys->Remove(*key_value, &index)) {
204    // The key is not found, so it's not valid to use it for signing.
205    callback.Run(false);
206    return;
207  }
208
209  state_store_->SetExtensionValue(extension_id,
210                                  kStateStorePlatformKeys,
211                                  platform_keys.PassAs<base::Value>());
212  callback.Run(true);
213}
214
215void PlatformKeysService::GotPlatformKeysOfExtension(
216    const std::string& extension_id,
217    const GetPlatformKeysCallback& callback,
218    scoped_ptr<base::Value> value) {
219  if (!value)
220    value.reset(new base::ListValue);
221
222  base::ListValue* keys = NULL;
223  if (!value->GetAsList(&keys)) {
224    LOG(ERROR) << "Found a value of wrong type.";
225    value.reset();
226  }
227  ignore_result(value.release());
228  callback.Run(make_scoped_ptr(keys));
229}
230
231}  // namespace chromeos
232