Home | History | Annotate | Download | only in platform_keys
      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 "chrome/browser/extensions/state_store.h"
     12 #include "content/public/browser/browser_thread.h"
     13 
     14 using content::BrowserThread;
     15 
     16 namespace chromeos {
     17 
     18 namespace {
     19 
     20 const char kErrorInternal[] = "Internal Error.";
     21 const char kErrorKeyNotAllowedForSigning[] =
     22     "This key is not allowed for signing. Either it was used for signing "
     23     "before or it was not correctly generated.";
     24 const char kStateStorePlatformKeys[] = "PlatformKeys";
     25 
     26 scoped_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.
     35 void 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.
     50 void 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 
     72 PlatformKeysService::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 
     81 PlatformKeysService::~PlatformKeysService() {
     82 }
     83 
     84 void 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 
    100 void 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 
    118 void 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 
    131 void 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 
    143 void 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 
    155 void 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 
    169 void 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 
    194 void 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 
    215 void 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