Home | History | Annotate | Download | only in webcrypto
      1 // Copyright (c) 2013 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/renderer/webcrypto/webcrypto_impl.h"
      6 
      7 #include <algorithm>
      8 #include <functional>
      9 #include <map>
     10 #include "base/json/json_reader.h"
     11 #include "base/lazy_instance.h"
     12 #include "base/logging.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/strings/string_piece.h"
     15 #include "base/values.h"
     16 #include "content/renderer/webcrypto/webcrypto_util.h"
     17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
     18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
     19 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
     20 
     21 namespace content {
     22 
     23 namespace {
     24 
     25 bool IsAlgorithmAsymmetric(const blink::WebCryptoAlgorithm& algorithm) {
     26   // TODO(padolph): include all other asymmetric algorithms once they are
     27   // defined, e.g. EC and DH.
     28   return (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
     29           algorithm.id() == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
     30           algorithm.id() == blink::WebCryptoAlgorithmIdRsaOaep);
     31 }
     32 
     33 // Binds a specific key length value to a compatible factory function.
     34 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithOneShortArg)(
     35     unsigned short);
     36 template <AlgFactoryFuncWithOneShortArg func, unsigned short key_length>
     37 blink::WebCryptoAlgorithm BindAlgFactoryWithKeyLen() {
     38   return func(key_length);
     39 }
     40 
     41 // Binds a WebCryptoAlgorithmId value to a compatible factory function.
     42 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncWithWebCryptoAlgIdArg)(
     43     blink::WebCryptoAlgorithmId);
     44 template <AlgFactoryFuncWithWebCryptoAlgIdArg func,
     45           blink::WebCryptoAlgorithmId algorithm_id>
     46 blink::WebCryptoAlgorithm BindAlgFactoryAlgorithmId() {
     47   return func(algorithm_id);
     48 }
     49 
     50 // Defines a map between a JWK 'alg' string ID and a corresponding Web Crypto
     51 // factory function.
     52 typedef blink::WebCryptoAlgorithm (*AlgFactoryFuncNoArgs)();
     53 typedef std::map<std::string, AlgFactoryFuncNoArgs> JwkAlgFactoryMap;
     54 
     55 class JwkAlgorithmFactoryMap {
     56  public:
     57   JwkAlgorithmFactoryMap() {
     58     map_["HS256"] =
     59         &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen,
     60                                   256>;
     61     map_["HS384"] =
     62         &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen,
     63                                   384>;
     64     map_["HS512"] =
     65         &BindAlgFactoryWithKeyLen<webcrypto::CreateHmacAlgorithmByHashOutputLen,
     66                                   512>;
     67     map_["RS256"] =
     68         &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
     69                                    blink::WebCryptoAlgorithmIdSha256>;
     70     map_["RS384"] =
     71         &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
     72                                    blink::WebCryptoAlgorithmIdSha384>;
     73     map_["RS512"] =
     74         &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaSsaAlgorithm,
     75                                    blink::WebCryptoAlgorithmIdSha512>;
     76     map_["RSA1_5"] =
     77         &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
     78                                    blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>;
     79     map_["RSA-OAEP"] =
     80         &BindAlgFactoryAlgorithmId<webcrypto::CreateRsaOaepAlgorithm,
     81                                    blink::WebCryptoAlgorithmIdSha1>;
     82     // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet
     83     map_["A128KW"] = &blink::WebCryptoAlgorithm::createNull;
     84     // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet
     85     map_["A256KW"] = &blink::WebCryptoAlgorithm::createNull;
     86     map_["A128GCM"] =
     87         &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
     88                                    blink::WebCryptoAlgorithmIdAesGcm>;
     89     map_["A256GCM"] =
     90         &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
     91                                    blink::WebCryptoAlgorithmIdAesGcm>;
     92     map_["A128CBC"] =
     93         &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
     94                                    blink::WebCryptoAlgorithmIdAesCbc>;
     95     map_["A192CBC"] =
     96         &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
     97                                    blink::WebCryptoAlgorithmIdAesCbc>;
     98     map_["A256CBC"] =
     99         &BindAlgFactoryAlgorithmId<webcrypto::CreateAlgorithm,
    100                                    blink::WebCryptoAlgorithmIdAesCbc>;
    101   }
    102 
    103   blink::WebCryptoAlgorithm CreateAlgorithmFromName(const std::string& alg_id)
    104       const {
    105     const JwkAlgFactoryMap::const_iterator pos = map_.find(alg_id);
    106     if (pos == map_.end())
    107       return blink::WebCryptoAlgorithm::createNull();
    108     return pos->second();
    109   }
    110 
    111  private:
    112   JwkAlgFactoryMap map_;
    113 };
    114 
    115 base::LazyInstance<JwkAlgorithmFactoryMap> jwk_alg_factory =
    116     LAZY_INSTANCE_INITIALIZER;
    117 
    118 bool WebCryptoAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1,
    119                                    const blink::WebCryptoAlgorithm& alg2) {
    120   DCHECK(!alg1.isNull());
    121   DCHECK(!alg2.isNull());
    122   if (alg1.id() != alg2.id())
    123     return false;
    124   switch (alg1.id()) {
    125     case blink::WebCryptoAlgorithmIdHmac:
    126     case blink::WebCryptoAlgorithmIdRsaOaep:
    127     case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
    128       if (WebCryptoAlgorithmsConsistent(
    129               webcrypto::GetInnerHashAlgorithm(alg1),
    130               webcrypto::GetInnerHashAlgorithm(alg2))) {
    131         return true;
    132       }
    133       break;
    134     case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
    135     case blink::WebCryptoAlgorithmIdSha1:
    136     case blink::WebCryptoAlgorithmIdSha224:
    137     case blink::WebCryptoAlgorithmIdSha256:
    138     case blink::WebCryptoAlgorithmIdSha384:
    139     case blink::WebCryptoAlgorithmIdSha512:
    140     case blink::WebCryptoAlgorithmIdAesCbc:
    141     case blink::WebCryptoAlgorithmIdAesGcm:
    142     case blink::WebCryptoAlgorithmIdAesCtr:
    143       return true;
    144     default:
    145       NOTREACHED();  // Not a supported algorithm.
    146       break;
    147   }
    148   return false;
    149 }
    150 
    151 bool GetDecodedUrl64ValueByKey(
    152     const base::DictionaryValue& dict,
    153     const std::string& key,
    154     std::string* decoded) {
    155   std::string value_url64;
    156   if (!dict.GetString(key, &value_url64) ||
    157       !webcrypto::Base64DecodeUrlSafe(value_url64, decoded) ||
    158       !decoded->size()) {
    159     return false;
    160   }
    161   return true;
    162 }
    163 
    164 }  // namespace
    165 
    166 WebCryptoImpl::WebCryptoImpl() {
    167   Init();
    168 }
    169 
    170 void WebCryptoImpl::encrypt(
    171     const blink::WebCryptoAlgorithm& algorithm,
    172     const blink::WebCryptoKey& key,
    173     const unsigned char* data,
    174     unsigned data_size,
    175     blink::WebCryptoResult result) {
    176   DCHECK(!algorithm.isNull());
    177   blink::WebArrayBuffer buffer;
    178   if (!EncryptInternal(algorithm, key, data, data_size, &buffer)) {
    179     result.completeWithError();
    180   } else {
    181     result.completeWithBuffer(buffer);
    182   }
    183 }
    184 
    185 void WebCryptoImpl::decrypt(
    186     const blink::WebCryptoAlgorithm& algorithm,
    187     const blink::WebCryptoKey& key,
    188     const unsigned char* data,
    189     unsigned data_size,
    190     blink::WebCryptoResult result) {
    191   DCHECK(!algorithm.isNull());
    192   blink::WebArrayBuffer buffer;
    193   if (!DecryptInternal(algorithm, key, data, data_size, &buffer)) {
    194     result.completeWithError();
    195   } else {
    196     result.completeWithBuffer(buffer);
    197   }
    198 }
    199 
    200 void WebCryptoImpl::digest(
    201     const blink::WebCryptoAlgorithm& algorithm,
    202     const unsigned char* data,
    203     unsigned data_size,
    204     blink::WebCryptoResult result) {
    205   DCHECK(!algorithm.isNull());
    206   blink::WebArrayBuffer buffer;
    207   if (!DigestInternal(algorithm, data, data_size, &buffer)) {
    208     result.completeWithError();
    209   } else {
    210     result.completeWithBuffer(buffer);
    211   }
    212 }
    213 
    214 void WebCryptoImpl::generateKey(
    215     const blink::WebCryptoAlgorithm& algorithm,
    216     bool extractable,
    217     blink::WebCryptoKeyUsageMask usage_mask,
    218     blink::WebCryptoResult result) {
    219   DCHECK(!algorithm.isNull());
    220   if (IsAlgorithmAsymmetric(algorithm)) {
    221     blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
    222     blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
    223     if (!GenerateKeyPairInternal(
    224              algorithm, extractable, usage_mask, &public_key, &private_key)) {
    225       result.completeWithError();
    226     } else {
    227       DCHECK(public_key.handle());
    228       DCHECK(private_key.handle());
    229       DCHECK_EQ(algorithm.id(), public_key.algorithm().id());
    230       DCHECK_EQ(algorithm.id(), private_key.algorithm().id());
    231       DCHECK_EQ(true, public_key.extractable());
    232       DCHECK_EQ(extractable, private_key.extractable());
    233       DCHECK_EQ(usage_mask, public_key.usages());
    234       DCHECK_EQ(usage_mask, private_key.usages());
    235       result.completeWithKeyPair(public_key, private_key);
    236     }
    237   } else {
    238     blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
    239     if (!GenerateKeyInternal(algorithm, extractable, usage_mask, &key)) {
    240       result.completeWithError();
    241     } else {
    242       DCHECK(key.handle());
    243       DCHECK_EQ(algorithm.id(), key.algorithm().id());
    244       DCHECK_EQ(extractable, key.extractable());
    245       DCHECK_EQ(usage_mask, key.usages());
    246       result.completeWithKey(key);
    247     }
    248   }
    249 }
    250 
    251 void WebCryptoImpl::importKey(
    252     blink::WebCryptoKeyFormat format,
    253     const unsigned char* key_data,
    254     unsigned key_data_size,
    255     const blink::WebCryptoAlgorithm& algorithm_or_null,
    256     bool extractable,
    257     blink::WebCryptoKeyUsageMask usage_mask,
    258     blink::WebCryptoResult result) {
    259   blink::WebCryptoKey key = blink::WebCryptoKey::createNull();
    260   if (format == blink::WebCryptoKeyFormatJwk) {
    261     if (!ImportKeyJwk(key_data,
    262                       key_data_size,
    263                       algorithm_or_null,
    264                       extractable,
    265                       usage_mask,
    266                       &key)) {
    267       result.completeWithError();
    268       return;
    269     }
    270   } else {
    271     if (!ImportKeyInternal(format,
    272                            key_data,
    273                            key_data_size,
    274                            algorithm_or_null,
    275                            extractable,
    276                            usage_mask,
    277                            &key)) {
    278       result.completeWithError();
    279       return;
    280     }
    281   }
    282   DCHECK(key.handle());
    283   DCHECK(!key.algorithm().isNull());
    284   DCHECK_EQ(extractable, key.extractable());
    285   result.completeWithKey(key);
    286 }
    287 
    288 void WebCryptoImpl::exportKey(
    289     blink::WebCryptoKeyFormat format,
    290     const blink::WebCryptoKey& key,
    291     blink::WebCryptoResult result) {
    292   blink::WebArrayBuffer buffer;
    293   if (!ExportKeyInternal(format, key, &buffer)) {
    294     result.completeWithError();
    295     return;
    296   }
    297   result.completeWithBuffer(buffer);
    298 }
    299 
    300 void WebCryptoImpl::sign(
    301     const blink::WebCryptoAlgorithm& algorithm,
    302     const blink::WebCryptoKey& key,
    303     const unsigned char* data,
    304     unsigned data_size,
    305     blink::WebCryptoResult result) {
    306   DCHECK(!algorithm.isNull());
    307   blink::WebArrayBuffer buffer;
    308   if (!SignInternal(algorithm, key, data, data_size, &buffer)) {
    309     result.completeWithError();
    310   } else {
    311     result.completeWithBuffer(buffer);
    312   }
    313 }
    314 
    315 void WebCryptoImpl::verifySignature(
    316     const blink::WebCryptoAlgorithm& algorithm,
    317     const blink::WebCryptoKey& key,
    318     const unsigned char* signature,
    319     unsigned signature_size,
    320     const unsigned char* data,
    321     unsigned data_size,
    322     blink::WebCryptoResult result) {
    323   DCHECK(!algorithm.isNull());
    324   bool signature_match = false;
    325   if (!VerifySignatureInternal(algorithm,
    326                                key,
    327                                signature,
    328                                signature_size,
    329                                data,
    330                                data_size,
    331                                &signature_match)) {
    332     result.completeWithError();
    333   } else {
    334     result.completeWithBoolean(signature_match);
    335   }
    336 }
    337 
    338 bool WebCryptoImpl::ImportKeyJwk(
    339     const unsigned char* key_data,
    340     unsigned key_data_size,
    341     const blink::WebCryptoAlgorithm& algorithm_or_null,
    342     bool extractable,
    343     blink::WebCryptoKeyUsageMask usage_mask,
    344     blink::WebCryptoKey* key) {
    345 
    346   // The goal of this method is to extract key material and meta data from the
    347   // incoming JWK, combine them with the input parameters, and ultimately import
    348   // a Web Crypto Key.
    349   //
    350   // JSON Web Key Format (JWK)
    351   // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16
    352   // TODO(padolph): Not all possible values are handled by this code right now
    353   //
    354   // A JWK is a simple JSON dictionary with the following entries
    355   // - "kty" (Key Type) Parameter, REQUIRED
    356   // - <kty-specific parameters, see below>, REQUIRED
    357   // - "use" (Key Use) Parameter, OPTIONAL
    358   // - "alg" (Algorithm) Parameter, OPTIONAL
    359   // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE,
    360   //   see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796]
    361   // (all other entries are ignored)
    362   //
    363   // OPTIONAL here means that this code does not require the entry to be present
    364   // in the incoming JWK, because the method input parameters contain similar
    365   // information. If the optional JWK entry is present, it will be validated
    366   // against the corresponding input parameter for consistency and combined with
    367   // it according to rules defined below. A special case is that the method
    368   // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg'
    369   // value (if present) is used as a fallback.
    370   //
    371   // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
    372   // values are parsed out and combined with the method input parameters to
    373   // build a Web Crypto Key:
    374   // Web Crypto Key type            <-- (deduced)
    375   // Web Crypto Key extractable     <-- JWK extractable + input extractable
    376   // Web Crypto Key algorithm       <-- JWK alg + input algorithm
    377   // Web Crypto Key keyUsage        <-- JWK use + input usage_mask
    378   // Web Crypto Key keying material <-- kty-specific parameters
    379   //
    380   // Values for each JWK entry are case-sensitive and defined in
    381   // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16.
    382   // Note that not all values specified by JOSE are handled by this code. Only
    383   // handled values are listed.
    384   // - kty (Key Type)
    385   //   +-------+--------------------------------------------------------------+
    386   //   | "RSA" | RSA [RFC3447]                                                |
    387   //   | "oct" | Octet sequence (used to represent symmetric keys)            |
    388   //   +-------+--------------------------------------------------------------+
    389   // - use (Key Use)
    390   //   +-------+--------------------------------------------------------------+
    391   //   | "enc" | encrypt and decrypt operations                               |
    392   //   | "sig" | sign and verify (MAC) operations                             |
    393   //   | "wrap"| key wrap and unwrap [not yet part of JOSE]                   |
    394   //   +-------+--------------------------------------------------------------+
    395   // - extractable (Key Exportability)
    396   //   +-------+--------------------------------------------------------------+
    397   //   | true  | Key may be exported from the trusted environment             |
    398   //   | false | Key cannot exit the trusted environment                      |
    399   //   +-------+--------------------------------------------------------------+
    400   // - alg (Algorithm)
    401   //   See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16
    402   //   +--------------+-------------------------------------------------------+
    403   //   | Digital Signature or MAC Algorithm                                   |
    404   //   +--------------+-------------------------------------------------------+
    405   //   | "HS256"      | HMAC using SHA-256 hash algorithm                     |
    406   //   | "HS384"      | HMAC using SHA-384 hash algorithm                     |
    407   //   | "HS512"      | HMAC using SHA-512 hash algorithm                     |
    408   //   | "RS256"      | RSASSA using SHA-256 hash algorithm                   |
    409   //   | "RS384"      | RSASSA using SHA-384 hash algorithm                   |
    410   //   | "RS512"      | RSASSA using SHA-512 hash algorithm                   |
    411   //   +--------------+-------------------------------------------------------|
    412   //   | Key Management Algorithm                                             |
    413   //   +--------------+-------------------------------------------------------+
    414   //   | "RSA1_5"     | RSAES-PKCS1-V1_5 [RFC3447]                            |
    415   //   | "RSA-OAEP"   | RSAES using Optimal Asymmetric Encryption Padding     |
    416   //   |              | (OAEP) [RFC3447], with the default parameters         |
    417   //   |              | specified by RFC3447 in Section A.2.1                 |
    418   //   | "A128KW"     | Advanced Encryption Standard (AES) Key Wrap Algorithm |
    419   //   |              | [RFC3394] using 128 bit keys                          |
    420   //   | "A256KW"     | AES Key Wrap Algorithm using 256 bit keys             |
    421   //   | "A128GCM"    | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
    422   //   |              | 128 bit keys                                          |
    423   //   | "A256GCM"    | AES GCM using 256 bit keys                            |
    424   //   | "A128CBC"    | AES in Cipher Block Chaining Mode (CBC) with PKCS #5  |
    425   //   |              | padding [NIST.800-38A] [not yet part of JOSE, see     |
    426   //   |              | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796  |
    427   //   | "A192CBC"    | AES CBC using 192 bit keys [not yet part of JOSE]     |
    428   //   | "A256CBC"    | AES CBC using 256 bit keys [not yet part of JOSE]     |
    429   //   +--------------+-------------------------------------------------------+
    430   //
    431   // kty-specific parameters
    432   // The value of kty determines the type and content of the keying material
    433   // carried in the JWK to be imported. Currently only two possibilities are
    434   // supported: a raw key or an RSA public key. RSA private keys are not
    435   // supported because typical applications seldom need to import a private key,
    436   // and the large number of JWK parameters required to describe one.
    437   // - kty == "oct" (symmetric or other raw key)
    438   //   +-------+--------------------------------------------------------------+
    439   //   | "k"   | Contains the value of the symmetric (or other single-valued) |
    440   //   |       | key.  It is represented as the base64url encoding of the     |
    441   //   |       | octet sequence containing the key value.                     |
    442   //   +-------+--------------------------------------------------------------+
    443   // - kty == "RSA" (RSA public key)
    444   //   +-------+--------------------------------------------------------------+
    445   //   | "n"   | Contains the modulus value for the RSA public key.  It is    |
    446   //   |       | represented as the base64url encoding of the value's         |
    447   //   |       | unsigned big endian representation as an octet sequence.     |
    448   //   +-------+--------------------------------------------------------------+
    449   //   | "e"   | Contains the exponent value for the RSA public key.  It is   |
    450   //   |       | represented as the base64url encoding of the value's         |
    451   //   |       | unsigned big endian representation as an octet sequence.     |
    452   //   +-------+--------------------------------------------------------------+
    453   //
    454   // Consistency and conflict resolution
    455   // The 'algorithm_or_null', 'extractable', and 'usage_mask' input parameters
    456   // may be different than the corresponding values inside the JWK. The Web
    457   // Crypto spec says that if a JWK value is present but is inconsistent with
    458   // the input value, it is an error and the operation must fail. If no
    459   // inconsistency is found, the input and JWK values are combined as follows:
    460   //
    461   // algorithm
    462   //   If an algorithm is provided by both the input parameter and the JWK,
    463   //   consistency between the two is based only on algorithm ID's (including an
    464   //   inner hash algorithm if present). In this case if the consistency
    465   //   check is passed, the input algorithm is used. If only one of either the
    466   //   input algorithm and JWK alg is provided, it is used as the final
    467   //   algorithm.
    468   //
    469   // extractable
    470   //   If the JWK extractable is true but the input parameter is false, make the
    471   //   Web Crypto Key non-extractable. Conversely, if the JWK extractable is
    472   //   false but the input parameter is true, it is an inconsistency. If both
    473   //   are true or both are false, use that value.
    474   //
    475   // usage_mask
    476   //   The input usage_mask must be a strict subset of the interpreted JWK use
    477   //   value, else it is judged inconsistent. In all cases the input usage_mask
    478   //   is used as the final usage_mask.
    479   //
    480 
    481   if (!key_data_size)
    482     return false;
    483   DCHECK(key);
    484 
    485   // Parse the incoming JWK JSON.
    486   base::StringPiece json_string(reinterpret_cast<const char*>(key_data),
    487                                 key_data_size);
    488   scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
    489   // Note, bare pointer dict_value is ok since it points into scoped value.
    490   base::DictionaryValue* dict_value = NULL;
    491   if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
    492     return false;
    493 
    494   // JWK "kty". Exit early if this required JWK parameter is missing.
    495   std::string jwk_kty_value;
    496   if (!dict_value->GetString("kty", &jwk_kty_value))
    497     return false;
    498 
    499   // JWK "extractable" (optional) --> extractable parameter
    500   {
    501     bool jwk_extractable_value;
    502     if (dict_value->GetBoolean("extractable", &jwk_extractable_value)) {
    503       if (!jwk_extractable_value && extractable)
    504         return false;
    505       extractable = extractable && jwk_extractable_value;
    506     }
    507   }
    508 
    509   // JWK "alg" (optional) --> algorithm parameter
    510   // Note: input algorithm is also optional, so we have six cases to handle.
    511   // 1. JWK alg present but unrecognized: error
    512   // 2. JWK alg valid AND input algorithm isNull: use JWK value
    513   // 3. JWK alg valid AND input algorithm specified, but JWK value
    514   //      inconsistent with input: error
    515   // 4. JWK alg valid AND input algorithm specified, both consistent: use
    516   //      input value (because it has potentially more details)
    517   // 5. JWK alg missing AND input algorithm isNull: error
    518   // 6. JWK alg missing AND input algorithm specified: use input value
    519   blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull();
    520   std::string jwk_alg_value;
    521   if (dict_value->GetString("alg", &jwk_alg_value)) {
    522     // JWK alg present
    523 
    524     // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can
    525     // only be from the RSA family.
    526 
    527     const blink::WebCryptoAlgorithm jwk_algorithm =
    528         jwk_alg_factory.Get().CreateAlgorithmFromName(jwk_alg_value);
    529     if (jwk_algorithm.isNull()) {
    530       // JWK alg unrecognized
    531       return false;  // case 1
    532     }
    533     // JWK alg valid
    534     if (algorithm_or_null.isNull()) {
    535       // input algorithm not specified
    536       algorithm = jwk_algorithm;  // case 2
    537     } else {
    538       // input algorithm specified
    539       if (!WebCryptoAlgorithmsConsistent(jwk_algorithm, algorithm_or_null))
    540         return false;  // case 3
    541       algorithm = algorithm_or_null;  // case 4
    542     }
    543   } else {
    544     // JWK alg missing
    545     if (algorithm_or_null.isNull())
    546       return false;  // case 5
    547     algorithm = algorithm_or_null;  // case 6
    548   }
    549   DCHECK(!algorithm.isNull());
    550 
    551   // JWK "use" (optional) --> usage_mask parameter
    552   std::string jwk_use_value;
    553   if (dict_value->GetString("use", &jwk_use_value)) {
    554     blink::WebCryptoKeyUsageMask jwk_usage_mask = 0;
    555     if (jwk_use_value == "enc") {
    556       jwk_usage_mask =
    557           blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt;
    558     } else if (jwk_use_value == "sig") {
    559       jwk_usage_mask =
    560           blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
    561     } else if (jwk_use_value == "wrap") {
    562       jwk_usage_mask =
    563           blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey;
    564     } else {
    565       return false;
    566     }
    567     if ((jwk_usage_mask & usage_mask) != usage_mask) {
    568       // A usage_mask must be a subset of jwk_usage_mask.
    569       return false;
    570     }
    571   }
    572 
    573   // JWK keying material --> ImportKeyInternal()
    574   if (jwk_kty_value == "oct") {
    575 
    576     std::string jwk_k_value;
    577     if (!GetDecodedUrl64ValueByKey(*dict_value, "k", &jwk_k_value))
    578       return false;
    579 
    580     // TODO(padolph): Some JWK alg ID's embed information about the key length
    581     // in the alg ID string. For example "A128" implies the JWK carries 128 bits
    582     // of key material, and "HS512" implies the JWK carries _at least_ 512 bits
    583     // of key material. For such keys validate the actual key length against the
    584     // value in the ID.
    585 
    586     return ImportKeyInternal(blink::WebCryptoKeyFormatRaw,
    587                              reinterpret_cast<const uint8*>(jwk_k_value.data()),
    588                              jwk_k_value.size(),
    589                              algorithm,
    590                              extractable,
    591                              usage_mask,
    592                              key);
    593   } else if (jwk_kty_value == "RSA") {
    594 
    595     // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
    596     // in the JWK, while an RSA private key must have those, plus at least a "d"
    597     // (private exponent) entry.
    598     // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
    599     // section 6.3.
    600 
    601     // RSA private key import is not currently supported, so fail here if a "d"
    602     // entry is found.
    603     // TODO(padolph): Support RSA private key import.
    604     if (dict_value->HasKey("d"))
    605       return false;
    606 
    607     std::string jwk_n_value;
    608     if (!GetDecodedUrl64ValueByKey(*dict_value, "n", &jwk_n_value))
    609       return false;
    610     std::string jwk_e_value;
    611     if (!GetDecodedUrl64ValueByKey(*dict_value, "e", &jwk_e_value))
    612       return false;
    613 
    614     return ImportRsaPublicKeyInternal(
    615         reinterpret_cast<const uint8*>(jwk_n_value.data()),
    616         jwk_n_value.size(),
    617         reinterpret_cast<const uint8*>(jwk_e_value.data()),
    618         jwk_e_value.size(),
    619         algorithm,
    620         extractable,
    621         usage_mask,
    622         key);
    623 
    624   } else {
    625     return false;
    626   }
    627 
    628   return true;
    629 }
    630 
    631 }  // namespace content
    632