| OLD | NEW |
| (Empty) |
| 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 <algorithm> | |
| 6 #include <functional> | |
| 7 #include <map> | |
| 8 #include "base/json/json_reader.h" | |
| 9 #include "base/lazy_instance.h" | |
| 10 #include "base/logging.h" | |
| 11 #include "base/memory/scoped_ptr.h" | |
| 12 #include "base/strings/string_piece.h" | |
| 13 #include "base/values.h" | |
| 14 #include "content/renderer/webcrypto/crypto_data.h" | |
| 15 #include "content/renderer/webcrypto/platform_crypto.h" | |
| 16 #include "content/renderer/webcrypto/shared_crypto.h" | |
| 17 #include "content/renderer/webcrypto/webcrypto_util.h" | |
| 18 | |
| 19 namespace content { | |
| 20 | |
| 21 namespace webcrypto { | |
| 22 | |
| 23 namespace { | |
| 24 | |
| 25 typedef blink::WebCryptoAlgorithm (*AlgorithmCreationFunc)(); | |
| 26 | |
| 27 class JwkAlgorithmInfo { | |
| 28 public: | |
| 29 JwkAlgorithmInfo() | |
| 30 : creation_func_(NULL), | |
| 31 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {} | |
| 32 | |
| 33 explicit JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func) | |
| 34 : creation_func_(algorithm_creation_func), | |
| 35 required_key_length_bytes_(NO_KEY_SIZE_REQUIREMENT) {} | |
| 36 | |
| 37 JwkAlgorithmInfo(AlgorithmCreationFunc algorithm_creation_func, | |
| 38 unsigned int required_key_length_bits) | |
| 39 : creation_func_(algorithm_creation_func), | |
| 40 required_key_length_bytes_(required_key_length_bits / 8) { | |
| 41 DCHECK((required_key_length_bits % 8) == 0); | |
| 42 } | |
| 43 | |
| 44 bool CreateImportAlgorithm(blink::WebCryptoAlgorithm* algorithm) const { | |
| 45 *algorithm = creation_func_(); | |
| 46 return !algorithm->isNull(); | |
| 47 } | |
| 48 | |
| 49 bool IsInvalidKeyByteLength(size_t byte_length) const { | |
| 50 if (required_key_length_bytes_ == NO_KEY_SIZE_REQUIREMENT) | |
| 51 return false; | |
| 52 return required_key_length_bytes_ != byte_length; | |
| 53 } | |
| 54 | |
| 55 private: | |
| 56 enum { NO_KEY_SIZE_REQUIREMENT = UINT_MAX }; | |
| 57 | |
| 58 AlgorithmCreationFunc creation_func_; | |
| 59 | |
| 60 // The expected key size for the algorithm or NO_KEY_SIZE_REQUIREMENT. | |
| 61 unsigned int required_key_length_bytes_; | |
| 62 }; | |
| 63 | |
| 64 typedef std::map<std::string, JwkAlgorithmInfo> JwkAlgorithmInfoMap; | |
| 65 | |
| 66 class JwkAlgorithmRegistry { | |
| 67 public: | |
| 68 JwkAlgorithmRegistry() { | |
| 69 // TODO(eroman): | |
| 70 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-20 | |
| 71 // says HMAC with SHA-2 should have a key size at least as large as the | |
| 72 // hash output. | |
| 73 alg_to_info_["HS256"] = | |
| 74 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm, | |
| 75 blink::WebCryptoAlgorithmIdSha256>); | |
| 76 alg_to_info_["HS384"] = | |
| 77 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm, | |
| 78 blink::WebCryptoAlgorithmIdSha384>); | |
| 79 alg_to_info_["HS512"] = | |
| 80 JwkAlgorithmInfo(&BindAlgorithmId<CreateHmacImportAlgorithm, | |
| 81 blink::WebCryptoAlgorithmIdSha512>); | |
| 82 alg_to_info_["RS256"] = | |
| 83 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm, | |
| 84 blink::WebCryptoAlgorithmIdSha256>); | |
| 85 alg_to_info_["RS384"] = | |
| 86 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm, | |
| 87 blink::WebCryptoAlgorithmIdSha384>); | |
| 88 alg_to_info_["RS512"] = | |
| 89 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaSsaImportAlgorithm, | |
| 90 blink::WebCryptoAlgorithmIdSha512>); | |
| 91 alg_to_info_["RSA1_5"] = JwkAlgorithmInfo( | |
| 92 &BindAlgorithmId<CreateAlgorithm, | |
| 93 blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5>); | |
| 94 alg_to_info_["RSA-OAEP"] = | |
| 95 JwkAlgorithmInfo(&BindAlgorithmId<CreateRsaOaepImportAlgorithm, | |
| 96 blink::WebCryptoAlgorithmIdSha1>); | |
| 97 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 128 yet | |
| 98 alg_to_info_["A128KW"] = | |
| 99 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 128); | |
| 100 // TODO(padolph): The Web Crypto spec does not enumerate AES-KW 256 yet | |
| 101 alg_to_info_["A256KW"] = | |
| 102 JwkAlgorithmInfo(&blink::WebCryptoAlgorithm::createNull, 256); | |
| 103 alg_to_info_["A128GCM"] = JwkAlgorithmInfo( | |
| 104 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>, | |
| 105 128); | |
| 106 alg_to_info_["A256GCM"] = JwkAlgorithmInfo( | |
| 107 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesGcm>, | |
| 108 256); | |
| 109 alg_to_info_["A128CBC"] = JwkAlgorithmInfo( | |
| 110 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>, | |
| 111 128); | |
| 112 alg_to_info_["A192CBC"] = JwkAlgorithmInfo( | |
| 113 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>, | |
| 114 192); | |
| 115 alg_to_info_["A256CBC"] = JwkAlgorithmInfo( | |
| 116 &BindAlgorithmId<CreateAlgorithm, blink::WebCryptoAlgorithmIdAesCbc>, | |
| 117 256); | |
| 118 } | |
| 119 | |
| 120 // Returns NULL if the algorithm name was not registered. | |
| 121 const JwkAlgorithmInfo* GetAlgorithmInfo(const std::string& jwk_alg) const { | |
| 122 const JwkAlgorithmInfoMap::const_iterator pos = alg_to_info_.find(jwk_alg); | |
| 123 if (pos == alg_to_info_.end()) | |
| 124 return NULL; | |
| 125 return &pos->second; | |
| 126 } | |
| 127 | |
| 128 private: | |
| 129 // Binds a WebCryptoAlgorithmId value to a compatible factory function. | |
| 130 typedef blink::WebCryptoAlgorithm (*FuncWithWebCryptoAlgIdArg)( | |
| 131 blink::WebCryptoAlgorithmId); | |
| 132 template <FuncWithWebCryptoAlgIdArg func, | |
| 133 blink::WebCryptoAlgorithmId algorithm_id> | |
| 134 static blink::WebCryptoAlgorithm BindAlgorithmId() { | |
| 135 return func(algorithm_id); | |
| 136 } | |
| 137 | |
| 138 JwkAlgorithmInfoMap alg_to_info_; | |
| 139 }; | |
| 140 | |
| 141 base::LazyInstance<JwkAlgorithmRegistry> jwk_alg_registry = | |
| 142 LAZY_INSTANCE_INITIALIZER; | |
| 143 | |
| 144 bool ImportAlgorithmsConsistent(const blink::WebCryptoAlgorithm& alg1, | |
| 145 const blink::WebCryptoAlgorithm& alg2) { | |
| 146 DCHECK(!alg1.isNull()); | |
| 147 DCHECK(!alg2.isNull()); | |
| 148 if (alg1.id() != alg2.id()) | |
| 149 return false; | |
| 150 if (alg1.paramsType() != alg2.paramsType()) | |
| 151 return false; | |
| 152 switch (alg1.paramsType()) { | |
| 153 case blink::WebCryptoAlgorithmParamsTypeNone: | |
| 154 return true; | |
| 155 case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams: | |
| 156 return ImportAlgorithmsConsistent(alg1.rsaHashedImportParams()->hash(), | |
| 157 alg2.rsaHashedImportParams()->hash()); | |
| 158 case blink::WebCryptoAlgorithmParamsTypeHmacImportParams: | |
| 159 return ImportAlgorithmsConsistent(alg1.hmacImportParams()->hash(), | |
| 160 alg2.hmacImportParams()->hash()); | |
| 161 default: | |
| 162 return false; | |
| 163 } | |
| 164 } | |
| 165 | |
| 166 // Extracts the required string property with key |path| from |dict| and saves | |
| 167 // the result to |*result|. If the property does not exist or is not a string, | |
| 168 // returns an error. | |
| 169 Status GetJwkString(base::DictionaryValue* dict, | |
| 170 const std::string& path, | |
| 171 std::string* result) { | |
| 172 base::Value* value = NULL; | |
| 173 if (!dict->Get(path, &value)) | |
| 174 return Status::ErrorJwkPropertyMissing(path); | |
| 175 if (!value->GetAsString(result)) | |
| 176 return Status::ErrorJwkPropertyWrongType(path, "string"); | |
| 177 return Status::Success(); | |
| 178 } | |
| 179 | |
| 180 // Extracts the optional string property with key |path| from |dict| and saves | |
| 181 // the result to |*result| if it was found. If the property exists and is not a | |
| 182 // string, returns an error. Otherwise returns success, and sets | |
| 183 // |*property_exists| if it was found. | |
| 184 Status GetOptionalJwkString(base::DictionaryValue* dict, | |
| 185 const std::string& path, | |
| 186 std::string* result, | |
| 187 bool* property_exists) { | |
| 188 *property_exists = false; | |
| 189 base::Value* value = NULL; | |
| 190 if (!dict->Get(path, &value)) | |
| 191 return Status::Success(); | |
| 192 | |
| 193 if (!value->GetAsString(result)) | |
| 194 return Status::ErrorJwkPropertyWrongType(path, "string"); | |
| 195 | |
| 196 *property_exists = true; | |
| 197 return Status::Success(); | |
| 198 } | |
| 199 | |
| 200 // Extracts the required string property with key |path| from |dict| and saves | |
| 201 // the base64-decoded bytes to |*result|. If the property does not exist or is | |
| 202 // not a string, or could not be base64-decoded, returns an error. | |
| 203 Status GetJwkBytes(base::DictionaryValue* dict, | |
| 204 const std::string& path, | |
| 205 std::string* result) { | |
| 206 std::string base64_string; | |
| 207 Status status = GetJwkString(dict, path, &base64_string); | |
| 208 if (status.IsError()) | |
| 209 return status; | |
| 210 | |
| 211 if (!Base64DecodeUrlSafe(base64_string, result)) | |
| 212 return Status::ErrorJwkBase64Decode(path); | |
| 213 | |
| 214 return Status::Success(); | |
| 215 } | |
| 216 | |
| 217 // Extracts the optional boolean property with key |path| from |dict| and saves | |
| 218 // the result to |*result| if it was found. If the property exists and is not a | |
| 219 // boolean, returns an error. Otherwise returns success, and sets | |
| 220 // |*property_exists| if it was found. | |
| 221 Status GetOptionalJwkBool(base::DictionaryValue* dict, | |
| 222 const std::string& path, | |
| 223 bool* result, | |
| 224 bool* property_exists) { | |
| 225 *property_exists = false; | |
| 226 base::Value* value = NULL; | |
| 227 if (!dict->Get(path, &value)) | |
| 228 return Status::Success(); | |
| 229 | |
| 230 if (!value->GetAsBoolean(result)) | |
| 231 return Status::ErrorJwkPropertyWrongType(path, "boolean"); | |
| 232 | |
| 233 *property_exists = true; | |
| 234 return Status::Success(); | |
| 235 } | |
| 236 | |
| 237 } // namespace | |
| 238 | |
| 239 Status ImportKeyJwk(const CryptoData& key_data, | |
| 240 const blink::WebCryptoAlgorithm& algorithm_or_null, | |
| 241 bool extractable, | |
| 242 blink::WebCryptoKeyUsageMask usage_mask, | |
| 243 blink::WebCryptoKey* key) { | |
| 244 | |
| 245 // The goal of this method is to extract key material and meta data from the | |
| 246 // incoming JWK, combine them with the input parameters, and ultimately import | |
| 247 // a Web Crypto Key. | |
| 248 // | |
| 249 // JSON Web Key Format (JWK) | |
| 250 // http://tools.ietf.org/html/draft-ietf-jose-json-web-key-16 | |
| 251 // TODO(padolph): Not all possible values are handled by this code right now | |
| 252 // | |
| 253 // A JWK is a simple JSON dictionary with the following entries | |
| 254 // - "kty" (Key Type) Parameter, REQUIRED | |
| 255 // - <kty-specific parameters, see below>, REQUIRED | |
| 256 // - "use" (Key Use) Parameter, OPTIONAL | |
| 257 // - "alg" (Algorithm) Parameter, OPTIONAL | |
| 258 // - "extractable" (Key Exportability), OPTIONAL [NOTE: not yet part of JOSE, | |
| 259 // see https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796] | |
| 260 // (all other entries are ignored) | |
| 261 // | |
| 262 // OPTIONAL here means that this code does not require the entry to be present | |
| 263 // in the incoming JWK, because the method input parameters contain similar | |
| 264 // information. If the optional JWK entry is present, it will be validated | |
| 265 // against the corresponding input parameter for consistency and combined with | |
| 266 // it according to rules defined below. A special case is that the method | |
| 267 // input parameter 'algorithm' is also optional. If it is null, the JWK 'alg' | |
| 268 // value (if present) is used as a fallback. | |
| 269 // | |
| 270 // Input 'key_data' contains the JWK. To build a Web Crypto Key, the JWK | |
| 271 // values are parsed out and combined with the method input parameters to | |
| 272 // build a Web Crypto Key: | |
| 273 // Web Crypto Key type <-- (deduced) | |
| 274 // Web Crypto Key extractable <-- JWK extractable + input extractable | |
| 275 // Web Crypto Key algorithm <-- JWK alg + input algorithm | |
| 276 // Web Crypto Key keyUsage <-- JWK use + input usage_mask | |
| 277 // Web Crypto Key keying material <-- kty-specific parameters | |
| 278 // | |
| 279 // Values for each JWK entry are case-sensitive and defined in | |
| 280 // http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16. | |
| 281 // Note that not all values specified by JOSE are handled by this code. Only | |
| 282 // handled values are listed. | |
| 283 // - kty (Key Type) | |
| 284 // +-------+--------------------------------------------------------------+ | |
| 285 // | "RSA" | RSA [RFC3447] | | |
| 286 // | "oct" | Octet sequence (used to represent symmetric keys) | | |
| 287 // +-------+--------------------------------------------------------------+ | |
| 288 // - use (Key Use) | |
| 289 // +-------+--------------------------------------------------------------+ | |
| 290 // | "enc" | encrypt and decrypt operations | | |
| 291 // | "sig" | sign and verify (MAC) operations | | |
| 292 // | "wrap"| key wrap and unwrap [not yet part of JOSE] | | |
| 293 // +-------+--------------------------------------------------------------+ | |
| 294 // - extractable (Key Exportability) | |
| 295 // +-------+--------------------------------------------------------------+ | |
| 296 // | true | Key may be exported from the trusted environment | | |
| 297 // | false | Key cannot exit the trusted environment | | |
| 298 // +-------+--------------------------------------------------------------+ | |
| 299 // - alg (Algorithm) | |
| 300 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-16 | |
| 301 // +--------------+-------------------------------------------------------+ | |
| 302 // | Digital Signature or MAC Algorithm | | |
| 303 // +--------------+-------------------------------------------------------+ | |
| 304 // | "HS256" | HMAC using SHA-256 hash algorithm | | |
| 305 // | "HS384" | HMAC using SHA-384 hash algorithm | | |
| 306 // | "HS512" | HMAC using SHA-512 hash algorithm | | |
| 307 // | "RS256" | RSASSA using SHA-256 hash algorithm | | |
| 308 // | "RS384" | RSASSA using SHA-384 hash algorithm | | |
| 309 // | "RS512" | RSASSA using SHA-512 hash algorithm | | |
| 310 // +--------------+-------------------------------------------------------| | |
| 311 // | Key Management Algorithm | | |
| 312 // +--------------+-------------------------------------------------------+ | |
| 313 // | "RSA1_5" | RSAES-PKCS1-V1_5 [RFC3447] | | |
| 314 // | "RSA-OAEP" | RSAES using Optimal Asymmetric Encryption Padding | | |
| 315 // | | (OAEP) [RFC3447], with the default parameters | | |
| 316 // | | specified by RFC3447 in Section A.2.1 | | |
| 317 // | "A128KW" | Advanced Encryption Standard (AES) Key Wrap Algorithm | | |
| 318 // | | [RFC3394] using 128 bit keys | | |
| 319 // | "A256KW" | AES Key Wrap Algorithm using 256 bit keys | | |
| 320 // | "A128GCM" | AES in Galois/Counter Mode (GCM) [NIST.800-38D] using | | |
| 321 // | | 128 bit keys | | |
| 322 // | "A256GCM" | AES GCM using 256 bit keys | | |
| 323 // | "A128CBC" | AES in Cipher Block Chaining Mode (CBC) with PKCS #5 | | |
| 324 // | | padding [NIST.800-38A] [not yet part of JOSE, see | | |
| 325 // | | https://www.w3.org/Bugs/Public/show_bug.cgi?id=23796 | | |
| 326 // | "A192CBC" | AES CBC using 192 bit keys [not yet part of JOSE] | | |
| 327 // | "A256CBC" | AES CBC using 256 bit keys [not yet part of JOSE] | | |
| 328 // +--------------+-------------------------------------------------------+ | |
| 329 // | |
| 330 // kty-specific parameters | |
| 331 // The value of kty determines the type and content of the keying material | |
| 332 // carried in the JWK to be imported. Currently only two possibilities are | |
| 333 // supported: a raw key or an RSA public key. RSA private keys are not | |
| 334 // supported because typical applications seldom need to import a private key, | |
| 335 // and the large number of JWK parameters required to describe one. | |
| 336 // - kty == "oct" (symmetric or other raw key) | |
| 337 // +-------+--------------------------------------------------------------+ | |
| 338 // | "k" | Contains the value of the symmetric (or other single-valued) | | |
| 339 // | | key. It is represented as the base64url encoding of the | | |
| 340 // | | octet sequence containing the key value. | | |
| 341 // +-------+--------------------------------------------------------------+ | |
| 342 // - kty == "RSA" (RSA public key) | |
| 343 // +-------+--------------------------------------------------------------+ | |
| 344 // | "n" | Contains the modulus value for the RSA public key. It is | | |
| 345 // | | represented as the base64url encoding of the value's | | |
| 346 // | | unsigned big endian representation as an octet sequence. | | |
| 347 // +-------+--------------------------------------------------------------+ | |
| 348 // | "e" | Contains the exponent value for the RSA public key. It is | | |
| 349 // | | represented as the base64url encoding of the value's | | |
| 350 // | | unsigned big endian representation as an octet sequence. | | |
| 351 // +-------+--------------------------------------------------------------+ | |
| 352 // | |
| 353 // Consistency and conflict resolution | |
| 354 // The 'algorithm_or_null', 'extractable', and 'usage_mask' input parameters | |
| 355 // may be different than the corresponding values inside the JWK. The Web | |
| 356 // Crypto spec says that if a JWK value is present but is inconsistent with | |
| 357 // the input value, it is an error and the operation must fail. If no | |
| 358 // inconsistency is found, the input and JWK values are combined as follows: | |
| 359 // | |
| 360 // algorithm | |
| 361 // If an algorithm is provided by both the input parameter and the JWK, | |
| 362 // consistency between the two is based only on algorithm ID's (including an | |
| 363 // inner hash algorithm if present). In this case if the consistency | |
| 364 // check is passed, the input algorithm is used. If only one of either the | |
| 365 // input algorithm and JWK alg is provided, it is used as the final | |
| 366 // algorithm. | |
| 367 // | |
| 368 // extractable | |
| 369 // If the JWK extractable is true but the input parameter is false, make the | |
| 370 // Web Crypto Key non-extractable. Conversely, if the JWK extractable is | |
| 371 // false but the input parameter is true, it is an inconsistency. If both | |
| 372 // are true or both are false, use that value. | |
| 373 // | |
| 374 // usage_mask | |
| 375 // The input usage_mask must be a strict subset of the interpreted JWK use | |
| 376 // value, else it is judged inconsistent. In all cases the input usage_mask | |
| 377 // is used as the final usage_mask. | |
| 378 // | |
| 379 | |
| 380 if (!key_data.byte_length()) | |
| 381 return Status::ErrorImportEmptyKeyData(); | |
| 382 DCHECK(key); | |
| 383 | |
| 384 // Parse the incoming JWK JSON. | |
| 385 base::StringPiece json_string(reinterpret_cast<const char*>(key_data.bytes()), | |
| 386 key_data.byte_length()); | |
| 387 scoped_ptr<base::Value> value(base::JSONReader::Read(json_string)); | |
| 388 // Note, bare pointer dict_value is ok since it points into scoped value. | |
| 389 base::DictionaryValue* dict_value = NULL; | |
| 390 if (!value.get() || !value->GetAsDictionary(&dict_value) || !dict_value) | |
| 391 return Status::ErrorJwkNotDictionary(); | |
| 392 | |
| 393 // JWK "kty". Exit early if this required JWK parameter is missing. | |
| 394 std::string jwk_kty_value; | |
| 395 Status status = GetJwkString(dict_value, "kty", &jwk_kty_value); | |
| 396 if (status.IsError()) | |
| 397 return status; | |
| 398 | |
| 399 // JWK "extractable" (optional) --> extractable parameter | |
| 400 { | |
| 401 bool jwk_extractable_value = false; | |
| 402 bool has_jwk_extractable; | |
| 403 status = GetOptionalJwkBool(dict_value, | |
| 404 "extractable", | |
| 405 &jwk_extractable_value, | |
| 406 &has_jwk_extractable); | |
| 407 if (status.IsError()) | |
| 408 return status; | |
| 409 if (has_jwk_extractable && !jwk_extractable_value && extractable) | |
| 410 return Status::ErrorJwkExtractableInconsistent(); | |
| 411 } | |
| 412 | |
| 413 // JWK "alg" (optional) --> algorithm parameter | |
| 414 // Note: input algorithm is also optional, so we have six cases to handle. | |
| 415 // 1. JWK alg present but unrecognized: error | |
| 416 // 2. JWK alg valid AND input algorithm isNull: use JWK value | |
| 417 // 3. JWK alg valid AND input algorithm specified, but JWK value | |
| 418 // inconsistent with input: error | |
| 419 // 4. JWK alg valid AND input algorithm specified, both consistent: use | |
| 420 // input value (because it has potentially more details) | |
| 421 // 5. JWK alg missing AND input algorithm isNull: error | |
| 422 // 6. JWK alg missing AND input algorithm specified: use input value | |
| 423 blink::WebCryptoAlgorithm algorithm = blink::WebCryptoAlgorithm::createNull(); | |
| 424 const JwkAlgorithmInfo* algorithm_info = NULL; | |
| 425 std::string jwk_alg_value; | |
| 426 bool has_jwk_alg; | |
| 427 status = | |
| 428 GetOptionalJwkString(dict_value, "alg", &jwk_alg_value, &has_jwk_alg); | |
| 429 if (status.IsError()) | |
| 430 return status; | |
| 431 | |
| 432 if (has_jwk_alg) { | |
| 433 // JWK alg present | |
| 434 | |
| 435 // TODO(padolph): Validate alg vs kty. For example kty="RSA" implies alg can | |
| 436 // only be from the RSA family. | |
| 437 | |
| 438 blink::WebCryptoAlgorithm jwk_algorithm = | |
| 439 blink::WebCryptoAlgorithm::createNull(); | |
| 440 algorithm_info = jwk_alg_registry.Get().GetAlgorithmInfo(jwk_alg_value); | |
| 441 if (!algorithm_info || | |
| 442 !algorithm_info->CreateImportAlgorithm(&jwk_algorithm)) | |
| 443 return Status::ErrorJwkUnrecognizedAlgorithm(); // case 1 | |
| 444 | |
| 445 // JWK alg valid | |
| 446 if (algorithm_or_null.isNull()) { | |
| 447 // input algorithm not specified | |
| 448 algorithm = jwk_algorithm; // case 2 | |
| 449 } else { | |
| 450 // input algorithm specified | |
| 451 if (!ImportAlgorithmsConsistent(jwk_algorithm, algorithm_or_null)) | |
| 452 return Status::ErrorJwkAlgorithmInconsistent(); // case 3 | |
| 453 algorithm = algorithm_or_null; // case 4 | |
| 454 } | |
| 455 } else { | |
| 456 // JWK alg missing | |
| 457 if (algorithm_or_null.isNull()) | |
| 458 return Status::ErrorJwkAlgorithmMissing(); // case 5 | |
| 459 algorithm = algorithm_or_null; // case 6 | |
| 460 } | |
| 461 DCHECK(!algorithm.isNull()); | |
| 462 | |
| 463 // JWK "use" (optional) --> usage_mask parameter | |
| 464 std::string jwk_use_value; | |
| 465 bool has_jwk_use; | |
| 466 status = | |
| 467 GetOptionalJwkString(dict_value, "use", &jwk_use_value, &has_jwk_use); | |
| 468 if (status.IsError()) | |
| 469 return status; | |
| 470 if (has_jwk_use) { | |
| 471 blink::WebCryptoKeyUsageMask jwk_usage_mask = 0; | |
| 472 if (jwk_use_value == "enc") { | |
| 473 jwk_usage_mask = | |
| 474 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageDecrypt; | |
| 475 } else if (jwk_use_value == "sig") { | |
| 476 jwk_usage_mask = | |
| 477 blink::WebCryptoKeyUsageSign | blink::WebCryptoKeyUsageVerify; | |
| 478 } else if (jwk_use_value == "wrap") { | |
| 479 jwk_usage_mask = | |
| 480 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey; | |
| 481 } else { | |
| 482 return Status::ErrorJwkUnrecognizedUsage(); | |
| 483 } | |
| 484 if ((jwk_usage_mask & usage_mask) != usage_mask) { | |
| 485 // A usage_mask must be a subset of jwk_usage_mask. | |
| 486 return Status::ErrorJwkUsageInconsistent(); | |
| 487 } | |
| 488 } | |
| 489 | |
| 490 // JWK keying material --> ImportKeyInternal() | |
| 491 if (jwk_kty_value == "oct") { | |
| 492 | |
| 493 std::string jwk_k_value; | |
| 494 status = GetJwkBytes(dict_value, "k", &jwk_k_value); | |
| 495 if (status.IsError()) | |
| 496 return status; | |
| 497 | |
| 498 // Some JWK alg ID's embed information about the key length in the alg ID | |
| 499 // string. For example "A128CBC" implies the JWK carries 128 bits | |
| 500 // of key material. For such keys validate that enough bytes were provided. | |
| 501 // If this validation is not done, then it would be possible to select a | |
| 502 // different algorithm by passing a different lengthed key, since that is | |
| 503 // how WebCrypto interprets things. | |
| 504 if (algorithm_info && | |
| 505 algorithm_info->IsInvalidKeyByteLength(jwk_k_value.size())) { | |
| 506 return Status::ErrorJwkIncorrectKeyLength(); | |
| 507 } | |
| 508 | |
| 509 return ImportKey(blink::WebCryptoKeyFormatRaw, | |
| 510 CryptoData(jwk_k_value), | |
| 511 algorithm, | |
| 512 extractable, | |
| 513 usage_mask, | |
| 514 key); | |
| 515 } else if (jwk_kty_value == "RSA") { | |
| 516 | |
| 517 // An RSA public key must have an "n" (modulus) and an "e" (exponent) entry | |
| 518 // in the JWK, while an RSA private key must have those, plus at least a "d" | |
| 519 // (private exponent) entry. | |
| 520 // See http://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-18, | |
| 521 // section 6.3. | |
| 522 | |
| 523 // RSA private key import is not currently supported, so fail here if a "d" | |
| 524 // entry is found. | |
| 525 // TODO(padolph): Support RSA private key import. | |
| 526 if (dict_value->HasKey("d")) | |
| 527 return Status::ErrorJwkRsaPrivateKeyUnsupported(); | |
| 528 | |
| 529 std::string jwk_n_value; | |
| 530 status = GetJwkBytes(dict_value, "n", &jwk_n_value); | |
| 531 if (status.IsError()) | |
| 532 return status; | |
| 533 std::string jwk_e_value; | |
| 534 status = GetJwkBytes(dict_value, "e", &jwk_e_value); | |
| 535 if (status.IsError()) | |
| 536 return status; | |
| 537 | |
| 538 return platform::ImportRsaPublicKey(algorithm, | |
| 539 extractable, | |
| 540 usage_mask, | |
| 541 CryptoData(jwk_n_value), | |
| 542 CryptoData(jwk_e_value), | |
| 543 key); | |
| 544 | |
| 545 } else { | |
| 546 return Status::ErrorJwkUnrecognizedKty(); | |
| 547 } | |
| 548 | |
| 549 return Status::Success(); | |
| 550 } | |
| 551 | |
| 552 } // namespace webcrypto | |
| 553 | |
| 554 } // namespace content | |
| OLD | NEW |