Home | History | Annotate | Download | only in webcrypto
      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 "content/child/webcrypto/algorithm_dispatch.h"
      6 
      7 #include "base/logging.h"
      8 #include "content/child/webcrypto/algorithm_implementation.h"
      9 #include "content/child/webcrypto/algorithm_registry.h"
     10 #include "content/child/webcrypto/crypto_data.h"
     11 #include "content/child/webcrypto/platform_crypto.h"
     12 #include "content/child/webcrypto/status.h"
     13 #include "content/child/webcrypto/webcrypto_util.h"
     14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
     15 
     16 namespace content {
     17 
     18 namespace webcrypto {
     19 
     20 namespace {
     21 
     22 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
     23                                 const blink::WebCryptoKey& key,
     24                                 const CryptoData& data,
     25                                 std::vector<uint8_t>* buffer) {
     26   if (algorithm.id() != key.algorithm().id())
     27     return Status::ErrorUnexpected();
     28 
     29   const AlgorithmImplementation* impl = NULL;
     30   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
     31   if (status.IsError())
     32     return status;
     33 
     34   return impl->Decrypt(algorithm, key, data, buffer);
     35 }
     36 
     37 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
     38                              const blink::WebCryptoKey& key,
     39                              const CryptoData& data,
     40                              std::vector<uint8_t>* buffer) {
     41   if (algorithm.id() != key.algorithm().id())
     42     return Status::ErrorUnexpected();
     43 
     44   const AlgorithmImplementation* impl = NULL;
     45   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
     46   if (status.IsError())
     47     return status;
     48 
     49   return impl->Encrypt(algorithm, key, data, buffer);
     50 }
     51 
     52 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,
     53                                         const blink::WebCryptoKey& key,
     54                                         std::vector<uint8_t>* buffer) {
     55   const AlgorithmImplementation* impl = NULL;
     56   Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl);
     57   if (status.IsError())
     58     return status;
     59 
     60   switch (format) {
     61     case blink::WebCryptoKeyFormatRaw:
     62       return impl->ExportKeyRaw(key, buffer);
     63     case blink::WebCryptoKeyFormatSpki:
     64       return impl->ExportKeySpki(key, buffer);
     65     case blink::WebCryptoKeyFormatPkcs8:
     66       return impl->ExportKeyPkcs8(key, buffer);
     67     case blink::WebCryptoKeyFormatJwk:
     68       return impl->ExportKeyJwk(key, buffer);
     69     default:
     70       return Status::ErrorUnsupported();
     71   }
     72 }
     73 
     74 }  // namespace
     75 
     76 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
     77                const blink::WebCryptoKey& key,
     78                const CryptoData& data,
     79                std::vector<uint8_t>* buffer) {
     80   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
     81     return Status::ErrorUnexpected();
     82   return EncryptDontCheckUsage(algorithm, key, data, buffer);
     83 }
     84 
     85 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
     86                const blink::WebCryptoKey& key,
     87                const CryptoData& data,
     88                std::vector<uint8_t>* buffer) {
     89   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
     90     return Status::ErrorUnexpected();
     91   return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
     92 }
     93 
     94 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
     95               const CryptoData& data,
     96               std::vector<uint8_t>* buffer) {
     97   const AlgorithmImplementation* impl = NULL;
     98   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
     99   if (status.IsError())
    100     return status;
    101 
    102   return impl->Digest(algorithm, data, buffer);
    103 }
    104 
    105 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
    106                          bool extractable,
    107                          blink::WebCryptoKeyUsageMask usage_mask,
    108                          blink::WebCryptoKey* key) {
    109   const AlgorithmImplementation* impl = NULL;
    110   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
    111   if (status.IsError())
    112     return status;
    113 
    114   status = impl->VerifyKeyUsagesBeforeGenerateKey(usage_mask);
    115   if (status.IsError())
    116     return status;
    117 
    118   return impl->GenerateSecretKey(algorithm, extractable, usage_mask, key);
    119 }
    120 
    121 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
    122                        bool extractable,
    123                        blink::WebCryptoKeyUsageMask combined_usage_mask,
    124                        blink::WebCryptoKey* public_key,
    125                        blink::WebCryptoKey* private_key) {
    126   const AlgorithmImplementation* impl = NULL;
    127   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
    128   if (status.IsError())
    129     return status;
    130 
    131   blink::WebCryptoKeyUsageMask public_usage_mask;
    132   blink::WebCryptoKeyUsageMask private_usage_mask;
    133   status = impl->VerifyKeyUsagesBeforeGenerateKeyPair(
    134       combined_usage_mask, &public_usage_mask, &private_usage_mask);
    135   if (status.IsError())
    136     return status;
    137 
    138   return impl->GenerateKeyPair(algorithm,
    139                                extractable,
    140                                public_usage_mask,
    141                                private_usage_mask,
    142                                public_key,
    143                                private_key);
    144 }
    145 
    146 // Note that this function may be called from the target Blink thread.
    147 Status ImportKey(blink::WebCryptoKeyFormat format,
    148                  const CryptoData& key_data,
    149                  const blink::WebCryptoAlgorithm& algorithm,
    150                  bool extractable,
    151                  blink::WebCryptoKeyUsageMask usage_mask,
    152                  blink::WebCryptoKey* key) {
    153   const AlgorithmImplementation* impl = NULL;
    154   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
    155   if (status.IsError())
    156     return status;
    157 
    158   status = impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask);
    159   if (status.IsError())
    160     return status;
    161 
    162   switch (format) {
    163     case blink::WebCryptoKeyFormatRaw:
    164       return impl->ImportKeyRaw(
    165           key_data, algorithm, extractable, usage_mask, key);
    166     case blink::WebCryptoKeyFormatSpki:
    167       return impl->ImportKeySpki(
    168           key_data, algorithm, extractable, usage_mask, key);
    169     case blink::WebCryptoKeyFormatPkcs8:
    170       return impl->ImportKeyPkcs8(
    171           key_data, algorithm, extractable, usage_mask, key);
    172     case blink::WebCryptoKeyFormatJwk:
    173       return impl->ImportKeyJwk(
    174           key_data, algorithm, extractable, usage_mask, key);
    175     default:
    176       return Status::ErrorUnsupported();
    177   }
    178 }
    179 
    180 Status ExportKey(blink::WebCryptoKeyFormat format,
    181                  const blink::WebCryptoKey& key,
    182                  std::vector<uint8_t>* buffer) {
    183   if (!key.extractable())
    184     return Status::ErrorKeyNotExtractable();
    185   return ExportKeyDontCheckExtractability(format, key, buffer);
    186 }
    187 
    188 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
    189             const blink::WebCryptoKey& key,
    190             const CryptoData& data,
    191             std::vector<uint8_t>* buffer) {
    192   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
    193     return Status::ErrorUnexpected();
    194   if (algorithm.id() != key.algorithm().id())
    195     return Status::ErrorUnexpected();
    196 
    197   const AlgorithmImplementation* impl = NULL;
    198   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
    199   if (status.IsError())
    200     return status;
    201 
    202   return impl->Sign(algorithm, key, data, buffer);
    203 }
    204 
    205 Status Verify(const blink::WebCryptoAlgorithm& algorithm,
    206               const blink::WebCryptoKey& key,
    207               const CryptoData& signature,
    208               const CryptoData& data,
    209               bool* signature_match) {
    210   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify))
    211     return Status::ErrorUnexpected();
    212   if (algorithm.id() != key.algorithm().id())
    213     return Status::ErrorUnexpected();
    214 
    215   const AlgorithmImplementation* impl = NULL;
    216   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
    217   if (status.IsError())
    218     return status;
    219 
    220   return impl->Verify(algorithm, key, signature, data, signature_match);
    221 }
    222 
    223 Status WrapKey(blink::WebCryptoKeyFormat format,
    224                const blink::WebCryptoKey& key_to_wrap,
    225                const blink::WebCryptoKey& wrapping_key,
    226                const blink::WebCryptoAlgorithm& wrapping_algorithm,
    227                std::vector<uint8_t>* buffer) {
    228   if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey))
    229     return Status::ErrorUnexpected();
    230 
    231   std::vector<uint8_t> exported_data;
    232   Status status = ExportKey(format, key_to_wrap, &exported_data);
    233   if (status.IsError())
    234     return status;
    235   return EncryptDontCheckUsage(
    236       wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer);
    237 }
    238 
    239 Status UnwrapKey(blink::WebCryptoKeyFormat format,
    240                  const CryptoData& wrapped_key_data,
    241                  const blink::WebCryptoKey& wrapping_key,
    242                  const blink::WebCryptoAlgorithm& wrapping_algorithm,
    243                  const blink::WebCryptoAlgorithm& algorithm,
    244                  bool extractable,
    245                  blink::WebCryptoKeyUsageMask usage_mask,
    246                  blink::WebCryptoKey* key) {
    247   if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
    248     return Status::ErrorUnexpected();
    249   if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
    250     return Status::ErrorUnexpected();
    251 
    252   // Fail fast if the import is doomed to fail.
    253   const AlgorithmImplementation* import_impl = NULL;
    254   Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl);
    255   if (status.IsError())
    256     return status;
    257 
    258   status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask);
    259   if (status.IsError())
    260     return status;
    261 
    262   std::vector<uint8_t> buffer;
    263   status = DecryptDontCheckKeyUsage(
    264       wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
    265   if (status.IsError())
    266     return status;
    267 
    268   // NOTE that returning the details of ImportKey() failures may leak
    269   // information about the plaintext of the encrypted key (for instance the JWK
    270   // key_ops). As long as the ImportKey error messages don't describe actual
    271   // key bytes however this should be OK. For more discussion see
    272   // http://crubg.com/372040
    273   return ImportKey(
    274       format, CryptoData(buffer), algorithm, extractable, usage_mask, key);
    275 }
    276 
    277 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
    278     blink::WebCryptoAlgorithmId algorithm) {
    279   PlatformInit();
    280   return CreatePlatformDigestor(algorithm);
    281 }
    282 
    283 }  // namespace webcrypto
    284 
    285 }  // namespace content
    286