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 "jwk.h"
      6 
      7 #include <algorithm>
      8 #include <functional>
      9 #include <map>
     10 
     11 #include "base/base64.h"
     12 #include "base/json/json_reader.h"
     13 #include "base/json/json_writer.h"
     14 #include "base/stl_util.h"
     15 #include "base/strings/string_piece.h"
     16 #include "content/child/webcrypto/crypto_data.h"
     17 #include "content/child/webcrypto/status.h"
     18 #include "content/child/webcrypto/webcrypto_util.h"
     19 
     20 // TODO(eroman): The algorithm-specific logic in this file for AES and RSA
     21 // should be moved into the corresponding AlgorithmImplementation file. It
     22 // exists in this file to avoid duplication between OpenSSL and NSS
     23 // implementations.
     24 
     25 // JSON Web Key Format (JWK)
     26 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-21
     27 //
     28 // A JWK is a simple JSON dictionary with the following entries
     29 // - "kty" (Key Type) Parameter, REQUIRED
     30 // - <kty-specific parameters, see below>, REQUIRED
     31 // - "use" (Key Use) Parameter, OPTIONAL
     32 // - "key_ops" (Key Operations) Parameter, OPTIONAL
     33 // - "alg" (Algorithm) Parameter, OPTIONAL
     34 // - "ext" (Key Exportability), OPTIONAL
     35 // (all other entries are ignored)
     36 //
     37 // OPTIONAL here means that this code does not require the entry to be present
     38 // in the incoming JWK, because the method input parameters contain similar
     39 // information. If the optional JWK entry is present, it will be validated
     40 // against the corresponding input parameter for consistency and combined with
     41 // it according to rules defined below.
     42 //
     43 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK
     44 // values are parsed out and combined with the method input parameters to
     45 // build a Web Crypto Key:
     46 // Web Crypto Key type            <-- (deduced)
     47 // Web Crypto Key extractable     <-- JWK ext + input extractable
     48 // Web Crypto Key algorithm       <-- JWK alg + input algorithm
     49 // Web Crypto Key keyUsage        <-- JWK use, key_ops + input usage_mask
     50 // Web Crypto Key keying material <-- kty-specific parameters
     51 //
     52 // Values for each JWK entry are case-sensitive and defined in
     53 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18.
     54 // Note that not all values specified by JOSE are handled by this code. Only
     55 // handled values are listed.
     56 // - kty (Key Type)
     57 //   +-------+--------------------------------------------------------------+
     58 //   | "RSA" | RSA [RFC3447]                                                |
     59 //   | "oct" | Octet sequence (used to represent symmetric keys)            |
     60 //   +-------+--------------------------------------------------------------+
     61 //
     62 // - key_ops (Key Use Details)
     63 //   The key_ops field is an array that contains one or more strings from
     64 //   the table below, and describes the operations for which this key may be
     65 //   used.
     66 //   +-------+--------------------------------------------------------------+
     67 //   | "encrypt"    | encrypt operations                                    |
     68 //   | "decrypt"    | decrypt operations                                    |
     69 //   | "sign"       | sign (MAC) operations                                 |
     70 //   | "verify"     | verify (MAC) operations                               |
     71 //   | "wrapKey"    | key wrap                                              |
     72 //   | "unwrapKey"  | key unwrap                                            |
     73 //   | "deriveKey"  | key derivation                                        |
     74 //   | "deriveBits" | key derivation                                        |
     75 //   +-------+--------------------------------------------------------------+
     76 //
     77 // - use (Key Use)
     78 //   The use field contains a single entry from the table below.
     79 //   +-------+--------------------------------------------------------------+
     80 //   | "sig"     | equivalent to key_ops of [sign, verify]                  |
     81 //   | "enc"     | equivalent to key_ops of [encrypt, decrypt, wrapKey,     |
     82 //   |           | unwrapKey, deriveKey, deriveBits]                        |
     83 //   +-------+--------------------------------------------------------------+
     84 //
     85 //   NOTE: If both "use" and "key_ops" JWK members are present, the usages
     86 //   specified by them MUST be consistent.  In particular, the "use" value
     87 //   "sig" corresponds to "sign" and/or "verify".  The "use" value "enc"
     88 //   corresponds to all other values defined above.  If "key_ops" values
     89 //   corresponding to both "sig" and "enc" "use" values are present, the "use"
     90 //   member SHOULD NOT be present, and if present, its value MUST NOT be
     91 //   either "sig" or "enc".
     92 //
     93 // - ext (Key Exportability)
     94 //   +-------+--------------------------------------------------------------+
     95 //   | true  | Key may be exported from the trusted environment             |
     96 //   | false | Key cannot exit the trusted environment                      |
     97 //   +-------+--------------------------------------------------------------+
     98 //
     99 // - alg (Algorithm)
    100 //   See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18
    101 //   +--------------+-------------------------------------------------------+
    102 //   | Digital Signature or MAC Algorithm                                   |
    103 //   +--------------+-------------------------------------------------------+
    104 //   | "HS1"        | HMAC using SHA-1 hash algorithm                       |
    105 //   | "HS256"      | HMAC using SHA-256 hash algorithm                     |
    106 //   | "HS384"      | HMAC using SHA-384 hash algorithm                     |
    107 //   | "HS512"      | HMAC using SHA-512 hash algorithm                     |
    108 //   | "RS1"        | RSASSA using SHA-1 hash algorithm
    109 //   | "RS256"      | RSASSA using SHA-256 hash algorithm                   |
    110 //   | "RS384"      | RSASSA using SHA-384 hash algorithm                   |
    111 //   | "RS512"      | RSASSA using SHA-512 hash algorithm                   |
    112 //   +--------------+-------------------------------------------------------|
    113 //   | Key Management Algorithm                                             |
    114 //   +--------------+-------------------------------------------------------+
    115 //   | "RSA-OAEP"   | RSAES using Optimal Asymmetric Encryption Padding     |
    116 //   |              | (OAEP) [RFC3447], with the default parameters         |
    117 //   |              | specified by RFC3447 in Section A.2.1                 |
    118 //   | "A128KW"     | Advanced Encryption Standard (AES) Key Wrap Algorithm |
    119 //   |              | [RFC3394] using 128 bit keys                          |
    120 //   | "A192KW"     | AES Key Wrap Algorithm using 192 bit keys             |
    121 //   | "A256KW"     | AES Key Wrap Algorithm using 256 bit keys             |
    122 //   | "A128GCM"    | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using |
    123 //   |              | 128 bit keys                                          |
    124 //   | "A192GCM"    | AES GCM using 192 bit keys                            |
    125 //   | "A256GCM"    | AES GCM using 256 bit keys                            |
    126 //   | "A128CBC"    | AES in Cipher Block Chaining Mode (CBC) with PKCS #5  |
    127 //   |              | padding [NIST.800-38A]                                |
    128 //   | "A192CBC"    | AES CBC using 192 bit keys                            |
    129 //   | "A256CBC"    | AES CBC using 256 bit keys                            |
    130 //   +--------------+-------------------------------------------------------+
    131 //
    132 // kty-specific parameters
    133 // The value of kty determines the type and content of the keying material
    134 // carried in the JWK to be imported.
    135 // // - kty == "oct" (symmetric or other raw key)
    136 //   +-------+--------------------------------------------------------------+
    137 //   | "k"   | Contains the value of the symmetric (or other single-valued) |
    138 //   |       | key.  It is represented as the base64url encoding of the     |
    139 //   |       | octet sequence containing the key value.                     |
    140 //   +-------+--------------------------------------------------------------+
    141 // - kty == "RSA" (RSA public key)
    142 //   +-------+--------------------------------------------------------------+
    143 //   | "n"   | Contains the modulus value for the RSA public key.  It is    |
    144 //   |       | represented as the base64url encoding of the value's         |
    145 //   |       | unsigned big endian representation as an octet sequence.     |
    146 //   +-------+--------------------------------------------------------------+
    147 //   | "e"   | Contains the exponent value for the RSA public key.  It is   |
    148 //   |       | represented as the base64url encoding of the value's         |
    149 //   |       | unsigned big endian representation as an octet sequence.     |
    150 //   +-------+--------------------------------------------------------------+
    151 // - If key == "RSA" and the "d" parameter is present then it is a private key.
    152 //   All the parameters above for public keys apply, as well as the following.
    153 //   (Note that except for "d", all of these are optional):
    154 //   +-------+--------------------------------------------------------------+
    155 //   | "d"   | Contains the private exponent value for the RSA private key. |
    156 //   |       | It is represented as the base64url encoding of the value's   |
    157 //   |       | unsigned big endian representation as an octet sequence.     |
    158 //   +-------+--------------------------------------------------------------+
    159 //   | "p"   | Contains the first prime factor value for the RSA private    |
    160 //   |       | key.  It is represented as the base64url encoding of the     |
    161 //   |       | value's                                                      |
    162 //   |       | unsigned big endian representation as an octet sequence.     |
    163 //   +-------+--------------------------------------------------------------+
    164 //   | "q"   | Contains the second prime factor value for the RSA private   |
    165 //   |       | key.  It is represented as the base64url encoding of the     |
    166 //   |       | value's unsigned big endian representation as an octet       |
    167 //   |       | sequence.                                                    |
    168 //   +-------+--------------------------------------------------------------+
    169 //   | "dp"  | Contains the first factor CRT exponent value for the RSA     |
    170 //   |       | private key.  It is represented as the base64url encoding of |
    171 //   |       | the value's unsigned big endian representation as an octet   |
    172 //   |       | sequence.                                                    |
    173 //   +-------+--------------------------------------------------------------+
    174 //   | "dq"  | Contains the second factor CRT exponent value for the RSA    |
    175 //   |       | private key.  It is represented as the base64url encoding of |
    176 //   |       | the value's unsigned big endian representation as an octet   |
    177 //   |       | sequence.                                                    |
    178 //   +-------+--------------------------------------------------------------+
    179 //   | "dq"  | Contains the first CRT coefficient value for the RSA private |
    180 //   |       | key.  It is represented as the base64url encoding of the     |
    181 //   |       | value's unsigned big endian representation as an octet       |
    182 //   |       | sequence.                                                    |
    183 //   +-------+--------------------------------------------------------------+
    184 //
    185 // Consistency and conflict resolution
    186 // The 'algorithm', 'extractable', and 'usage_mask' input parameters
    187 // may be different than the corresponding values inside the JWK. The Web
    188 // Crypto spec says that if a JWK value is present but is inconsistent with
    189 // the input value, it is an error and the operation must fail. If no
    190 // inconsistency is found then the input parameters are used.
    191 //
    192 // algorithm
    193 //   If the JWK algorithm is provided, it must match the web crypto input
    194 //   algorithm (both the algorithm ID and inner hash if applicable).
    195 //
    196 // extractable
    197 //   If the JWK ext field is true but the input parameter is false, make the
    198 //   Web Crypto Key non-extractable. Conversely, if the JWK ext field is
    199 //   false but the input parameter is true, it is an inconsistency. If both
    200 //   are true or both are false, use that value.
    201 //
    202 // usage_mask
    203 //   The input usage_mask must be a strict subset of the interpreted JWK use
    204 //   value, else it is judged inconsistent. In all cases the input usage_mask
    205 //   is used as the final usage_mask.
    206 //
    207 
    208 namespace content {
    209 
    210 namespace webcrypto {
    211 
    212 namespace {
    213 
    214 // Web Crypto equivalent usage mask for JWK 'use' = 'enc'.
    215 const blink::WebCryptoKeyUsageMask kJwkEncUsage =
    216     blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt |
    217     blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey |
    218     blink::WebCryptoKeyUsageDeriveKey | blink::WebCryptoKeyUsageDeriveBits;
    219 // Web Crypto equivalent usage mask for JWK 'use' = 'sig'.
    220 const blink::WebCryptoKeyUsageMask kJwkSigUsage =
    221     blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify;
    222 
    223 class JwkWriter {
    224  public:
    225   JwkWriter(const std::string& algorithm,
    226             bool extractable,
    227             blink::WebCryptoKeyUsageMask usage_mask,
    228             const std::string& kty) {
    229     dict_.SetString("alg", algorithm);
    230     dict_.Set("key_ops", CreateJwkKeyOpsFromWebCryptoUsages(usage_mask));
    231     dict_.SetBoolean("ext", extractable);
    232     dict_.SetString("kty", kty);
    233   }
    234 
    235   void Set(const std::string& key, const std::string& value) {
    236     dict_.SetString(key, value);
    237   }
    238 
    239   void SetBase64Encoded(const std::string& key, const CryptoData& value) {
    240     dict_.SetString(key,
    241                     Base64EncodeUrlSafe(base::StringPiece(
    242                         reinterpret_cast<const char*>(value.bytes()),
    243                         value.byte_length())));
    244   }
    245 
    246   void ToBytes(std::vector<uint8_t>* utf8_bytes) {
    247     std::string json;
    248     base::JSONWriter::Write(&dict_, &json);
    249     utf8_bytes->assign(json.begin(), json.end());
    250   }
    251 
    252  private:
    253   base::DictionaryValue dict_;
    254 };
    255 
    256 // Extracts the required string property with key |path| from |dict| and saves
    257 // the result to |*result|. If the property does not exist or is not a string,
    258 // returns an error.
    259 Status GetJwkString(base::DictionaryValue* dict,
    260                     const std::string& path,
    261                     std::string* result) {
    262   base::Value* value = NULL;
    263   if (!dict->Get(path, &value))
    264     return Status::ErrorJwkPropertyMissing(path);
    265   if (!value->GetAsString(result))
    266     return Status::ErrorJwkPropertyWrongType(path, "string");
    267   return Status::Success();
    268 }
    269 
    270 // Extracts the optional string property with key |path| from |dict| and saves
    271 // the result to |*result| if it was found. If the property exists and is not a
    272 // string, returns an error. Otherwise returns success, and sets
    273 // |*property_exists| if it was found.
    274 Status GetOptionalJwkString(base::DictionaryValue* dict,
    275                             const std::string& path,
    276                             std::string* result,
    277                             bool* property_exists) {
    278   *property_exists = false;
    279   base::Value* value = NULL;
    280   if (!dict->Get(path, &value))
    281     return Status::Success();
    282 
    283   if (!value->GetAsString(result))
    284     return Status::ErrorJwkPropertyWrongType(path, "string");
    285 
    286   *property_exists = true;
    287   return Status::Success();
    288 }
    289 
    290 // Extracts the optional array property with key |path| from |dict| and saves
    291 // the result to |*result| if it was found. If the property exists and is not an
    292 // array, returns an error. Otherwise returns success, and sets
    293 // |*property_exists| if it was found. Note that |*result| is owned by |dict|.
    294 Status GetOptionalJwkList(base::DictionaryValue* dict,
    295                           const std::string& path,
    296                           base::ListValue** result,
    297                           bool* property_exists) {
    298   *property_exists = false;
    299   base::Value* value = NULL;
    300   if (!dict->Get(path, &value))
    301     return Status::Success();
    302 
    303   if (!value->GetAsList(result))
    304     return Status::ErrorJwkPropertyWrongType(path, "list");
    305 
    306   *property_exists = true;
    307   return Status::Success();
    308 }
    309 
    310 // Extracts the required string property with key |path| from |dict| and saves
    311 // the base64url-decoded bytes to |*result|. If the property does not exist or
    312 // is not a string, or could not be base64url-decoded, returns an error.
    313 Status GetJwkBytes(base::DictionaryValue* dict,
    314                    const std::string& path,
    315                    std::string* result) {
    316   std::string base64_string;
    317   Status status = GetJwkString(dict, path, &base64_string);
    318   if (status.IsError())
    319     return status;
    320 
    321   if (!Base64DecodeUrlSafe(base64_string, result))
    322     return Status::ErrorJwkBase64Decode(path);
    323 
    324   return Status::Success();
    325 }
    326 
    327 // Extracts the required base64url property, which is interpreted as being a
    328 // big-endian unsigned integer.
    329 Status GetJwkBigInteger(base::DictionaryValue* dict,
    330                         const std::string& path,
    331                         std::string* result) {
    332   Status status = GetJwkBytes(dict, path, result);
    333   if (status.IsError())
    334     return status;
    335 
    336   if (result->empty())
    337     return Status::ErrorJwkEmptyBigInteger(path);
    338 
    339   // The JWA spec says that "The octet sequence MUST utilize the minimum number
    340   // of octets to represent the value." This means there shouldn't be any
    341   // leading zeros.
    342   if (result->size() > 1 && (*result)[0] == 0)
    343     return Status::ErrorJwkBigIntegerHasLeadingZero(path);
    344 
    345   return Status::Success();
    346 }
    347 
    348 // Extracts the optional boolean property with key |path| from |dict| and saves
    349 // the result to |*result| if it was found. If the property exists and is not a
    350 // boolean, returns an error. Otherwise returns success, and sets
    351 // |*property_exists| if it was found.
    352 Status GetOptionalJwkBool(base::DictionaryValue* dict,
    353                           const std::string& path,
    354                           bool* result,
    355                           bool* property_exists) {
    356   *property_exists = false;
    357   base::Value* value = NULL;
    358   if (!dict->Get(path, &value))
    359     return Status::Success();
    360 
    361   if (!value->GetAsBoolean(result))
    362     return Status::ErrorJwkPropertyWrongType(path, "boolean");
    363 
    364   *property_exists = true;
    365   return Status::Success();
    366 }
    367 
    368 Status VerifyExt(base::DictionaryValue* dict, bool expected_extractable) {
    369   // JWK "ext" (optional) --> extractable parameter
    370   bool jwk_ext_value = false;
    371   bool has_jwk_ext;
    372   Status status = GetOptionalJwkBool(dict, "ext", &jwk_ext_value, &has_jwk_ext);
    373   if (status.IsError())
    374     return status;
    375   if (has_jwk_ext && expected_extractable && !jwk_ext_value)
    376     return Status::ErrorJwkExtInconsistent();
    377   return Status::Success();
    378 }
    379 
    380 Status VerifyUsages(base::DictionaryValue* dict,
    381                     blink::WebCryptoKeyUsageMask expected_usage_mask) {
    382   // JWK "key_ops" (optional) --> usage_mask parameter
    383   base::ListValue* jwk_key_ops_value = NULL;
    384   bool has_jwk_key_ops;
    385   Status status =
    386       GetOptionalJwkList(dict, "key_ops", &jwk_key_ops_value, &has_jwk_key_ops);
    387   if (status.IsError())
    388     return status;
    389   blink::WebCryptoKeyUsageMask jwk_key_ops_mask = 0;
    390   if (has_jwk_key_ops) {
    391     status =
    392         GetWebCryptoUsagesFromJwkKeyOps(jwk_key_ops_value, &jwk_key_ops_mask);
    393     if (status.IsError())
    394       return status;
    395     // The input usage_mask must be a subset of jwk_key_ops_mask.
    396     if (!ContainsKeyUsages(jwk_key_ops_mask, expected_usage_mask))
    397       return Status::ErrorJwkKeyopsInconsistent();
    398   }
    399 
    400   // JWK "use" (optional) --> usage_mask parameter
    401   std::string jwk_use_value;
    402   bool has_jwk_use;
    403   status = GetOptionalJwkString(dict, "use", &jwk_use_value, &has_jwk_use);
    404   if (status.IsError())
    405     return status;
    406   blink::WebCryptoKeyUsageMask jwk_use_mask = 0;
    407   if (has_jwk_use) {
    408     if (jwk_use_value == "enc")
    409       jwk_use_mask = kJwkEncUsage;
    410     else if (jwk_use_value == "sig")
    411       jwk_use_mask = kJwkSigUsage;
    412     else
    413       return Status::ErrorJwkUnrecognizedUse();
    414     // The input usage_mask must be a subset of jwk_use_mask.
    415     if (!ContainsKeyUsages(jwk_use_mask, expected_usage_mask))
    416       return Status::ErrorJwkUseInconsistent();
    417   }
    418 
    419   // If both 'key_ops' and 'use' are present, ensure they are consistent.
    420   if (has_jwk_key_ops && has_jwk_use &&
    421       !ContainsKeyUsages(jwk_use_mask, jwk_key_ops_mask))
    422     return Status::ErrorJwkUseAndKeyopsInconsistent();
    423 
    424   return Status::Success();
    425 }
    426 
    427 Status VerifyAlg(base::DictionaryValue* dict,
    428                  const std::string& expected_algorithm) {
    429   // JWK "alg" --> algorithm parameter
    430   bool has_jwk_alg;
    431   std::string jwk_alg_value;
    432   Status status =
    433       GetOptionalJwkString(dict, "alg", &jwk_alg_value, &has_jwk_alg);
    434   if (status.IsError())
    435     return status;
    436 
    437   if (has_jwk_alg && jwk_alg_value != expected_algorithm)
    438     return Status::ErrorJwkAlgorithmInconsistent();
    439 
    440   return Status::Success();
    441 }
    442 
    443 Status ParseJwkCommon(const CryptoData& bytes,
    444                       bool expected_extractable,
    445                       blink::WebCryptoKeyUsageMask expected_usage_mask,
    446                       std::string* kty,
    447                       scoped_ptr<base::DictionaryValue>* dict) {
    448   // Parse the incoming JWK JSON.
    449   base::StringPiece json_string(reinterpret_cast<const char*>(bytes.bytes()),
    450                                 bytes.byte_length());
    451 
    452   scoped_ptr<base::Value> value(base::JSONReader::Read(json_string));
    453   base::DictionaryValue* dict_value = NULL;
    454 
    455   if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value)
    456     return Status::ErrorJwkNotDictionary();
    457 
    458   // Release |value|, as ownership will be transferred to |dict| via
    459   // |dict_value|, which points to the same object as |value|.
    460   ignore_result(value.release());
    461   dict->reset(dict_value);
    462 
    463   // JWK "kty". Exit early if this required JWK parameter is missing.
    464   Status status = GetJwkString(dict_value, "kty", kty);
    465   if (status.IsError())
    466     return status;
    467 
    468   status = VerifyExt(dict_value, expected_extractable);
    469   if (status.IsError())
    470     return status;
    471 
    472   status = VerifyUsages(dict_value, expected_usage_mask);
    473   if (status.IsError())
    474     return status;
    475 
    476   return Status::Success();
    477 }
    478 
    479 Status ReadSecretKeyNoExpectedAlg(
    480     const CryptoData& key_data,
    481     bool expected_extractable,
    482     blink::WebCryptoKeyUsageMask expected_usage_mask,
    483     std::vector<uint8_t>* raw_key_data,
    484     scoped_ptr<base::DictionaryValue>* dict) {
    485   if (!key_data.byte_length())
    486     return Status::ErrorImportEmptyKeyData();
    487 
    488   std::string kty;
    489   Status status = ParseJwkCommon(
    490       key_data, expected_extractable, expected_usage_mask, &kty, dict);
    491   if (status.IsError())
    492     return status;
    493 
    494   if (kty != "oct")
    495     return Status::ErrorJwkUnexpectedKty("oct");
    496 
    497   std::string jwk_k_value;
    498   status = GetJwkBytes(dict->get(), "k", &jwk_k_value);
    499   if (status.IsError())
    500     return status;
    501   raw_key_data->assign(jwk_k_value.begin(), jwk_k_value.end());
    502 
    503   return Status::Success();
    504 }
    505 
    506 }  // namespace
    507 
    508 void WriteSecretKeyJwk(const CryptoData& raw_key_data,
    509                        const std::string& algorithm,
    510                        bool extractable,
    511                        blink::WebCryptoKeyUsageMask usage_mask,
    512                        std::vector<uint8_t>* jwk_key_data) {
    513   JwkWriter writer(algorithm, extractable, usage_mask, "oct");
    514   writer.SetBase64Encoded("k", raw_key_data);
    515   writer.ToBytes(jwk_key_data);
    516 }
    517 
    518 Status ReadSecretKeyJwk(const CryptoData& key_data,
    519                         const std::string& expected_algorithm,
    520                         bool expected_extractable,
    521                         blink::WebCryptoKeyUsageMask expected_usage_mask,
    522                         std::vector<uint8_t>* raw_key_data) {
    523   scoped_ptr<base::DictionaryValue> dict;
    524   Status status = ReadSecretKeyNoExpectedAlg(
    525       key_data, expected_extractable, expected_usage_mask, raw_key_data, &dict);
    526   if (status.IsError())
    527     return status;
    528   return VerifyAlg(dict.get(), expected_algorithm);
    529 }
    530 
    531 std::string MakeJwkAesAlgorithmName(const std::string& suffix,
    532                                     unsigned int keylen_bytes) {
    533   if (keylen_bytes == 16)
    534     return std::string("A128") + suffix;
    535   if (keylen_bytes == 24)
    536     return std::string("A192") + suffix;
    537   if (keylen_bytes == 32)
    538     return std::string("A256") + suffix;
    539   return std::string();
    540 }
    541 
    542 Status ReadAesSecretKeyJwk(const CryptoData& key_data,
    543                            const std::string& algorithm_name_suffix,
    544                            bool expected_extractable,
    545                            blink::WebCryptoKeyUsageMask expected_usage_mask,
    546                            std::vector<uint8_t>* raw_key_data) {
    547   scoped_ptr<base::DictionaryValue> dict;
    548   Status status = ReadSecretKeyNoExpectedAlg(
    549       key_data, expected_extractable, expected_usage_mask, raw_key_data, &dict);
    550   if (status.IsError())
    551     return status;
    552 
    553   bool has_jwk_alg;
    554   std::string jwk_alg;
    555   status = GetOptionalJwkString(dict.get(), "alg", &jwk_alg, &has_jwk_alg);
    556   if (status.IsError())
    557     return status;
    558 
    559   if (has_jwk_alg) {
    560     std::string expected_algorithm_name =
    561         MakeJwkAesAlgorithmName(algorithm_name_suffix, raw_key_data->size());
    562 
    563     if (jwk_alg != expected_algorithm_name) {
    564       // Give a different error message if the key length was wrong.
    565       if (jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 16) ||
    566           jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 24) ||
    567           jwk_alg == MakeJwkAesAlgorithmName(algorithm_name_suffix, 32)) {
    568         return Status::ErrorJwkIncorrectKeyLength();
    569       }
    570       return Status::ErrorJwkAlgorithmInconsistent();
    571     }
    572   }
    573 
    574   return Status::Success();
    575 }
    576 
    577 // Writes an RSA public key to a JWK dictionary
    578 void WriteRsaPublicKeyJwk(const CryptoData& n,
    579                           const CryptoData& e,
    580                           const std::string& algorithm,
    581                           bool extractable,
    582                           blink::WebCryptoKeyUsageMask usage_mask,
    583                           std::vector<uint8_t>* jwk_key_data) {
    584   JwkWriter writer(algorithm, extractable, usage_mask, "RSA");
    585   writer.SetBase64Encoded("n", n);
    586   writer.SetBase64Encoded("e", e);
    587   writer.ToBytes(jwk_key_data);
    588 }
    589 
    590 // Writes an RSA private key to a JWK dictionary
    591 void WriteRsaPrivateKeyJwk(const CryptoData& n,
    592                            const CryptoData& e,
    593                            const CryptoData& d,
    594                            const CryptoData& p,
    595                            const CryptoData& q,
    596                            const CryptoData& dp,
    597                            const CryptoData& dq,
    598                            const CryptoData& qi,
    599                            const std::string& algorithm,
    600                            bool extractable,
    601                            blink::WebCryptoKeyUsageMask usage_mask,
    602                            std::vector<uint8_t>* jwk_key_data) {
    603   JwkWriter writer(algorithm, extractable, usage_mask, "RSA");
    604 
    605   writer.SetBase64Encoded("n", n);
    606   writer.SetBase64Encoded("e", e);
    607   writer.SetBase64Encoded("d", d);
    608   // Although these are "optional" in the JWA, WebCrypto spec requires them to
    609   // be emitted.
    610   writer.SetBase64Encoded("p", p);
    611   writer.SetBase64Encoded("q", q);
    612   writer.SetBase64Encoded("dp", dp);
    613   writer.SetBase64Encoded("dq", dq);
    614   writer.SetBase64Encoded("qi", qi);
    615   writer.ToBytes(jwk_key_data);
    616 }
    617 
    618 JwkRsaInfo::JwkRsaInfo() : is_private_key(false) {
    619 }
    620 
    621 JwkRsaInfo::~JwkRsaInfo() {
    622 }
    623 
    624 Status ReadRsaKeyJwk(const CryptoData& key_data,
    625                      const std::string& expected_algorithm,
    626                      bool expected_extractable,
    627                      blink::WebCryptoKeyUsageMask expected_usage_mask,
    628                      JwkRsaInfo* result) {
    629   if (!key_data.byte_length())
    630     return Status::ErrorImportEmptyKeyData();
    631 
    632   scoped_ptr<base::DictionaryValue> dict;
    633   std::string kty;
    634   Status status = ParseJwkCommon(
    635       key_data, expected_extractable, expected_usage_mask, &kty, &dict);
    636   if (status.IsError())
    637     return status;
    638 
    639   status = VerifyAlg(dict.get(), expected_algorithm);
    640   if (status.IsError())
    641     return status;
    642 
    643   if (kty != "RSA")
    644     return Status::ErrorJwkUnexpectedKty("RSA");
    645 
    646   // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry
    647   // in the JWK, while an RSA private key must have those, plus at least a "d"
    648   // (private exponent) entry.
    649   // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18,
    650   // section 6.3.
    651   status = GetJwkBigInteger(dict.get(), "n", &result->n);
    652   if (status.IsError())
    653     return status;
    654   status = GetJwkBigInteger(dict.get(), "e", &result->e);
    655   if (status.IsError())
    656     return status;
    657 
    658   result->is_private_key = dict->HasKey("d");
    659   if (!result->is_private_key)
    660     return Status::Success();
    661 
    662   status = GetJwkBigInteger(dict.get(), "d", &result->d);
    663   if (status.IsError())
    664     return status;
    665 
    666   // The "p", "q", "dp", "dq", and "qi" properties are optional in the JWA
    667   // spec. However they are required by Chromium's WebCrypto implementation.
    668 
    669   status = GetJwkBigInteger(dict.get(), "p", &result->p);
    670   if (status.IsError())
    671     return status;
    672 
    673   status = GetJwkBigInteger(dict.get(), "q", &result->q);
    674   if (status.IsError())
    675     return status;
    676 
    677   status = GetJwkBigInteger(dict.get(), "dp", &result->dp);
    678   if (status.IsError())
    679     return status;
    680 
    681   status = GetJwkBigInteger(dict.get(), "dq", &result->dq);
    682   if (status.IsError())
    683     return status;
    684 
    685   status = GetJwkBigInteger(dict.get(), "qi", &result->qi);
    686   if (status.IsError())
    687     return status;
    688 
    689   return Status::Success();
    690 }
    691 
    692 const char* GetJwkHmacAlgorithmName(blink::WebCryptoAlgorithmId hash) {
    693   switch (hash) {
    694     case blink::WebCryptoAlgorithmIdSha1:
    695       return "HS1";
    696     case blink::WebCryptoAlgorithmIdSha256:
    697       return "HS256";
    698     case blink::WebCryptoAlgorithmIdSha384:
    699       return "HS384";
    700     case blink::WebCryptoAlgorithmIdSha512:
    701       return "HS512";
    702     default:
    703       return NULL;
    704   }
    705 }
    706 
    707 // TODO(eroman): This accepts invalid inputs. http://crbug.com/378034
    708 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) {
    709   std::string base64_encoded_text(input);
    710   std::replace(
    711       base64_encoded_text.begin(), base64_encoded_text.end(), '-', '+');
    712   std::replace(
    713       base64_encoded_text.begin(), base64_encoded_text.end(), '_', '/');
    714   base64_encoded_text.append((4 - base64_encoded_text.size() % 4) % 4, '=');
    715   return base::Base64Decode(base64_encoded_text, output);
    716 }
    717 
    718 std::string Base64EncodeUrlSafe(const base::StringPiece& input) {
    719   std::string output;
    720   base::Base64Encode(input, &output);
    721   std::replace(output.begin(), output.end(), '+', '-');
    722   std::replace(output.begin(), output.end(), '/', '_');
    723   output.erase(std::remove(output.begin(), output.end(), '='), output.end());
    724   return output;
    725 }
    726 
    727 std::string Base64EncodeUrlSafe(const std::vector<uint8_t>& input) {
    728   const base::StringPiece string_piece(
    729       reinterpret_cast<const char*>(vector_as_array(&input)), input.size());
    730   return Base64EncodeUrlSafe(string_piece);
    731 }
    732 
    733 }  // namespace webcrypto
    734 
    735 }  // namespace content
    736