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/shared_crypto.h"
      6 
      7 #include "base/logging.h"
      8 #include "content/child/webcrypto/crypto_data.h"
      9 #include "content/child/webcrypto/jwk.h"
     10 #include "content/child/webcrypto/platform_crypto.h"
     11 #include "content/child/webcrypto/status.h"
     12 #include "content/child/webcrypto/webcrypto_util.h"
     13 #include "crypto/secure_util.h"
     14 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
     15 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
     16 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
     17 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
     18 
     19 namespace content {
     20 
     21 namespace webcrypto {
     22 
     23 // ------------
     24 // Threading:
     25 // ------------
     26 //
     27 // All functions in this file are called from the webcrypto worker pool except
     28 // for:
     29 //
     30 //   * SerializeKeyForClone()
     31 //   * DeserializeKeyForClone()
     32 //   * ImportKey() // TODO(eroman): Change this.
     33 
     34 namespace {
     35 
     36 // TODO(eroman): Move this helper to WebCryptoKey.
     37 bool KeyUsageAllows(const blink::WebCryptoKey& key,
     38                     const blink::WebCryptoKeyUsage usage) {
     39   return ((key.usages() & usage) != 0);
     40 }
     41 
     42 bool IsValidAesKeyLengthBits(unsigned int length_bits) {
     43   // 192-bit AES is disallowed.
     44   return length_bits == 128 || length_bits == 256;
     45 }
     46 
     47 bool IsValidAesKeyLengthBytes(unsigned int length_bytes) {
     48   // 192-bit AES is disallowed.
     49   return length_bytes == 16 || length_bytes == 32;
     50 }
     51 
     52 const size_t kAesBlockSizeBytes = 16;
     53 
     54 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode,
     55                             const blink::WebCryptoAlgorithm& algorithm,
     56                             const blink::WebCryptoKey& key,
     57                             const CryptoData& data,
     58                             std::vector<uint8>* buffer) {
     59   platform::SymKey* sym_key;
     60   Status status = ToPlatformSymKey(key, &sym_key);
     61   if (status.IsError())
     62     return status;
     63 
     64   const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
     65   if (!params)
     66     return Status::ErrorUnexpected();
     67 
     68   CryptoData iv(params->iv().data(), params->iv().size());
     69   if (iv.byte_length() != kAesBlockSizeBytes)
     70     return Status::ErrorIncorrectSizeAesCbcIv();
     71 
     72   return platform::EncryptDecryptAesCbc(mode, sym_key, data, iv, buffer);
     73 }
     74 
     75 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode,
     76                             const blink::WebCryptoAlgorithm& algorithm,
     77                             const blink::WebCryptoKey& key,
     78                             const CryptoData& data,
     79                             std::vector<uint8>* buffer) {
     80   platform::SymKey* sym_key;
     81   Status status = ToPlatformSymKey(key, &sym_key);
     82   if (status.IsError())
     83     return status;
     84 
     85   const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
     86   if (!params)
     87     return Status::ErrorUnexpected();
     88 
     89   unsigned int tag_length_bits = 128;
     90   if (params->hasTagLengthBits())
     91     tag_length_bits = params->optionalTagLengthBits();
     92 
     93   if (tag_length_bits != 32 && tag_length_bits != 64 && tag_length_bits != 96 &&
     94       tag_length_bits != 104 && tag_length_bits != 112 &&
     95       tag_length_bits != 120 && tag_length_bits != 128)
     96     return Status::ErrorInvalidAesGcmTagLength();
     97 
     98   return platform::EncryptDecryptAesGcm(
     99       mode,
    100       sym_key,
    101       data,
    102       CryptoData(params->iv()),
    103       CryptoData(params->optionalAdditionalData()),
    104       tag_length_bits,
    105       buffer);
    106 }
    107 
    108 Status EncryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm,
    109                       const blink::WebCryptoKey& key,
    110                       const CryptoData& data,
    111                       std::vector<uint8>* buffer) {
    112   platform::PublicKey* public_key;
    113   Status status = ToPlatformPublicKey(key, &public_key);
    114   if (status.IsError())
    115     return status;
    116 
    117   const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams();
    118   if (!params)
    119     return Status::ErrorUnexpected();
    120 
    121   return platform::EncryptRsaOaep(public_key,
    122                                   key.algorithm().rsaHashedParams()->hash(),
    123                                   CryptoData(params->optionalLabel()),
    124                                   data,
    125                                   buffer);
    126 }
    127 
    128 Status DecryptRsaOaep(const blink::WebCryptoAlgorithm& algorithm,
    129                       const blink::WebCryptoKey& key,
    130                       const CryptoData& data,
    131                       std::vector<uint8>* buffer) {
    132   platform::PrivateKey* private_key;
    133   Status status = ToPlatformPrivateKey(key, &private_key);
    134   if (status.IsError())
    135     return status;
    136 
    137   const blink::WebCryptoRsaOaepParams* params = algorithm.rsaOaepParams();
    138   if (!params)
    139     return Status::ErrorUnexpected();
    140 
    141   return platform::DecryptRsaOaep(private_key,
    142                                   key.algorithm().rsaHashedParams()->hash(),
    143                                   CryptoData(params->optionalLabel()),
    144                                   data,
    145                                   buffer);
    146 }
    147 
    148 Status SignHmac(const blink::WebCryptoAlgorithm& algorithm,
    149                 const blink::WebCryptoKey& key,
    150                 const CryptoData& data,
    151                 std::vector<uint8>* buffer) {
    152   platform::SymKey* sym_key;
    153   Status status = ToPlatformSymKey(key, &sym_key);
    154   if (status.IsError())
    155     return status;
    156 
    157   return platform::SignHmac(
    158       sym_key, key.algorithm().hmacParams()->hash(), data, buffer);
    159 }
    160 
    161 Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm,
    162                   const blink::WebCryptoKey& key,
    163                   const CryptoData& signature,
    164                   const CryptoData& data,
    165                   bool* signature_match) {
    166   std::vector<uint8> result;
    167   Status status = SignHmac(algorithm, key, data, &result);
    168   if (status.IsError())
    169     return status;
    170 
    171   // Do not allow verification of truncated MACs.
    172   *signature_match =
    173       result.size() == signature.byte_length() &&
    174       crypto::SecureMemEqual(
    175           Uint8VectorStart(result), signature.bytes(), signature.byte_length());
    176 
    177   return Status::Success();
    178 }
    179 
    180 Status SignRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
    181                            const blink::WebCryptoKey& key,
    182                            const CryptoData& data,
    183                            std::vector<uint8>* buffer) {
    184   platform::PrivateKey* private_key;
    185   Status status = ToPlatformPrivateKey(key, &private_key);
    186   if (status.IsError())
    187     return status;
    188 
    189   return platform::SignRsaSsaPkcs1v1_5(
    190       private_key, key.algorithm().rsaHashedParams()->hash(), data, buffer);
    191 }
    192 
    193 Status VerifyRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
    194                              const blink::WebCryptoKey& key,
    195                              const CryptoData& signature,
    196                              const CryptoData& data,
    197                              bool* signature_match) {
    198   platform::PublicKey* public_key;
    199   Status status = ToPlatformPublicKey(key, &public_key);
    200   if (status.IsError())
    201     return status;
    202 
    203   return platform::VerifyRsaSsaPkcs1v1_5(
    204       public_key,
    205       key.algorithm().rsaHashedParams()->hash(),
    206       signature,
    207       data,
    208       signature_match);
    209 }
    210 
    211 // Note that this function may be called from the target Blink thread.
    212 Status ImportKeyRaw(const CryptoData& key_data,
    213                     const blink::WebCryptoAlgorithm& algorithm,
    214                     bool extractable,
    215                     blink::WebCryptoKeyUsageMask usage_mask,
    216                     blink::WebCryptoKey* key) {
    217   switch (algorithm.id()) {
    218     case blink::WebCryptoAlgorithmIdAesCtr:
    219     case blink::WebCryptoAlgorithmIdAesCbc:
    220     case blink::WebCryptoAlgorithmIdAesGcm:
    221     case blink::WebCryptoAlgorithmIdAesKw:
    222       if (!IsValidAesKeyLengthBytes(key_data.byte_length())) {
    223         return key_data.byte_length() == 24
    224                    ? Status::ErrorAes192BitUnsupported()
    225                    : Status::ErrorImportAesKeyLength();
    226       }
    227     // Fallthrough intentional!
    228     case blink::WebCryptoAlgorithmIdHmac:
    229       return platform::ImportKeyRaw(
    230           algorithm, key_data, extractable, usage_mask, key);
    231     default:
    232       return Status::ErrorUnsupported();
    233   }
    234 }
    235 
    236 // Returns the key format to use for structured cloning.
    237 blink::WebCryptoKeyFormat GetCloneFormatForKeyType(
    238     blink::WebCryptoKeyType type) {
    239   switch (type) {
    240     case blink::WebCryptoKeyTypeSecret:
    241       return blink::WebCryptoKeyFormatRaw;
    242     case blink::WebCryptoKeyTypePublic:
    243       return blink::WebCryptoKeyFormatSpki;
    244     case blink::WebCryptoKeyTypePrivate:
    245       return blink::WebCryptoKeyFormatPkcs8;
    246   }
    247 
    248   NOTREACHED();
    249   return blink::WebCryptoKeyFormatRaw;
    250 }
    251 
    252 // Converts a KeyAlgorithm into an equivalent Algorithm for import.
    253 blink::WebCryptoAlgorithm KeyAlgorithmToImportAlgorithm(
    254     const blink::WebCryptoKeyAlgorithm& algorithm) {
    255   switch (algorithm.paramsType()) {
    256     case blink::WebCryptoKeyAlgorithmParamsTypeAes:
    257       return CreateAlgorithm(algorithm.id());
    258     case blink::WebCryptoKeyAlgorithmParamsTypeHmac:
    259       return CreateHmacImportAlgorithm(algorithm.hmacParams()->hash().id());
    260     case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
    261       return CreateRsaHashedImportAlgorithm(
    262           algorithm.id(), algorithm.rsaHashedParams()->hash().id());
    263     case blink::WebCryptoKeyAlgorithmParamsTypeNone:
    264       break;
    265     default:
    266       break;
    267   }
    268   return blink::WebCryptoAlgorithm::createNull();
    269 }
    270 
    271 // There is some duplicated information in the serialized format used by
    272 // structured clone (since the KeyAlgorithm is serialized separately from the
    273 // key data). Use this extra information to further validate what was
    274 // deserialized from the key data.
    275 //
    276 // A failure here implies either a bug in the code, or that the serialized data
    277 // was corrupted.
    278 bool ValidateDeserializedKey(const blink::WebCryptoKey& key,
    279                              const blink::WebCryptoKeyAlgorithm& algorithm,
    280                              blink::WebCryptoKeyType type) {
    281   if (algorithm.id() != key.algorithm().id())
    282     return false;
    283 
    284   if (key.type() != type)
    285     return false;
    286 
    287   switch (algorithm.paramsType()) {
    288     case blink::WebCryptoKeyAlgorithmParamsTypeAes:
    289       if (algorithm.aesParams()->lengthBits() !=
    290           key.algorithm().aesParams()->lengthBits())
    291         return false;
    292       break;
    293     case blink::WebCryptoKeyAlgorithmParamsTypeRsaHashed:
    294       if (algorithm.rsaHashedParams()->modulusLengthBits() !=
    295           key.algorithm().rsaHashedParams()->modulusLengthBits())
    296         return false;
    297       if (algorithm.rsaHashedParams()->publicExponent().size() !=
    298           key.algorithm().rsaHashedParams()->publicExponent().size())
    299         return false;
    300       if (memcmp(algorithm.rsaHashedParams()->publicExponent().data(),
    301                  key.algorithm().rsaHashedParams()->publicExponent().data(),
    302                  key.algorithm().rsaHashedParams()->publicExponent().size()) !=
    303           0)
    304         return false;
    305       break;
    306     case blink::WebCryptoKeyAlgorithmParamsTypeNone:
    307     case blink::WebCryptoKeyAlgorithmParamsTypeHmac:
    308       break;
    309     default:
    310       return false;
    311   }
    312 
    313   return true;
    314 }
    315 
    316 Status EncryptDecryptAesKw(EncryptOrDecrypt mode,
    317                            const blink::WebCryptoAlgorithm& algorithm,
    318                            const blink::WebCryptoKey& key,
    319                            const CryptoData& data,
    320                            std::vector<uint8>* buffer) {
    321   platform::SymKey* sym_key;
    322   Status status = ToPlatformSymKey(key, &sym_key);
    323   if (status.IsError())
    324     return status;
    325 
    326   unsigned int min_length = mode == ENCRYPT ? 16 : 24;
    327 
    328   if (data.byte_length() < min_length)
    329     return Status::ErrorDataTooSmall();
    330   if (data.byte_length() % 8)
    331     return Status::ErrorInvalidAesKwDataLength();
    332 
    333   if (status.IsError())
    334     return status;
    335   return platform::EncryptDecryptAesKw(mode, sym_key, data, buffer);
    336 }
    337 
    338 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
    339                                 const blink::WebCryptoKey& key,
    340                                 const CryptoData& data,
    341                                 std::vector<uint8>* buffer) {
    342   if (algorithm.id() != key.algorithm().id())
    343     return Status::ErrorUnexpected();
    344   switch (algorithm.id()) {
    345     case blink::WebCryptoAlgorithmIdAesCbc:
    346       return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer);
    347     case blink::WebCryptoAlgorithmIdAesGcm:
    348       return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer);
    349     case blink::WebCryptoAlgorithmIdRsaOaep:
    350       return DecryptRsaOaep(algorithm, key, data, buffer);
    351     case blink::WebCryptoAlgorithmIdAesKw:
    352       return EncryptDecryptAesKw(DECRYPT, algorithm, key, data, buffer);
    353     default:
    354       return Status::ErrorUnsupported();
    355   }
    356 }
    357 
    358 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
    359                              const blink::WebCryptoKey& key,
    360                              const CryptoData& data,
    361                              std::vector<uint8>* buffer) {
    362   if (algorithm.id() != key.algorithm().id())
    363     return Status::ErrorUnexpected();
    364   switch (algorithm.id()) {
    365     case blink::WebCryptoAlgorithmIdAesCbc:
    366       return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer);
    367     case blink::WebCryptoAlgorithmIdAesGcm:
    368       return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer);
    369     case blink::WebCryptoAlgorithmIdAesKw:
    370       return EncryptDecryptAesKw(ENCRYPT, algorithm, key, data, buffer);
    371     case blink::WebCryptoAlgorithmIdRsaOaep:
    372       return EncryptRsaOaep(algorithm, key, data, buffer);
    373     default:
    374       return Status::ErrorUnsupported();
    375   }
    376 }
    377 
    378 Status UnwrapKeyDecryptAndImport(
    379     blink::WebCryptoKeyFormat format,
    380     const CryptoData& wrapped_key_data,
    381     const blink::WebCryptoKey& wrapping_key,
    382     const blink::WebCryptoAlgorithm& wrapping_algorithm,
    383     const blink::WebCryptoAlgorithm& algorithm,
    384     bool extractable,
    385     blink::WebCryptoKeyUsageMask usage_mask,
    386     blink::WebCryptoKey* key) {
    387   std::vector<uint8> buffer;
    388   Status status = DecryptDontCheckKeyUsage(
    389       wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
    390   if (status.IsError())
    391     return status;
    392   // NOTE that returning the details of ImportKey() failures may leak
    393   // information about the plaintext of the encrypted key (for instance the JWK
    394   // key_ops). As long as the ImportKey error messages don't describe actual
    395   // key bytes however this should be OK. For more discussion see
    396   // http://crubg.com/372040
    397   return ImportKey(
    398       format, CryptoData(buffer), algorithm, extractable, usage_mask, key);
    399 }
    400 
    401 Status WrapKeyExportAndEncrypt(
    402     blink::WebCryptoKeyFormat format,
    403     const blink::WebCryptoKey& key_to_wrap,
    404     const blink::WebCryptoKey& wrapping_key,
    405     const blink::WebCryptoAlgorithm& wrapping_algorithm,
    406     std::vector<uint8>* buffer) {
    407   std::vector<uint8> exported_data;
    408   Status status = ExportKey(format, key_to_wrap, &exported_data);
    409   if (status.IsError())
    410     return status;
    411   return EncryptDontCheckUsage(
    412       wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer);
    413 }
    414 
    415 // Returns the internal block size for SHA-*
    416 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) {
    417   switch (hash_id) {
    418     case blink::WebCryptoAlgorithmIdSha1:
    419     case blink::WebCryptoAlgorithmIdSha256:
    420       return 64;
    421     case blink::WebCryptoAlgorithmIdSha384:
    422     case blink::WebCryptoAlgorithmIdSha512:
    423       return 128;
    424     default:
    425       NOTREACHED();
    426       return 0;
    427   }
    428 }
    429 
    430 // Returns the mask of all key usages that are possible for |algorithm| and
    431 // |key_type|. If the combination of |algorithm| and |key_type| doesn't make
    432 // sense, then returns 0 (no usages).
    433 blink::WebCryptoKeyUsageMask GetValidKeyUsagesForKeyType(
    434     blink::WebCryptoAlgorithmId algorithm,
    435     blink::WebCryptoKeyType key_type) {
    436   if (IsAlgorithmAsymmetric(algorithm) ==
    437       (key_type == blink::WebCryptoKeyTypeSecret))
    438     return 0;
    439 
    440   switch (algorithm) {
    441     case blink::WebCryptoAlgorithmIdAesCbc:
    442     case blink::WebCryptoAlgorithmIdAesGcm:
    443     case blink::WebCryptoAlgorithmIdAesCtr:
    444       return blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
    445              blink::WebCryptoKeyUsageWrapKey |
    446              blink::WebCryptoKeyUsageUnwrapKey;
    447     case blink::WebCryptoAlgorithmIdAesKw:
    448       return blink::WebCryptoKeyUsageWrapKey |
    449              blink::WebCryptoKeyUsageUnwrapKey;
    450     case blink::WebCryptoAlgorithmIdHmac:
    451       return blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
    452     case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
    453       switch (key_type) {
    454         case blink::WebCryptoKeyTypePublic:
    455           return blink::WebCryptoKeyUsageVerify;
    456         case blink::WebCryptoKeyTypePrivate:
    457           return blink::WebCryptoKeyUsageSign;
    458         default:
    459           return 0;
    460       }
    461     case blink::WebCryptoAlgorithmIdRsaOaep:
    462       switch (key_type) {
    463         case blink::WebCryptoKeyTypePublic:
    464           return blink::WebCryptoKeyUsageEncrypt |
    465                  blink::WebCryptoKeyUsageWrapKey;
    466         case blink::WebCryptoKeyTypePrivate:
    467           return blink::WebCryptoKeyUsageDecrypt |
    468                  blink::WebCryptoKeyUsageUnwrapKey;
    469         default:
    470           return 0;
    471       }
    472     default:
    473       return 0;
    474   }
    475 }
    476 
    477 // Returns Status::Success() if |usages| is a valid set of key usages for
    478 // |algorithm| and |key_type|. Otherwise returns an error.
    479 // In the case of JWK format the check is incomplete for asymmetric algorithms.
    480 Status BestEffortCheckKeyUsagesForImport(blink::WebCryptoAlgorithmId algorithm,
    481                                          blink::WebCryptoKeyFormat format,
    482                                          blink::WebCryptoKeyUsageMask usages) {
    483   if (!IsAlgorithmAsymmetric(algorithm))
    484     return CheckKeyUsages(algorithm, blink::WebCryptoKeyTypeSecret, usages);
    485 
    486   // Try to infer the key type given the import format.
    487   blink::WebCryptoKeyType key_type;
    488   bool key_type_known = false;
    489 
    490   switch (format) {
    491     case blink::WebCryptoKeyFormatRaw:
    492       // TODO(eroman): The spec defines Diffie-Hellman raw import for public
    493       // keys, so this will need to be updated in the future when DH is
    494       // implemented.
    495       return Status::ErrorUnexpected();
    496     case blink::WebCryptoKeyFormatSpki:
    497       key_type = blink::WebCryptoKeyTypePublic;
    498       key_type_known = true;
    499       break;
    500     case blink::WebCryptoKeyFormatPkcs8:
    501       key_type = blink::WebCryptoKeyTypePrivate;
    502       key_type_known = true;
    503       break;
    504     case blink::WebCryptoKeyFormatJwk:
    505       key_type_known = false;
    506       break;
    507     default:
    508       return Status::ErrorUnexpected();
    509   }
    510 
    511   if (key_type_known)
    512     return CheckKeyUsages(algorithm, key_type, usages);
    513 
    514   // If the key type is not known, then the algorithm is asymmetric. Whether the
    515   // key data describes a public or private key isn't known yet. But it must at
    516   // least be ONE of those two.
    517   DCHECK(IsAlgorithmAsymmetric(algorithm));
    518 
    519   if (CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePublic, usages)
    520           .IsError() &&
    521       CheckKeyUsages(algorithm, blink::WebCryptoKeyTypePrivate, usages)
    522           .IsError()) {
    523     return Status::ErrorCreateKeyBadUsages();
    524   }
    525 
    526   return Status::Success();
    527 }
    528 
    529 // Returns an error if |combined_usage_mask| is invalid for generating a key
    530 // pair for |algorithm|. Otherwise returns Status::Success(), and fills
    531 // |public_key_usages| with the usages for the public key, and
    532 // |private_key_usages| with those for the private key.
    533 Status CheckKeyUsagesForGenerateKeyPair(
    534     blink::WebCryptoAlgorithmId algorithm,
    535     blink::WebCryptoKeyUsageMask combined_usage_mask,
    536     blink::WebCryptoKeyUsageMask* public_key_usages,
    537     blink::WebCryptoKeyUsageMask* private_key_usages) {
    538   DCHECK(IsAlgorithmAsymmetric(algorithm));
    539 
    540   blink::WebCryptoKeyUsageMask all_public_key_usages =
    541       GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePublic);
    542   blink::WebCryptoKeyUsageMask all_private_key_usages =
    543       GetValidKeyUsagesForKeyType(algorithm, blink::WebCryptoKeyTypePrivate);
    544 
    545   if (!ContainsKeyUsages(all_public_key_usages | all_private_key_usages,
    546                          combined_usage_mask))
    547     return Status::ErrorCreateKeyBadUsages();
    548 
    549   *public_key_usages = combined_usage_mask & all_public_key_usages;
    550   *private_key_usages = combined_usage_mask & all_private_key_usages;
    551 
    552   return Status::Success();
    553 }
    554 
    555 // Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
    556 // to unsigned long.
    557 bool BigIntegerToLong(const uint8* data,
    558                       unsigned int data_size,
    559                       unsigned long* result) {
    560   // TODO(padolph): Is it correct to say that empty data is an error, or does it
    561   // mean value 0? See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23655
    562   if (data_size == 0)
    563     return false;
    564 
    565   *result = 0;
    566   for (size_t i = 0; i < data_size; ++i) {
    567     size_t reverse_i = data_size - i - 1;
    568 
    569     if (reverse_i >= sizeof(unsigned long) && data[i])
    570       return false;  // Too large for a long.
    571 
    572     *result |= data[i] << 8 * reverse_i;
    573   }
    574   return true;
    575 }
    576 
    577 
    578 }  // namespace
    579 
    580 void Init() { platform::Init(); }
    581 
    582 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
    583                const blink::WebCryptoKey& key,
    584                const CryptoData& data,
    585                std::vector<uint8>* buffer) {
    586   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
    587     return Status::ErrorUnexpected();
    588   return EncryptDontCheckUsage(algorithm, key, data, buffer);
    589 }
    590 
    591 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
    592                const blink::WebCryptoKey& key,
    593                const CryptoData& data,
    594                std::vector<uint8>* buffer) {
    595   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
    596     return Status::ErrorUnexpected();
    597   return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
    598 }
    599 
    600 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
    601               const CryptoData& data,
    602               std::vector<uint8>* buffer) {
    603   switch (algorithm.id()) {
    604     case blink::WebCryptoAlgorithmIdSha1:
    605     case blink::WebCryptoAlgorithmIdSha256:
    606     case blink::WebCryptoAlgorithmIdSha384:
    607     case blink::WebCryptoAlgorithmIdSha512:
    608       return platform::DigestSha(algorithm.id(), data, buffer);
    609     default:
    610       return Status::ErrorUnsupported();
    611   }
    612 }
    613 
    614 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
    615     blink::WebCryptoAlgorithmId algorithm) {
    616   return platform::CreateDigestor(algorithm);
    617 }
    618 
    619 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
    620                          bool extractable,
    621                          blink::WebCryptoKeyUsageMask usage_mask,
    622                          blink::WebCryptoKey* key) {
    623   Status status =
    624       CheckKeyUsages(algorithm.id(), blink::WebCryptoKeyTypeSecret, usage_mask);
    625   if (status.IsError())
    626     return status;
    627 
    628   unsigned int keylen_bytes = 0;
    629 
    630   // Get the secret key length in bytes from generation parameters.
    631   // This resolves any defaults.
    632   switch (algorithm.id()) {
    633     case blink::WebCryptoAlgorithmIdAesCbc:
    634     case blink::WebCryptoAlgorithmIdAesGcm:
    635     case blink::WebCryptoAlgorithmIdAesKw: {
    636       if (!IsValidAesKeyLengthBits(algorithm.aesKeyGenParams()->lengthBits())) {
    637         return algorithm.aesKeyGenParams()->lengthBits() == 192
    638                    ? Status::ErrorAes192BitUnsupported()
    639                    : Status::ErrorGenerateKeyLength();
    640       }
    641       keylen_bytes = algorithm.aesKeyGenParams()->lengthBits() / 8;
    642       break;
    643     }
    644     case blink::WebCryptoAlgorithmIdHmac: {
    645       const blink::WebCryptoHmacKeyGenParams* params =
    646           algorithm.hmacKeyGenParams();
    647       DCHECK(params);
    648       if (params->hasLengthBits()) {
    649         if (params->optionalLengthBits() % 8)
    650           return Status::ErrorGenerateKeyLength();
    651         keylen_bytes = params->optionalLengthBits() / 8;
    652       } else {
    653         keylen_bytes = ShaBlockSizeBytes(params->hash().id());
    654         if (keylen_bytes == 0)
    655           return Status::ErrorUnsupported();
    656       }
    657       break;
    658     }
    659 
    660     default:
    661       return Status::ErrorUnsupported();
    662   }
    663 
    664   // TODO(eroman): Is this correct? HMAC can import zero-length keys, so should
    665   //               probably be able to allowed to generate them too.
    666   if (keylen_bytes == 0)
    667     return Status::ErrorGenerateKeyLength();
    668 
    669   return platform::GenerateSecretKey(
    670       algorithm, extractable, usage_mask, keylen_bytes, key);
    671 }
    672 
    673 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
    674                        bool extractable,
    675                        blink::WebCryptoKeyUsageMask combined_usage_mask,
    676                        blink::WebCryptoKey* public_key,
    677                        blink::WebCryptoKey* private_key) {
    678   blink::WebCryptoKeyUsageMask public_key_usage_mask = 0;
    679   blink::WebCryptoKeyUsageMask private_key_usage_mask = 0;
    680 
    681   Status status = CheckKeyUsagesForGenerateKeyPair(algorithm.id(),
    682                                                    combined_usage_mask,
    683                                                    &public_key_usage_mask,
    684                                                    &private_key_usage_mask);
    685   if (status.IsError())
    686     return status;
    687 
    688   // TODO(padolph): Handle other asymmetric algorithm key generation.
    689   switch (algorithm.paramsType()) {
    690     case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: {
    691       const blink::WebCryptoRsaHashedKeyGenParams* params =
    692           algorithm.rsaHashedKeyGenParams();
    693 
    694       if (!params->modulusLengthBits())
    695         return Status::ErrorGenerateRsaZeroModulus();
    696 
    697       unsigned long public_exponent = 0;
    698       if (!BigIntegerToLong(params->publicExponent().data(),
    699                             params->publicExponent().size(),
    700                             &public_exponent) ||
    701           (public_exponent != 3 && public_exponent != 65537)) {
    702         return Status::ErrorGenerateKeyPublicExponent();
    703       }
    704 
    705       return platform::GenerateRsaKeyPair(algorithm,
    706                                           extractable,
    707                                           public_key_usage_mask,
    708                                           private_key_usage_mask,
    709                                           params->modulusLengthBits(),
    710                                           public_exponent,
    711                                           public_key,
    712                                           private_key);
    713     }
    714     default:
    715       return Status::ErrorUnsupported();
    716   }
    717 }
    718 
    719 // Note that this function may be called from the target Blink thread.
    720 Status ImportKey(blink::WebCryptoKeyFormat format,
    721                  const CryptoData& key_data,
    722                  const blink::WebCryptoAlgorithm& algorithm,
    723                  bool extractable,
    724                  blink::WebCryptoKeyUsageMask usage_mask,
    725                  blink::WebCryptoKey* key) {
    726   // This is "best effort" because it is incomplete for JWK (for which the key
    727   // type is not yet known). ImportKeyJwk() does extra checks on key usage once
    728   // the key type has been determined.
    729   Status status =
    730       BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask);
    731   if (status.IsError())
    732     return status;
    733 
    734   switch (format) {
    735     case blink::WebCryptoKeyFormatRaw:
    736       return ImportKeyRaw(key_data, algorithm, extractable, usage_mask, key);
    737     case blink::WebCryptoKeyFormatSpki:
    738       return platform::ImportKeySpki(
    739           algorithm, key_data, extractable, usage_mask, key);
    740     case blink::WebCryptoKeyFormatPkcs8:
    741       return platform::ImportKeyPkcs8(
    742           algorithm, key_data, extractable, usage_mask, key);
    743     case blink::WebCryptoKeyFormatJwk:
    744       return ImportKeyJwk(key_data, algorithm, extractable, usage_mask, key);
    745     default:
    746       return Status::ErrorUnsupported();
    747   }
    748 }
    749 
    750 // TODO(eroman): Move this to anonymous namespace.
    751 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,
    752                                         const blink::WebCryptoKey& key,
    753                                         std::vector<uint8>* buffer) {
    754   switch (format) {
    755     case blink::WebCryptoKeyFormatRaw: {
    756       platform::SymKey* sym_key;
    757       Status status = ToPlatformSymKey(key, &sym_key);
    758       if (status.IsError())
    759         return status;
    760       return platform::ExportKeyRaw(sym_key, buffer);
    761     }
    762     case blink::WebCryptoKeyFormatSpki: {
    763       platform::PublicKey* public_key;
    764       Status status = ToPlatformPublicKey(key, &public_key);
    765       if (status.IsError())
    766         return status;
    767       return platform::ExportKeySpki(public_key, buffer);
    768     }
    769     case blink::WebCryptoKeyFormatPkcs8: {
    770       platform::PrivateKey* private_key;
    771       Status status = ToPlatformPrivateKey(key, &private_key);
    772       if (status.IsError())
    773         return status;
    774       return platform::ExportKeyPkcs8(private_key, key.algorithm(), buffer);
    775     }
    776     case blink::WebCryptoKeyFormatJwk:
    777       return ExportKeyJwk(key, buffer);
    778     default:
    779       return Status::ErrorUnsupported();
    780   }
    781 }
    782 
    783 Status ExportKey(blink::WebCryptoKeyFormat format,
    784                  const blink::WebCryptoKey& key,
    785                  std::vector<uint8>* buffer) {
    786   if (!key.extractable())
    787     return Status::ErrorKeyNotExtractable();
    788   return ExportKeyDontCheckExtractability(format, key, buffer);
    789 }
    790 
    791 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
    792             const blink::WebCryptoKey& key,
    793             const CryptoData& data,
    794             std::vector<uint8>* buffer) {
    795   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
    796     return Status::ErrorUnexpected();
    797   if (algorithm.id() != key.algorithm().id())
    798     return Status::ErrorUnexpected();
    799 
    800   switch (algorithm.id()) {
    801     case blink::WebCryptoAlgorithmIdHmac:
    802       return SignHmac(algorithm, key, data, buffer);
    803     case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
    804       return SignRsaSsaPkcs1v1_5(algorithm, key, data, buffer);
    805     default:
    806       return Status::ErrorUnsupported();
    807   }
    808 }
    809 
    810 Status VerifySignature(const blink::WebCryptoAlgorithm& algorithm,
    811                        const blink::WebCryptoKey& key,
    812                        const CryptoData& signature,
    813                        const CryptoData& data,
    814                        bool* signature_match) {
    815   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify))
    816     return Status::ErrorUnexpected();
    817   if (algorithm.id() != key.algorithm().id())
    818     return Status::ErrorUnexpected();
    819 
    820   if (!signature.byte_length()) {
    821     // None of the algorithms generate valid zero-length signatures so this
    822     // will necessarily fail verification. Early return to protect
    823     // implementations from dealing with a NULL signature pointer.
    824     *signature_match = false;
    825     return Status::Success();
    826   }
    827 
    828   switch (algorithm.id()) {
    829     case blink::WebCryptoAlgorithmIdHmac:
    830       return VerifyHmac(algorithm, key, signature, data, signature_match);
    831     case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
    832       return VerifyRsaSsaPkcs1v1_5(
    833           algorithm, key, signature, data, signature_match);
    834     default:
    835       return Status::ErrorUnsupported();
    836   }
    837 }
    838 
    839 Status WrapKey(blink::WebCryptoKeyFormat format,
    840                const blink::WebCryptoKey& key_to_wrap,
    841                const blink::WebCryptoKey& wrapping_key,
    842                const blink::WebCryptoAlgorithm& wrapping_algorithm,
    843                std::vector<uint8>* buffer) {
    844   if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey))
    845     return Status::ErrorUnexpected();
    846   if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
    847     return Status::ErrorUnexpected();
    848 
    849   return WrapKeyExportAndEncrypt(
    850       format, key_to_wrap, wrapping_key, wrapping_algorithm, buffer);
    851 }
    852 
    853 Status UnwrapKey(blink::WebCryptoKeyFormat format,
    854                  const CryptoData& wrapped_key_data,
    855                  const blink::WebCryptoKey& wrapping_key,
    856                  const blink::WebCryptoAlgorithm& wrapping_algorithm,
    857                  const blink::WebCryptoAlgorithm& algorithm,
    858                  bool extractable,
    859                  blink::WebCryptoKeyUsageMask usage_mask,
    860                  blink::WebCryptoKey* key) {
    861   if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
    862     return Status::ErrorUnexpected();
    863   if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
    864     return Status::ErrorUnexpected();
    865 
    866   // Fail-fast if the key usages don't make sense. This avoids decrypting the
    867   // key only to then have import fail. It is "best effort" because when
    868   // unwrapping JWK for asymmetric algorithms the key type isn't known yet.
    869   Status status =
    870       BestEffortCheckKeyUsagesForImport(algorithm.id(), format, usage_mask);
    871   if (status.IsError())
    872     return status;
    873 
    874   return UnwrapKeyDecryptAndImport(format,
    875                                    wrapped_key_data,
    876                                    wrapping_key,
    877                                    wrapping_algorithm,
    878                                    algorithm,
    879                                    extractable,
    880                                    usage_mask,
    881                                    key);
    882 }
    883 
    884 // Note that this function is called from the target Blink thread.
    885 bool SerializeKeyForClone(const blink::WebCryptoKey& key,
    886                           blink::WebVector<uint8>* key_data) {
    887   return static_cast<webcrypto::platform::Key*>(key.handle())
    888       ->ThreadSafeSerializeForClone(key_data);
    889 }
    890 
    891 // Note that this function is called from the target Blink thread.
    892 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm& algorithm,
    893                             blink::WebCryptoKeyType type,
    894                             bool extractable,
    895                             blink::WebCryptoKeyUsageMask usage_mask,
    896                             const CryptoData& key_data,
    897                             blink::WebCryptoKey* key) {
    898   // TODO(eroman): This should not call into the platform crypto layer.
    899   // Otherwise it runs the risk of stalling while the NSS/OpenSSL global locks
    900   // are held.
    901   //
    902   // An alternate approach is to defer the key import until the key is used.
    903   // However this means that any deserialization errors would have to be
    904   // surfaced as WebCrypto errors, leading to slightly different behaviors. For
    905   // instance you could clone a key which fails to be deserialized.
    906   Status status = ImportKey(GetCloneFormatForKeyType(type),
    907                             key_data,
    908                             KeyAlgorithmToImportAlgorithm(algorithm),
    909                             extractable,
    910                             usage_mask,
    911                             key);
    912   if (status.IsError())
    913     return false;
    914   return ValidateDeserializedKey(*key, algorithm, type);
    915 }
    916 
    917 Status ToPlatformSymKey(const blink::WebCryptoKey& key,
    918                         platform::SymKey** out) {
    919   *out = static_cast<platform::Key*>(key.handle())->AsSymKey();
    920   if (!*out)
    921     return Status::ErrorUnexpectedKeyType();
    922   return Status::Success();
    923 }
    924 
    925 Status ToPlatformPublicKey(const blink::WebCryptoKey& key,
    926                            platform::PublicKey** out) {
    927   *out = static_cast<platform::Key*>(key.handle())->AsPublicKey();
    928   if (!*out)
    929     return Status::ErrorUnexpectedKeyType();
    930   return Status::Success();
    931 }
    932 
    933 Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
    934                             platform::PrivateKey** out) {
    935   *out = static_cast<platform::Key*>(key.handle())->AsPrivateKey();
    936   if (!*out)
    937     return Status::ErrorUnexpectedKeyType();
    938   return Status::Success();
    939 }
    940 
    941 // Returns Status::Success() if |usages| is a valid set of key usages for
    942 // |algorithm| and |key_type|. Otherwise returns an error.
    943 Status CheckKeyUsages(blink::WebCryptoAlgorithmId algorithm,
    944                       blink::WebCryptoKeyType key_type,
    945                       blink::WebCryptoKeyUsageMask usages) {
    946   if (!ContainsKeyUsages(GetValidKeyUsagesForKeyType(algorithm, key_type),
    947                          usages))
    948     return Status::ErrorCreateKeyBadUsages();
    949 
    950   return Status::Success();
    951 }
    952 
    953 }  // namespace webcrypto
    954 
    955 }  // namespace content
    956